I'm finding myself writing a LOT of unsafe { NonZero::new_unchecked(1) } and similar lines. It seems like language updates facilitate a more compact syntax such as NonZero::new_const::<1>(). This seems like it could be implemented along the lines of
You can eliminate the repetitiveness by defining a function that does it.
The best way to handle this in the language would be to allow literals like 1 to have this type too. Even better if any custom types could have integer literals.
Pattern types is something that may or may not exist, and if it ends up stabilized it may be 10 years from now.. this API is something that can be added right now
And also: NonZero may well become deprecated once pattern types is stabilized!
There are interesting rules around pattern-restricted types that can result in u8 is 1.. and NonZeroU8 behaving differently if we want the intuitive subtyping rules to work out. So I don't think NonZero<_> will end up fully deprecated, just used in APIs a lot less.
What would be really awesome is if the compiler had support for using the literal syntax so there's no need to define any sort of special constructor method whose need might be obviated by future compiler features like const unwrap():
const FOO: NonZero<u8> = 42;
Something like this would cause a compile error:
const FOO: NonZero<u8> = 0;
Not sure what blocked this sort of thing before with e.g. NonZeroU8 but with NonZero<T> it seems there's now at least only one type that needs some magic compiler assistance.
The primary thing is that type inference/fallback around the {integer} placeholder inference type is extremely ad-hoc and hacky, and adding new types into the set is likely to cause inference breakage, that breakage has reasonable potential to be widespread, and there's no good way to keep it from immediately being stable (as trait impls generally always are).
(E.g. you can sometimes call methods directly on {integer}, if they come from a trait. If the method is shadowed by an inherent method, calling it twice can call either method depending on context, without any compiler warnings. It's a textbook example of spooky action at distance.)
There's interest in migrating it to a trait, but removing the pile of special cases quickly runs headfirst into the thorny problem that is defaults that affect type inference. The discussion on the old tracking issue covers some of the hairy questions that led to closing that issue.
AIUI this is one of the things that the new inference engine / trait solver should unblock, and everyone with the ability to do so is focused on moving that work forward in leu of extending the current system.
more important than compactness is saftey. NonZeroU8::new_unchecked(0) is immediate undefined behavior, even though most users wouldn't mind the additional cost of a check+panic.
const functions have become a lot less limited than they were a few years ago.
The limitations of const was hardly an issue then (and it hasn't improved here, as const traits are needed). It was a matter of being able to implement it on the language side of things.