I am quite new to Rust, so sorry by advance if I'm misunderstanding something.
I have some code in Rust where I have generic functions such as this one :
pub(crate) fn square_root<T: Float>(value_array: &[T]) -> T {
value_array[0].sqrt()
}
I also have this macro :
macro_rules! print_queries {
($INTERVAL:ty, $INTERVAL_INIT:expr, $TYPE_NAME:expr, $METHOD:expr, $PRINT_METHOD:expr, $VARIABLE_COUNT:expr) => {
{
let mut used_variables: Vec<$INTERVAL> = Vec::with_capacity($VARIABLE_COUNT);
for i in 0..$VARIABLE_COUNT {
used_variables.push($INTERVAL_INIT(COMP_DOUBLES[i]));
}
match std::panic::catch_unwind(|| $METHOD(&used_variables)) {
Ok(result) => {
println!("{}: ", $TYPE_NAME);
print_query(lower(result), upper(result), $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
}
Err(_) => {
println!("{}: ", $TYPE_NAME);
print_query(1.0, -1.0, $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
}
}
}
}
}
The macro is used with the first function as the parameter $METHOD, e.g.
print_queries!(InariInterval, inari_interval, "INARI", square_root, print_square_root, 1);
As you can see, I'm using this method with the Inari crate, which is a crate for interval arithmetic : https://docs.rs/inari/latest/inari/index.html InariInterval is a copy of the type inari::Interval, and inari_interval is a method creating an Interval from one float.
However, this does not work, and here is the error I get :
error[E0277]: the trait bound `inari::Interval: num_traits::Float` is not satisfied
--> src/query.rs:65:5
|
65 | run_query!(square_root, print_square_root, 1, square_root_range, check_input_square_root);
| ^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | required by a bound introduced by this call
| the trait `num_traits::Float` is not implemented for `inari::Interval`
|
= help: the following other types implement trait `num_traits::Float`:
f32
f64
note: required by a bound in `methods::square_root`
--> src/methods.rs:803:30
|
803 | pub(crate) fn square_root<T: Float>(value_array: &[T]) -> T {
| ^^^^^ required by this bound in `square_root`
I'd like as much as possible to keep my functions generic. I don't think I can implement square_root without using Float, and that would only partly solve the problem since I have other functions with the same issue.
I tried to implement the Float trait for Inari but it doesn't seem to be possible. I got this error : Only traits defined in the current crate can be implemented for arbitrary types [E0117]
Thus, I'm a little bit stuck and I don't know if I can find a solution while keeping my functions generic.
Thanks for advance for your help and suggestions.
You have a couple options:
Float
.Interval
.The first would be ideal, but it may not be possible if Float
is too specific for intervals. Otherwise, the second is probably the best, although you would then be responsible for implementing this trait for existing types, such as f32
, f64
, and other crates' floats. The third is similar to the second, but would make you responsible for implementing existing traits for your type.
Also, don't use catch_unwind
unless you absolutely need to. Panics are meant to be unrecoverable, so if you are expecting an error, use an Option
or Result
so that truly unrecoverable errors are not ignored.
pub(crate) fn square_root<T: Float>(value_array: &[T]) -> Option<T> {
// `first` is the same as `get(0)`
value_array.first().map(|value| value.sqrt())
}
// inside the macro
match $METHOD(&used_variables) {
Some(result) => {
println!("{}: ", $TYPE_NAME);
print_query(lower(result), upper(result), $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
}
None => {
println!("{}: ", $TYPE_NAME);
print_query(1.0, -1.0, $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
}
}