Reputation: 561
Inspired by How to get struct field names in Rust?, I want to get an implemented method of the struct based on a str
, something like:
macro_rules! comp {
(struct $name:ident {
$($field_name:ident : $field_type:ty,)*
}
impl $name2:ident {
$(pub fn $func_name:ident($($args:tt)*) $bk:block)*
}
) => {
//basic component
struct $name {
$($field_name: $field_type),*
}
impl $name {
$(pub fn $func_name($($args)*) $bk)*
// the generated function
pub fn get_method(index: &str) -> &'static dyn Fn() {
$(if stringify!($func_name) == index {
return $func_name; // (***)
})*
//
// Some code here to return the right function
//
}
}
};
}
fn main() {
comp! {
struct S {
field: String,
}
impl S {
pub fn method1() {
println!("method1 called");
}
pub fn method2() {
println!("method2 called");
}
}
}
// the functionality should achieved
// S::get_method("method1") == S::method1
// S::get_method("method2") == S::method2
}
Originally I wanted to get the function pointer with return $func_name
, but it seems impossible; the line of code marked with (***)
gets the error:
error[E0423]: expected function, found macro `stringify`
--> src/main.rs:19:22
|
19 | $(if stringify($func_name) == index {
| ^^^^^^^^^ not a function
...
31 | / comp! {
32 | | struct S {
33 | | field: String,
34 | | }
... |
42 | | }
43 | | }
| |_____- in this macro invocation
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
help: use `!` to invoke the macro
|
19 | $(if stringify!($func_name) == index {
| ^
error[E0425]: cannot find value `method1` in this scope
--> src/main.rs:36:20
|
36 | pub fn method1() {
| ^^^^^^^ not found in this scope
error[E0425]: cannot find value `method2` in this scope
--> src/main.rs:39:20
|
39 | pub fn method2() {
| ^^^^^^^ not found in this scope
error[E0308]: mismatched types
--> src/main.rs:19:19
|
19 | $(if stringify($func_name) == index {
| ___________________^
20 | | return $func_name; // (***)
21 | | })*
| |_________________^ expected reference, found `()`
...
31 | / comp! {
32 | | struct S {
33 | | field: String,
34 | | }
... |
42 | | }
43 | | }
| |_____- in this macro invocation
|
= note: expected reference `&'static (dyn std::ops::Fn() + 'static)`
found unit type `()`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
How to get it done?
Upvotes: 0
Views: 689
Reputation: 561
first of all, I'd like to thank @Shepmaster, your suggestion applies to most cases if your problem is not complicated. However it's required to tackle a struct
, a block of code provided by user, in this case, the only way I figure out is use macro rule to achieve that
after some time, I finally get it done. in our case, for short, we can do
fn get_method(ind: &str) -> Option<&dyn Fn()> {
// the default type of $name::$func is fn(), function pointer
// it is recommended to convert into &dyn Fn() if you impl many methods
let methods = vec![ $(&$name::$func as &dyn Fn()),* ];
let inds = vec![$(stringify!($func)),*];
let mut i = 0;
for item in inds.iter() {
if item == &ind {
break;
} else {
i +=1;
}
}
if i <= inds.len() - 1 {
Some(methods[i])
} else {
None
}
}
Upvotes: 1