I want to write a macro, which generates a struct with a default fn new(...)
function. If the desired struct has a String
field, I want new
to be a template function like fn new<S: Into<String>>(..., field: S,...)
.
The problem occurred when creating these optional template parameter.
For example, for
impl_type!(
User {
id: i64,
name: String,
}
}
I want to get:
pub struct User { /* fields */ }
impl User {
pub fn new<S: Into<String>>(id: i64, name: S) -> Self {
User {
id: id,
name: name.into(),
}
}
}
What I'm getting:
error: expected one of `(` or `<`, found `impl_type`
--> src/macros/impl_type.rs:39:24
|
38 | impl $name {
| ____________________-
| |____________________|
| |
39 | | pub fn new impl_type!(@template_if_string $($field_type,)*)
| | ^^^^^^^^^ expected one of `(` or `<`
40 | | ($($field: impl_type!(@ty_fn $field_type),)*) -> Self {
My macro_rules!
code:
macro_rules! impl_type {
(
$name:ident {
$($field:ident : $field_type:ty,)*
}
) => {
pub struct $name {
$($field: $field_type,)*
}
impl $name {
pub fn new impl_type!(@template_if_string $($field_type,)*)
($($field: impl_type!(@ty_fn $field_type),)*) -> Self {
$name {
$($field: ($field).into(),)*
}
}
}
};
(@ty_fn String) => ( S );
(@ty_fn $field_type:ty) => ( impl_type!($field_type) );
(@template_if_string) => {};
(@template_if_string String, $($field_type:ty,)*) => {
<S: std::convert::Into<String>>
};
(@template_if_string $field_type:ty, $($other_field_type:ty,)*) => {
impl_type!(@template_if_string $($other_field_type,)*)
};
}
How could I invoke impl_type!
after new
or refactor the code so it works as intended?
I'm new to Rust. Any help is appreciated, thanks for your patience.