C and C++ has implicit integer promotion, rust does not.
in rust, for widening integer conversion, Into is implemented because they are infallible. for narrowing conversions, TryInto should be used and overflow/underflow should be handled correctly.
primitive cast exists but it silently truncates for lossy conversions, so use with caution.
third party crates like num-traits provide generic way to work with integers and floating points, and conversions between them.
if you want to keep your implementation of u32 but to hide the .into() on callsites, use a generic wrapper function, which can call the concrete implementation internally, like this:
pub fn convert_24_to_12(hour_24: impl Into<u32>) -> Result<(u32, bool), Box<dyn Error>> {
convert_24_to_12_u32(hour_24.into())
}
// your original implementation but renamed
// `pub` or not, it's your choice
pub convert_24_to_12_u32(hour_24: u32) -> Result<(u32, bool), Box<dyn Error>> {
//...
}
if you want to write an "overloaded" function for any integer type, it is a bit verbose. you need a trait to abstract away the operations in the function, this includes:
- a method for the
hour_24 > 23 and hour_24 > 11 comparisons, e.g. std::cmp::PartialOrd::gt()
- a method for the
hour_24 % 12 remainder, e.g. std::ops::Rem::rem()
- a method for the remainder type (if different from the input) to check for value
0
- a method to construct a literal value
12
then you implement the trait for all the integer types you want to support.
this is very tedious so it's better to use a third party crate, but you don't use cargo, so you'll have to do it yourself.
alternatively, you can simply overload the entire convert_24_to_12() function, slightly better than abstract away the individual operations.
also, you can create the impl blocks using a macro to reduce duplicated code.