How to parse the storage
type Vec as main type and picked generic type.
i.e, Vec and String.
That's because I want to make a function call like this
storage = Vec::new(String::from("xxx"))
main.rs
Struct example {
storage: Vec<String>
}
How to parse the storage
type Vec as main type and picked generic type.
i.e, Vec and String.
That's because I want to make a function call like this
storage = Vec::new(String::from("xxx"))
main.rs
Struct example {
storage: Vec<String>
}
I’m not entirely understanding your question here, in particular what you mean by parsing in this context, but taking your code example, it seems like you’re trying to initialize the field storage
in a struct with a value of Vec<String>
type. The right syntax for creating a vector with one or a handful of elements is to use the vec![...]
macro. To give a code example:
struct Example {
storage: Vec<String>,
}
fn main() {
let ex = Example {
storage: vec!["xxx".to_string()],
};
}
I'd like to parse the type using syn::parse_str()
function and in this case, I get the whole type: Vec<String>
for the data variable. I want to make it in two streams like Vec
and String
so that I can play with two different types.
The syn
crate is (AFAIK) mostly meant for writing procedural macros. I’m not entirely sure of what’s your use case here. What are you trying to achieve? Do you have some kind of textual input data you’re trying to turn into a Rust data structure? If yes, what format is it in?
you're right. i am making a new macro and this is to define a Default impl for the macro.
Oh, wait, are you saying you’re trying to parse the type, i.e. “Vec<String>
” itself?
Here's what I am doing now. And I want to get separated types from ty
in default_generator
function
src/derived_simple/libs.rs
#[proc_macro_derive(Simple)]
pub fn derived_simple(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let generics = add_trait_bounds(input.generics);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let defaults = default_generator(&input.data);
let gen = quote! {
impl #impl_generics Default for #name #ty_generics #where_clause {
fn default() -> Self {
#name {
#defaults
}
}
}
};
gen.into()
}
fn add_trait_bounds(mut generics: Generics) -> Generics {
for param in &mut generics.params {
if let GenericParam::Type(ref mut type_param) = *param {
type_param.bounds.push(parse_quote!(simple::Simple));
}
}
generics
}
fn default_generator(data: &Data) -> proc_macro2::TokenStream {
match *data {
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
let ty = &f.ty; // ty => Vec<String>, I want to make it separated into Vec and String
quote_spanned! {f.span() => #name: #ty,}
});
quote! {#(#recurse)*}
}
Fields::Unnamed(ref fields) => {
quote! {0}
}
Fields::Unit => {
quote! {0}
}
}
}
Data::Enum(_) | Data::Union(_) => unimplemented!(),
}
}
src/main.rs
#[derive(Simple)]
struct Storage {
data: Vec<String>
}
yes
I haven’t written any procedural macros myself yet, but looking at the syn
crate docs, it seems to me like a simple type such as Vec<String>
should be represented as a Type::Path
containing a TypePath
with qself: None
. And the path
field containing a Path
with a single segment. Finally, the PathSegment
type gives you an ident
which is going to be “Vec
” and arguments that are in angled brackets. Ultimately then AngleBracketedGenericArguments
has an args
field that is going to be containing the GenericArgument::Type
flavor of generic arguments. In case of Vec<String>
I’d expect a single such GenericArgument::Type(...)
element in that list that’s going to be your “String
” type.
Of course, to be more general, you’ll maybe want to support longer paths, too. E.g. if someone writes std::vec::Vec<String>
then it will be a path with 3 segments, “std
”, “vec
”, and “Vec<String>
”; both std
and vec
are probably going to be PathSegment
s with arguments: PathArguments::None
.
Thanks, let me try
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.