attrimpl 0.5.0

The crate provides attributes to automatically implement common traits and reduce boilerplate code.
Documentation
use crate::{access_params::AccessParams, get_mut_params::GetMutParams, get_params::GetParams};

#[derive(Clone)]
pub enum DirectiveKind {
    From,
    Into,
    Convert,

    GetRef(GetParams),
    GetCopy(GetParams),
    GetClone(GetParams),
    GetMut(GetMutParams),
    Access(AccessParams),

    AsRef,
    AsMut,
    As,

    Deref,
    DerefMut,
}

pub struct Directive {
    pub span: proc_macro2::Span,
    pub kind: DirectiveKind,
}

impl Directive {
    pub fn span(&self) -> proc_macro2::Span {
        self.span
    }
}

impl DirectiveKind {
    fn name(&self) -> &'static str {
        match self {
            DirectiveKind::From => "from",
            DirectiveKind::Into => "into",
            DirectiveKind::Convert => "convert",

            DirectiveKind::GetRef(_) => "get_ref",
            DirectiveKind::GetCopy(_) => "get_copy",
            DirectiveKind::GetClone(_) => "get_clone",
            DirectiveKind::GetMut(_) => "get_mut",
            DirectiveKind::Access(_) => "access",

            DirectiveKind::AsRef => "as_ref",
            DirectiveKind::AsMut => "as_mut",
            DirectiveKind::As => "as",

            DirectiveKind::Deref => "deref",
            DirectiveKind::DerefMut => "deref_mut",
        }
    }

    pub fn is_conflicted_with(&self, other: &DirectiveKind) -> bool {
        match self {
            DirectiveKind::From => match other {
                DirectiveKind::From | DirectiveKind::Convert => true,
                DirectiveKind::Into
                | DirectiveKind::GetRef(_)
                | DirectiveKind::GetCopy(_)
                | DirectiveKind::GetClone(_)
                | DirectiveKind::GetMut(_)
                | DirectiveKind::Access(_)
                | DirectiveKind::AsRef
                | DirectiveKind::AsMut
                | DirectiveKind::As
                | DirectiveKind::Deref
                | DirectiveKind::DerefMut => false,
            },
            DirectiveKind::Into => match other {
                DirectiveKind::Into | DirectiveKind::Convert => true,
                DirectiveKind::From
                | DirectiveKind::GetRef(_)
                | DirectiveKind::GetCopy(_)
                | DirectiveKind::GetClone(_)
                | DirectiveKind::GetMut(_)
                | DirectiveKind::Access(_)
                | DirectiveKind::AsRef
                | DirectiveKind::AsMut
                | DirectiveKind::As
                | DirectiveKind::Deref
                | DirectiveKind::DerefMut => false,
            },
            DirectiveKind::Convert => match other {
                DirectiveKind::From | DirectiveKind::Into | DirectiveKind::Convert => true,
                DirectiveKind::GetRef(_)
                | DirectiveKind::GetCopy(_)
                | DirectiveKind::GetClone(_)
                | DirectiveKind::GetMut(_)
                | DirectiveKind::Access(_)
                | DirectiveKind::AsRef
                | DirectiveKind::AsMut
                | DirectiveKind::As
                | DirectiveKind::Deref
                | DirectiveKind::DerefMut => false,
            },
            DirectiveKind::GetRef(GetParams { name })
            | DirectiveKind::GetCopy(GetParams { name })
            | DirectiveKind::GetClone(GetParams { name })
            | DirectiveKind::GetMut(GetMutParams { name }) => match other {
                DirectiveKind::GetRef(GetParams { name: other_name })
                | DirectiveKind::GetCopy(GetParams { name: other_name })
                | DirectiveKind::GetClone(GetParams { name: other_name })
                | DirectiveKind::GetMut(GetMutParams { name: other_name }) => *name == *other_name,
                DirectiveKind::Access(AccessParams {
                    get_name,
                    get_mut_name,
                    ..
                }) => *name == *get_name || *name == *get_mut_name,
                DirectiveKind::From
                | DirectiveKind::Into
                | DirectiveKind::Convert
                | DirectiveKind::AsRef
                | DirectiveKind::AsMut
                | DirectiveKind::As
                | DirectiveKind::Deref
                | DirectiveKind::DerefMut => false,
            },
            DirectiveKind::Access(params) => match other {
                DirectiveKind::GetRef(GetParams { name })
                | DirectiveKind::GetCopy(GetParams { name })
                | DirectiveKind::GetClone(GetParams { name })
                | DirectiveKind::GetMut(GetMutParams { name }) => {
                    params.get_name == *name || params.get_mut_name == *name
                }
                DirectiveKind::Access(AccessParams {
                    get_name,
                    get_mut_name,
                    ..
                }) => {
                    params.get_name == *get_name
                        || params.get_name == *get_mut_name
                        || params.get_mut_name == *get_name
                        || params.get_mut_name == *get_mut_name
                }
                DirectiveKind::From
                | DirectiveKind::Into
                | DirectiveKind::Convert
                | DirectiveKind::AsRef
                | DirectiveKind::AsMut
                | DirectiveKind::As
                | DirectiveKind::Deref
                | DirectiveKind::DerefMut => false,
            },
            DirectiveKind::AsRef => match other {
                DirectiveKind::AsRef | DirectiveKind::As => true,
                DirectiveKind::From
                | DirectiveKind::Into
                | DirectiveKind::Convert
                | DirectiveKind::GetRef(_)
                | DirectiveKind::GetCopy(_)
                | DirectiveKind::GetClone(_)
                | DirectiveKind::GetMut(_)
                | DirectiveKind::Access(_)
                | DirectiveKind::AsMut
                | DirectiveKind::Deref
                | DirectiveKind::DerefMut => false,
            },
            DirectiveKind::AsMut => match other {
                DirectiveKind::AsMut | DirectiveKind::As => true,
                DirectiveKind::From
                | DirectiveKind::Into
                | DirectiveKind::Convert
                | DirectiveKind::GetRef(_)
                | DirectiveKind::GetCopy(_)
                | DirectiveKind::GetClone(_)
                | DirectiveKind::GetMut(_)
                | DirectiveKind::Access(_)
                | DirectiveKind::AsRef
                | DirectiveKind::Deref
                | DirectiveKind::DerefMut => false,
            },
            DirectiveKind::As => match other {
                DirectiveKind::AsRef | DirectiveKind::AsMut | DirectiveKind::As => true,
                DirectiveKind::From
                | DirectiveKind::Into
                | DirectiveKind::Convert
                | DirectiveKind::GetRef(_)
                | DirectiveKind::GetCopy(_)
                | DirectiveKind::GetClone(_)
                | DirectiveKind::GetMut(_)
                | DirectiveKind::Access(_)
                | DirectiveKind::Deref
                | DirectiveKind::DerefMut => false,
            },
            DirectiveKind::Deref => match other {
                DirectiveKind::Deref => true,
                DirectiveKind::From
                | DirectiveKind::Into
                | DirectiveKind::Convert
                | DirectiveKind::GetRef(_)
                | DirectiveKind::GetCopy(_)
                | DirectiveKind::GetClone(_)
                | DirectiveKind::GetMut(_)
                | DirectiveKind::Access(_)
                | DirectiveKind::AsRef
                | DirectiveKind::AsMut
                | DirectiveKind::As
                | DirectiveKind::DerefMut => false,
            },
            DirectiveKind::DerefMut => match other {
                DirectiveKind::DerefMut => true,
                DirectiveKind::From
                | DirectiveKind::Into
                | DirectiveKind::Convert
                | DirectiveKind::GetRef(_)
                | DirectiveKind::GetCopy(_)
                | DirectiveKind::GetClone(_)
                | DirectiveKind::GetMut(_)
                | DirectiveKind::Access(_)
                | DirectiveKind::AsRef
                | DirectiveKind::AsMut
                | DirectiveKind::As
                | DirectiveKind::Deref => false,
            },
        }
    }
}

impl std::fmt::Display for DirectiveKind {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.name())
    }
}

impl Directive {
    pub fn parse(
        input: syn::parse::ParseStream,
        default_name: Option<syn::Ident>,
    ) -> syn::Result<Self> {
        let ident: syn::Ident = input.parse()?;
        let kind = match ident.to_string().as_str() {
            "from" => DirectiveKind::From,
            "into" => DirectiveKind::Into,
            "convert" => DirectiveKind::Convert,

            "get_ref" => DirectiveKind::GetRef(GetParams::parse(input, default_name)?),
            "get_clone" => DirectiveKind::GetClone(GetParams::parse(input, default_name)?),
            "get_copy" => DirectiveKind::GetCopy(GetParams::parse(input, default_name)?),
            "get_mut" => DirectiveKind::GetMut(GetMutParams::parse(input, default_name)?),
            "access" => DirectiveKind::Access(AccessParams::parse(input, default_name)?),

            "as_ref" => DirectiveKind::AsRef,
            "as_mut" => DirectiveKind::AsMut,
            "as" => DirectiveKind::As,

            "deref" => DirectiveKind::Deref,
            "deref_mut" => DirectiveKind::DerefMut,

            _ => {
                return Err(syn::Error::new(
                    ident.span(),
                    format!("unknown directive `{}`", ident),
                ));
            }
        };

        Ok(Directive {
            span: ident.span(),
            kind,
        })
    }
}