Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bounds with multiple types

Tags:

generics

rust

Currently I have the following rust function:

fn out_cubic(t: f32, begin: f32, change: f32, duration: f32) -> f32 {
    return change * (f32::powf((t / duration) - 1.0, 3.0) + 1.0) + begin;
}

I'm trying to make both begin and change parameters generic types. As far I understand, I could use Rust's bounds to say to the compiler that change and begin should implement the add and multiply operation:

use std::ops::{Add, Mul};

fn out_cubic<T: Add + Mul>(t: f32, begin: T, change: T, duration: f32) -> T {
    return change * (f32::powf((t / duration) - 1.0, 3.0) + 1.0) + begin;
}

But the above code show the following errors:

error[E0308]: mismatched types
  --> src/easing.rs:44:21
   |
43 | fn out_cubic<T: Add + Mul>(t: f32, begin: T, change: T, duration: f32) -> T {
   |              - this type parameter
44 |     return change * (f32::powf((t / duration) - 1.0, 3.0) + 1.0) + begin;
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found `f32`
   |
   = note: expected type parameter `T`
                        found type `f32`

error[E0369]: cannot add `T` to `<T as Mul>::Output`
  --> src/easing.rs:44:66
   |
44 |     return change * (f32::powf((t / duration) - 1.0, 3.0) + 1.0) + begin;
   |            ----------------------------------------------------- ^ ----- T
   |            |
   |            <T as Mul>::Output

Which makes sense, the compiler does not have any way to know that the type T should be able to add and multiply with a f32 type.

My question is, is it possible to create a function that implements both add and multiply operations with T and f32 types? Something like this:

fn out_cubic<T: Add<T> + Add<f32> + Mul<T> + Mul<f32>>(t: f32, begin: T, change: T, duration: f32) -> T {
    return change * (f32::powf((t / duration) - 1.0, 3.0) + 1.0) + begin;
}
like image 888
Rodrigo Ce Moretto Avatar asked Oct 18 '25 18:10

Rodrigo Ce Moretto


1 Answers

Since you're adding f32 + T, you actually need to assert that f32 is Add<T>:

fn out_cubic<T>(t: f32, begin: T, change: T, duration: f32) -> T
where
    T: Add<T, Output = T> + Mul<f32, Output = T>, // assert that Output is T
    f32: Add<T> + Add, // the `+ Add` is necessary for f32 to f32 addition for whatever reason
{
    return change * (f32::powf((t / duration) - 1.0, 3.0) + 1.0) + begin;
}

You could of course, make it even more generic by only asserting that it has to operate on their outputs, but it starts ot get messy:

fn out_cubic<T>(t: f32, begin: T, change: T, duration: f32) -> <<T as Mul<f32>>::Output as Add<T>>::Output
where
    T: Mul<f32>,
    <T as Mul<f32>>::Output: Add<T>,
    f32: Add<T> + Add,
{
    return change * (f32::powf((t / duration) - 1.0, 3.0) + 1.0) + begin;
}
like image 105
Aplet123 Avatar answered Oct 21 '25 07:10

Aplet123



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!