derivor 0.0.1

Some useful Derive(Trait) macro options.
Documentation
pub(crate) mod constants;
#[cfg(feature = "enums")]
pub(crate) mod enums;
#[cfg(any(feature = "enums", feature = "structs", feature = "unions"))]
pub(crate) mod fields;
#[cfg(feature = "structs")]
pub(crate) mod structs;
#[cfg(feature = "unions")]
pub(crate) mod unions;

use constants::CTOR_WORD;
#[cfg(feature = "enums")]
use enums::create_enum_token_stream;
#[cfg(feature = "structs")]
use structs::create_struct_token_stream;
#[cfg(feature = "unions")]
use unions::create_union_token_stream;


use {
    alloc::{
        format,
        string::{
            String, ToString
        },
    },
    quote::ToTokens,
    proc_macro::{
        TokenStream,
    },
    proc_macro2::{
        Delimiter, Ident, Span
    },
    syn::{
        token::Pub,
        spanned::Spanned,
        parse::{
            Parse, ParseStream,
            discouraged::AnyDelimiter,
        },
        parse_macro_input, Data, DeriveInput, Error, Type, Visibility,
    },
    crate::{
        BTreeSet,
    }
};

pub(crate) struct Definition {
    pub(crate) visibility: Visibility,
    pub(crate) ident: Ident,
    pub(crate) attrs: BTreeSet<Attribute>,
}

#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum Attribute {
    Const,
    DefaultAll,
    Default,
    IntoAll,
}

impl Default for Definition {
    fn default() -> Self {
        Self {
            visibility: Visibility::Public(Pub {
                span: Span::call_site(),
            }),
            ident: Ident::new("new", Span::mixed_site()),
            attrs: Default::default(),
        }
    }
}

pub(crate) fn adjust_keyword_ident(name: String) -> String {
    if syn::parse_str::<Ident>(&name).is_ok() {
        return name;
    }

    format!("r#{}", name)
}

#[cfg(not(any(feature = "enums", feature = "structs", feature = "unions")))]
pub(crate) fn derive_ctor_internal(input: TokenStream) -> TokenStream {
    let derive_input = parse_macro_input!(input as DeriveInput);

    match &derive_input.data {
        Data::Struct(_) => crate::create_struct(derive_input),
        Data::Enum(_) => crate::create_enum(derive_input),
        Data::Union(_) => crate::create_union(derive_input)
    }
}

pub(crate) fn parse_attributes_with_default<T: Parse, F: Fn() -> T>(
    attributes: &[syn::Attribute],
    default: F,
) -> Result<T, Error> {
    for attribute in attributes {
        if attribute.path().is_ident(CTOR_WORD) {
            return attribute.parse_args::<T>();
        }
    }
    Ok(default())
}

pub(crate) fn parse_attributes<T: Parse>(attributes: &[syn::Attribute]) -> Result<Option<T>, Error> {
    for attribute in attributes {
        if attribute.path().is_ident(CTOR_WORD) {
            return attribute.parse_args::<T>().map(Some);
        }
    }
    Ok(None)
}

pub(crate) fn is_phantom(typ: &Type) -> bool {
    for token in typ.to_token_stream() {
        if token.to_string() == "PhantomData" {
            return true;
        }
    }
    false
}

pub(crate) fn consume_delimited<T, F>(
    stream: ParseStream,
    expected: Delimiter,
    expression: F,
) -> Result<T, Error>
where
    F: Fn(ParseStream) -> Result<T, Error>,
{
    let (delimiter, span, buffer) = stream.parse_any_delimiter()?;
    if delimiter != expected {
        return Err(Error::new(span.span(),
                              format!("Expected enclosing {:?}", expected),
        ));
    }
    expression(&buffer)
}