For weight_matchers I have a macro that takes any primitive number. It needs to clamp floats to 0.0 .. 1.0 and integers to MIN .. MAX. These are values the compiler knows in context. But I can’t seem to express that.
All I have is a value of the inferred type. Sadly I can’t x.MIN, x::MIN, or <type_of(x)>::MIN.
Edit: To make this harder, it’s a feature of this crate to be able to do everything in const . Additionally I would not want to impl any trait for all primitive types, because floats currently have unstable sizes, and integers might get arbitrary bit sizes.
As per the companion question given only a value, I can distinguish floats and integers.
whatever you are trying to do, I feel like you are emulating what you did in a different language, but not the rust way.
it's uncommon in rust to "inspect" the type of a variable and dispatch to different code based on the type, like what you did.
instead of "inspection" or "reflection", polymorphism is usually achieved through a trait, which can either be statically dispatched, or dynamically dispatched, depending on the use case.
for example, instead of this:
// not
if is_i32(x) {
let y: i32 = clamp_int(x);
// more signed integer calculation
} else if is_u32(x) {
let y: u32 = clamp_int(x);
// more unsigned calcuation
} else if is_f64(x) {
let y: f64 = clamp_floatingpoint(x);
// more floating point calculation
} else if ... {
}
it's better to use a proper abstraction like this:
trait SomeCalculation {
fn calc(self) -> Self;
}
impl SomeCalculation for i32 {
fn calc(self) -> i32 {
let y = self.clamp(MIN, MAX);
// more signed integer calculation
todo!()
}
}
impl SomeCalculation for u32 {
fn calc(self) -> u32 {
todo!()
}
}
impl SomeCalculation for f64 {
fn calc(self) -> f64 {
todo!()
}
}
//...
// can use method call syntax like this:
let x = 42i32.calc();
let y = 0.5f64.calc();
// or associated function call like this:
let x = SomeCalculation(42i32);
let y = SomeCalculation(0.5f64);
Obviously. At the same time, so sad that an info that the compiler has is so unreachable!
My mistake that I had failed to repeat that I need this in const. And at a time where new numeric types are being introduced unstably it is impossible to cover them all.
What I really needed was just the natural range of each primitive integral type, aka t::MIN..=t::MAX without having the type name. Since Rust hides that info from macro/inferred type/generic, I was only trying to find a workaround.
The day after publishing such a hack as weight_matchers 0.4.0, I stumbled across the solution: the very two constants I need are obtainable by other means. Casting too big floats to integers saturates to MIN and MAX. But I don’t know which type to cast to, and .into() is not available here. But what if inferred casting works? To my joy, it does: we can get the values like f32::NEG_INFINITY as _. This allows deriving the total range for all primitive integral types.