use unsynn::*;
keyword! {
pub KPub = "pub";
pub KStruct = "struct";
pub KCrate = "crate";
pub KIn = "in";
pub KWhere = "where";
}
operator! {
pub Eq = "=";
pub Semi = ";";
pub PathSep = "::";
pub Lt = "<";
pub Gt = ">";
}
pub type ModPath = Cons<Option<PathSep>, PathSepDelimited<Ident>>;
pub type VerbatimUntil<C> = Many<Cons<Except<C>, AngleTokenTree>>;
unsynn! {
#[derive(Clone)]
pub struct AngleTokenTree(
#[allow(clippy::type_complexity)]
pub Either<Cons<Lt, Vec<Cons<Except<Gt>, AngleTokenTree>>, Gt>, TokenTree>,
);
#[derive(Clone)]
pub enum Vis {
PubIn(Cons<KPub, ParenthesisGroupContaining<Cons<Option<KIn>, ModPath>>>),
Pub(KPub),
}
#[derive(Clone)]
pub struct Attribute {
pub _pound: Pound,
pub _inner: Option<Bang>,
pub body: BracketGroupContaining<Vec<TokenTree>>,
}
pub struct ItemStruct {
pub attrs: Vec<Attribute>,
pub vis: Option<Vis>,
pub _struct_token: KStruct,
pub ident: Ident,
pub generics: Option<Generics>,
pub where_clause: Option<WhereClause>,
pub fields: Fields,
pub semi_token: Option<Semicolon>,
}
pub struct Generics {
pub _lt: Lt,
pub params: Vec<TokenTree>,
pub _gt: Gt,
}
pub struct WhereClause {
pub _where: KWhere,
pub predicates: Vec<TokenTree>,
}
#[derive(Clone)]
pub enum Fields {
Named(BraceGroupContaining<CommaDelimitedVec<NamedField>>),
Unnamed(ParenthesisGroupContaining<CommaDelimitedVec<UnnamedField>>),
Unit(Nothing),
}
#[derive(Clone)]
pub struct NamedField {
pub attrs: Vec<Attribute>,
pub vis: Option<Vis>,
pub ident: Ident,
pub _colon: Colon,
pub ty: Type,
}
#[derive(Clone)]
pub struct UnnamedField {
pub attrs: Vec<Attribute>,
pub vis: Option<Vis>,
pub ty: Type,
}
#[derive(Clone)]
pub struct Type {
pub tokens: VerbatimUntil<Either<Comma, Gt, Semicolon>>,
}
}
impl ItemStruct {
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
match &self.fields {
Fields::Named(f) => f.content.is_empty(),
Fields::Unnamed(f) => f.content.is_empty(),
Fields::Unit(_) => true,
}
}
}
#[allow(dead_code)]
pub enum Field<'a> {
Named(&'a NamedField),
Unnamed(&'a UnnamedField),
}
#[allow(dead_code)]
impl<'a> Field<'a> {
pub fn attrs(&self) -> &[Attribute] {
match self {
Field::Named(f) => &f.attrs,
Field::Unnamed(f) => &f.attrs,
}
}
pub fn ty(&self) -> &Type {
match self {
Field::Named(f) => &f.ty,
Field::Unnamed(f) => &f.ty,
}
}
pub fn ident(&self) -> Option<&Ident> {
match self {
Field::Named(f) => Some(&f.ident),
Field::Unnamed(_) => None,
}
}
pub fn vis(&self) -> Option<&Vis> {
match self {
Field::Named(f) => f.vis.as_ref(),
Field::Unnamed(f) => f.vis.as_ref(),
}
}
}
impl Type {
pub fn to_token_stream(&self) -> TokenStream {
let mut tokens = TokenStream::new();
for cons in self.tokens.iter() {
cons.value.to_tokens(&mut tokens);
}
tokens
}
}
impl quote::ToTokens for Type {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(self.to_token_stream());
}
}
impl quote::ToTokens for Attribute {
fn to_tokens(&self, tokens: &mut TokenStream) {
self._pound.to_tokens(tokens);
if let Some(ref inner) = self._inner {
inner.to_tokens(tokens);
}
self.body.to_tokens(tokens);
}
}
impl quote::ToTokens for ItemStruct {
fn to_tokens(&self, tokens: &mut TokenStream) {
for attr in &self.attrs {
quote::ToTokens::to_tokens(attr, tokens);
}
if let Some(ref vis) = self.vis {
tokens.extend(vis.to_token_stream());
}
tokens.extend(self._struct_token.to_token_stream());
quote::ToTokens::to_tokens(&self.ident, tokens);
if let Some(ref generics) = self.generics {
tokens.extend(generics.to_token_stream());
}
if let Some(ref where_clause) = self.where_clause {
tokens.extend(where_clause.to_token_stream());
}
tokens.extend(self.fields.to_token_stream());
if let Some(ref semi) = self.semi_token {
tokens.extend(semi.to_token_stream());
}
}
}