use super::*;
pub struct StructDef {
pub kind: StructKind,
pub attrs: Vec<Attribute>,
pub vis: Visibility,
pub name: Ident,
pub fields: Vec<FieldDef>,
pub nested_items: Vec<ItemDef>,
}
impl Parse for StructDef {
fn parse(input: ParseStream) -> Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let vis = input.parse::<Visibility>()?;
input.parse::<Token![struct]>()?;
let name = input.parse::<Ident>()?;
let mut nested_items: Vec<ItemDef> = Vec::new();
if input.peek(syn::token::Paren) {
let kind = StructKind::TupleStruct;
let content;
syn::parenthesized!(content in input);
let mut fields = Vec::new();
while !content.is_empty() {
let attrs = content.call(Attribute::parse_outer)?;
let vis = content.parse::<Visibility>()?;
let ty = content.parse::<Type>()?;
let name = Ident::new(&format!("_{}", fields.len()), ty.span());
fields.push(FieldDef {
attrs,
vis,
name,
ty,
});
if content.peek(Token![,]) {
content.parse::<Token![,]>()?;
}
}
input.parse::<Token![;]>()?;
return Ok(Self {
kind,
attrs,
vis,
name,
fields,
nested_items,
});
}
if input.peek(syn::token::Brace) {
let kind = StructKind::FieldStruct;
let content;
syn::braced!(content in input);
let mut fields = Vec::new();
while !content.is_empty() {
let is_nested_item = {
let lookahead = content.fork();
lookahead.call(Attribute::parse_outer).is_ok()
&& lookahead.parse::<Visibility>().is_ok()
&& lookahead.parse::<Option<Token![async]>>().is_ok()
&& (lookahead.peek(Token![struct])
|| lookahead.peek(Token![enum])
|| lookahead.peek(Token![impl])
|| lookahead.peek(Token![fn]))
};
if is_nested_item {
let mut result = content.parse()?;
match &mut result {
ItemDef::LooseFunc { func: _, parent } => {
*parent = Some(name.clone());
}
_ => {}
}
nested_items.push(result);
if content.peek(Token![,]) {
content.parse::<Token![,]>()?;
}
continue;
}
let is_field = {
let lookahead = content.fork();
lookahead.call(Attribute::parse_outer).is_ok()
&& lookahead.parse::<Visibility>().is_ok()
&& lookahead.parse::<Ident>().is_ok()
&& lookahead.peek(Token![:])
};
if is_field {
let attrs = content.call(Attribute::parse_outer)?;
let vis = content.parse::<Visibility>()?;
let name = content.parse::<Ident>()?;
content.parse::<Token![:]>()?;
let ty = content.parse::<Type>()?;
fields.push(FieldDef {
attrs,
vis,
name,
ty,
});
if content.peek(Token![,]) {
content.parse::<Token![,]>()?;
}
continue;
}
return Err(content.error("Expected field, struct, impl, or function"));
}
return Ok(Self {
kind,
attrs,
vis,
name,
fields,
nested_items,
});
}
if input.peek(Token![;]) {
let kind = StructKind::MarkerStruct;
input.parse::<Token![;]>()?;
return Ok(Self {
kind,
attrs,
vis,
name,
fields: Vec::new(),
nested_items,
});
}
return Err(input.error("Expected a valid struct"));
}
}
pub enum StructKind {
FieldStruct,
TupleStruct,
MarkerStruct,
}