baseplug
baseplug copied to clipboard
Donwfall85/feature/numbers
This branch implements the Num, Real and Discrete traits to represent numbers. The main objective is to replace the Float trait which is not very well designed. I only implemented the basic operations to keep the current behaviour but it is of course possible to play others (All credit goes to SamiP for implementing these traits).
The next step would be to allow the use of other primitive types than f32. To do this, you have to play with the Translatable <T, P: Plugin, Model> trait.
I tried the following implementation but quickly found myself stuck:
impl <P: Plugin, Model, T> Translatable <T, P, Model> for T
where T: Real + AsPrimitive <f32>.
This allows you to use f32 or f64. However, when we want to do the same thing for integers, we end up with a conflict:
impl <P: Plugin, Model, T> Translatable <T, P, Model> for T
where T: Discrete + AsPrimitive <f32>.
We have two blanket implementations and this is not allowed by Rust until we can do mutual trait exclusions.
One solution that works is to implement the Translatable <T, P: Plugin, Model> trait for each type with a macro:
macro_rules! impl_real {
( $($t:ty),* ) => {
$( impl<P: Plugin, Model> Translatable<$t, P, Model> for $t {
fn xlate_in(param: &Param<P, Model>, normalised: f32) -> $t {
...
}
fn xlate_out(&self, param: &Param<P, Model>) -> f32 {
...
}
}) *
}
}
impl_real! { f32, f64 }
macro_rules! impl_discrete {
( $($t:ty),* ) => {
$( impl<P: Plugin, Model> Translatable<$t, P, Model> for $t {
fn xlate_in(param: &Param<P, Model>, normalised: f32) -> $t {
.
}
fn xlate_out(&self, param: &Param<P, Model>) -> f32 {
.
}
}) *
}
}
impl_discrete! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize }
With this solution, it is possible to use any scalar type to build a parameter.
I need your vision on which solution would be most appropriate in the context of the project.