dynec-codegen 0.2.1

dynec codegen library implementation
Documentation
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::Error;

use super::parse_maybe_uninit;
use crate::util::{Attr, Named, Result};

pub(super) enum Arg {
    Param(Option<syn::token::Paren>, Attr<ParamArg>),
    Local(Option<syn::token::Paren>, Attr<LocalArg>),
    Global(Option<syn::token::Paren>, Attr<GlobalArg>),
    Simple(Option<syn::token::Paren>, Attr<SimpleArg>),
    Isotope(Option<syn::token::Paren>, Attr<IsotopeArg>),
    EntityCreator(Option<syn::token::Paren>, Attr<EntityCreatorArg>),
    EntityDeleter(Option<syn::token::Paren>, Attr<EntityDeleterArg>),
    EntityIterator(Option<syn::token::Paren>, Attr<EntityIteratorArg>),
}

impl Parse for Named<Arg> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse::<syn::Ident>()?;
        let name_string = name.to_string();

        let value = match name_string.as_str() {
            "param" => parse_opt_list(input, Arg::Param)?,
            "local" => parse_opt_list(input, Arg::Local)?,
            "global" => parse_opt_list(input, Arg::Global)?,
            "simple" => parse_opt_list(input, Arg::Simple)?,
            "isotope" => parse_opt_list(input, Arg::Isotope)?,
            "entity_creator" => parse_opt_list(input, Arg::EntityCreator)?,
            "entity_deleter" => parse_opt_list(input, Arg::EntityDeleter)?,
            "entity_iterator" => parse_opt_list(input, Arg::EntityIterator)?,
            _ => return Err(Error::new_spanned(&name, "Unknown attribute")),
        };
        Ok(Named { name, value })
    }
}

fn parse_opt_list<T>(
    input: ParseStream,
    arg_opt_variant: fn(Option<syn::token::Paren>, Attr<T>) -> Arg,
) -> Result<Arg>
where
    Named<T>: Parse,
{
    let mut paren = None;
    let mut opts = Attr::default();

    if input.peek(syn::token::Paren) {
        let inner;
        paren = Some(syn::parenthesized!(inner in input));
        opts = inner.parse::<Attr<T>>()?;
    }

    Ok(arg_opt_variant(paren, opts))
}

pub(super) enum LocalArg {
    HasEntity,
    HasNoEntity,
    Initial(syn::Token![=], Box<syn::Expr>),
}

impl Parse for Named<LocalArg> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse::<syn::Ident>()?;
        let name_string = name.to_string();

        let value = match name_string.as_str() {
            "entity" => LocalArg::HasEntity,
            "not_entity" => LocalArg::HasNoEntity,
            "initial" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let expr = input.parse::<syn::Expr>()?;
                LocalArg::Initial(eq, Box::new(expr))
            }
            _ => return Err(Error::new_spanned(&name, "Unknown option for #[dynec(local)]")),
        };
        Ok(Named { name, value })
    }
}

pub(super) enum ParamArg {
    HasEntity,
    HasNoEntity,
}

impl Parse for Named<ParamArg> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse::<syn::Ident>()?;
        let name_string = name.to_string();

        let value = match name_string.as_str() {
            "entity" => ParamArg::HasEntity,
            "not_entity" => ParamArg::HasNoEntity,
            _ => return Err(Error::new_spanned(&name, "Unknown option for #[dynec(param)]")),
        };
        Ok(Named { name, value })
    }
}

pub(super) enum GlobalArg {
    ThreadLocal,
    MaybeUninit(syn::token::Paren, Punctuated<syn::Type, syn::Token![,]>),
}

impl Parse for Named<GlobalArg> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse::<syn::Ident>()?;
        let name_string = name.to_string();

        let value = match name_string.as_str() {
            "thread_local" => GlobalArg::ThreadLocal,
            "maybe_uninit" => parse_maybe_uninit(input, GlobalArg::MaybeUninit)?,
            _ => return Err(Error::new_spanned(&name, "Unknown option for #[dynec(global)]")),
        };
        Ok(Named { name, value })
    }
}

pub(super) enum SimpleArg {
    Mutable,
    Arch(syn::Token![=], Box<syn::Type>),
    Comp(syn::Token![=], Box<syn::Type>),
    MaybeUninit(syn::token::Paren, Punctuated<syn::Type, syn::Token![,]>),
}

impl Parse for Named<SimpleArg> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse::<syn::Ident>()?;
        let name_string = name.to_string();

        let value = match name_string.as_str() {
            "mut" => SimpleArg::Mutable,
            "arch" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let ty = input.parse::<syn::Type>()?;
                SimpleArg::Arch(eq, Box::new(ty))
            }
            "comp" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let ty = input.parse::<syn::Type>()?;
                SimpleArg::Comp(eq, Box::new(ty))
            }
            "maybe_uninit" => parse_maybe_uninit(input, SimpleArg::MaybeUninit)?,
            _ => return Err(Error::new_spanned(&name, "Unknown option for #[dynec(simple)]")),
        };
        Ok(Named { name, value })
    }
}

pub(super) enum IsotopeArg {
    Mutable,
    Arch(syn::Token![=], Box<syn::Type>),
    Comp(syn::Token![=], Box<syn::Type>),
    Discrim(syn::Token![=], Box<syn::Expr>),
    DiscrimSet(syn::Token![=], Box<syn::Type>),
    MaybeUninit(syn::token::Paren, Punctuated<syn::Type, syn::Token![,]>),
}

impl Parse for Named<IsotopeArg> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse::<syn::Ident>()?;
        let name_string = name.to_string();

        let value = match name_string.as_str() {
            "mut" => IsotopeArg::Mutable,
            "arch" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let ty = input.parse::<syn::Type>()?;
                IsotopeArg::Arch(eq, Box::new(ty))
            }
            "comp" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let ty = input.parse::<syn::Type>()?;
                IsotopeArg::Comp(eq, Box::new(ty))
            }
            "discrim" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let discrim = input.parse::<syn::Expr>()?;
                IsotopeArg::Discrim(eq, Box::new(discrim))
            }
            "discrim_set" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let ty = input.parse::<syn::Type>()?;
                IsotopeArg::DiscrimSet(eq, Box::new(ty))
            }
            "maybe_uninit" => parse_maybe_uninit(input, IsotopeArg::MaybeUninit)?,
            _ => return Err(Error::new_spanned(&name, "Unknown option for #[dynec(isotope)]")),
        };
        Ok(Named { name, value })
    }
}

pub(super) enum EntityCreatorArg {
    Arch(syn::Token![=], Box<syn::Type>),
    NoPartition,
}

impl Parse for Named<EntityCreatorArg> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse::<syn::Ident>()?;
        let name_string = name.to_string();

        let value = match name_string.as_str() {
            "arch" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let ty = input.parse::<syn::Type>()?;
                EntityCreatorArg::Arch(eq, Box::new(ty))
            }
            "no_partition" => EntityCreatorArg::NoPartition,
            _ => {
                return Err(Error::new_spanned(
                    &name,
                    "Unknown option for #[dynec(entity_creator)]",
                ))
            }
        };
        Ok(Named { name, value })
    }
}

pub(super) enum EntityDeleterArg {
    Arch(syn::Token![=], Box<syn::Type>),
}

impl Parse for Named<EntityDeleterArg> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse::<syn::Ident>()?;
        let name_string = name.to_string();

        let value = match name_string.as_str() {
            "arch" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let ty = input.parse::<syn::Type>()?;
                EntityDeleterArg::Arch(eq, Box::new(ty))
            }
            _ => {
                return Err(Error::new_spanned(
                    &name,
                    "Unknown option for #[dynec(entity_deleter)]",
                ))
            }
        };
        Ok(Named { name, value })
    }
}

pub(super) enum EntityIteratorArg {
    Arch(syn::Token![=], Box<syn::Type>),
}

impl Parse for Named<EntityIteratorArg> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse::<syn::Ident>()?;
        let name_string = name.to_string();

        let value = match name_string.as_str() {
            "arch" => {
                let eq = input.parse::<syn::Token![=]>()?;
                let ty = input.parse::<syn::Type>()?;
                EntityIteratorArg::Arch(eq, Box::new(ty))
            }
            _ => {
                return Err(Error::new_spanned(
                    &name,
                    "Unknown option for #[dynec(entity_iterator)]",
                ))
            }
        };
        Ok(Named { name, value })
    }
}