I have the following rust code
use std::any::Any;
use std::rc::Rc;
fn main() {
let mut variables = Vec::<Rc<dyn Any>>::new();
variables.push(Rc::new(1_i32));
variables.push(Rc::new(false));
variables.push(Rc::new(4.53_f64));
let integer: i32 = *variables[0].clone().downcast::<i32>().unwrap();
let boolean: bool = *variables[1].clone().downcast::<bool>().unwrap();
let floating: f64 = *variables[2].clone().downcast::<f64>().unwrap();
let my_goal: (i32, bool, f64) = (integer, boolean, floating)
println!("{:?}", my_goal);
which I want to automatize using a macro. (I know that this is suboptimal, but this is just a MWE to ask a question about macros)
In particular I want to create a tuple downcasting Any
to given types
My first attempt is:
macro_rules! my_macro {
($vector:ident; $($type:ty),*) => {
// ($($type),*)
//println!("{:?}", $vector);
//$(println!("{:?}", stringify!($type));)*
let idx = 0;
($(
*$vector[0].clone().downcast::<$type>().unwrap()
),*)
};
}
which is wrong because of the 0
hardcoded. I tried several way to declare a variable and increment it along the macro but they failed.
How can I do?
I am pretty sure you failed to declare the variable because you only used a single set of curly braces when actually two would be required inside the macro after the fat arrow.
I suppose this is the macro you are after:
macro_rules! tuple_downcast {
($vector:ident; ($($type:ty),*)) => {{
let mut iter = $vector.into_iter();
(
$(
*iter.next()
.expect("The vector contains less elements than the type tuple.")
.clone()
.downcast::<$type>()
.expect("The value can not be downcasted to the specified type."),
)*
)
}};
}
you can use it like this:
use std::any::Any;
use std::rc::Rc;
macro_rules! tuple_downcast {
($vector:ident; ($($type:ty),*)) => {{
let mut iter = $vector.into_iter();
(
$(
*iter.next()
.expect("The vector contains less elements than the type tuple.")
.clone()
.downcast::<$type>()
.expect("The value can not be downcasted to the specified type."),
)*
)
}};
}
fn main() {
let mut variables = Vec::<Rc<dyn Any>>::new();
variables.push(Rc::new(1_i32));
variables.push(Rc::new(false));
variables.push(Rc::new(4.53_f64));
let integer: i32 = *variables[0].clone().downcast::<i32>().unwrap();
let boolean: bool = *variables[1].clone().downcast::<bool>().unwrap();
let floating: f64 = *variables[2].clone().downcast::<f64>().unwrap();
let my_goal: (i32, bool, f64) = (integer, boolean, floating);
println!("{:?}", my_goal);
let mut variables = Vec::<Rc<dyn Any>>::new();
variables.push(Rc::new(1_i32));
variables.push(Rc::new(false));
variables.push(Rc::new(4.53_f64));
let my_goal = tuple_downcast!(variables; (i32, bool, f64));
println!("{:?}", my_goal);
}
Which results in the following output:
(1, false, 4.53)
(1, false, 4.53)
Alternatively if you absolutely want to use an index for accessing the elements:
macro_rules! tuple_downcast {
($vector:ident; ($($type:ty),*)) => {{
let mut idx = 0;
(
$({
let value = *$vector[idx].clone()
.downcast::<$type>()
.unwrap();
idx += 1;
value
}),*
)
}};
}