So I have an enum with many dozens of variants. Each variant has a single associated value, It can be a f32, an u8, i8, 16, etc.
And I have a function that receives a value representing an enum variant, and also receives a string slice that should be castable as the same type that has to go into that variant. I then check whether the value can be casted to the expected type, and whether it is within some expected range. Then I return an Option contanining a specific enum variant containing that value, or None if it fails.
This already works well. I've also created several wrapper functions (one for each associated value type) to help avoiding repetition. Now I'm trying to create a more general wrapper but I'm stuck at this particular pain point:
The function needs receive a specific enum variant as an argument, and it has to be able to put the already checked value inside that received variant. And I don't want to use a match because of the huge number of variants there are.
Do you know if there any ways to do it? I'll share how far I've got.
These are my wrappers for when f32 values are involved:
/// Receive a string, try to parse it as f32
pub(crate) fn check_f32(value: &str) -> f32 {
let num: f32 = value.parse::<f32>()
.expect(&format!("ERROR: `{}` is not a valid f32 number", value));
num
}
/// Receive a string, try to parse it as f32 between a given range
pub(crate) fn check_f32_between(value: &str, min: f32, max: f32) -> Option<f32> {
let num = check_f32(value);
match num {
num if (min..=max).contains(&num) => Some(num),
_ => None
}
}
This is how I use them:
"pan" => {
let num = check_f32_between(value, 0., 100.);
num.and(Some(Opcode::pan(num.unwrap_or_default())))
// My intention is to replace that with something briefer like:
// f32::check(value, 0., 100., Opcode::pan)
}
And this is where I'm stuck:
// trying to make this work...
impl<T: utils::OpcodeType<T>> Opcode {
fn replace(self, value: T) -> Self {
Self(value)
}
}
pub trait OpcodeType<T> {
fn check(value: &str, min: T, max: T, opcode: Opcode) -> Option<Opcode>;
}
impl OpcodeType<f32> for f32 {
fn check(value: &str, min: f32, max: f32, opcode: Opcode) -> Option<Opcode> {
let num = utils::check_f32_between(value, min, max);
num.and(Some(opcode.replace(num.unwrap_or_default())))
}
}