As far as I can tell, the standard library doesn't have a method to convert between floats and ints with an error if the value can't be expressed exactly (like the behavior for converting between different-size ints), so I'd like to use TryFrom to fill that niche.
Specifically, for any pair of integer and floating-point type, there will be impl TryFrom<int> for float (minus the ones which already exist from the blanket impl from infallible From, like f64: From<i32>), and impl TryFrom<float> for int which semantically work by imagining the value as an arbitrary real number and only succeeding if the destination type has an exact match in the destination type (and if casting 0 to a float, pick positive zero).
Specifically, they'd have these useful properties:
- If a
.try_into()?call succeeds, the returned value will match the value produced by anascast. - Any chain of
.try_into()?calls which ends at the same type, if they both succeed, produce values which compare equal.- The empty chain is counted, so for
value: T,T::try_from(U::try_from(value)?)? == valuewill either return an error ifvalueisn't exactly expressible asUor evaluate totrue. -0.0 == 0.0is a true comparison despite the distinct values, sou32::try_from(-0.0)? == 0is allowed to succeed.- Float values like
NaNand the infinities will always fail to convert to any integer.
- The empty chain is counted, so for
- For types
TandUwhereT: From<U>(e.g.u64andu32), ifT::try_from(value)?succeeds, thenU::try_from(value)?will also succeed for that same input. - No rounding is automatically done, so e.g.
u32::try_from(12.0001)will always fail, but users can easily chain with a call to.round(),.trunc(), or whatever other rounding operations they want.
If you want saturating and any rounding scheme, the existing methods and as casting works well. This TryFrom implementation will provide an option for no saturating nor rounding, and the existing rounding methods complement it by allowing rounding also. The only combination I can think of that isn't enabled by this conversion is if you want to saturate but not round (e.g. allow 300. to 255u8, but disallow 12.0001 to 12u8), which I have never needed.
What do y'all think? Would anyone else find this useful?