o2o-impl 0.5.4

Implementation of 'o2o' crate
Documentation
use crate::attr::{self};
use crate::attr::{DataTypeAttrs, MemberAttrs};
use proc_macro2::Span;
use quote::ToTokens;

#[cfg(feature = "syn2")]
use syn2 as syn;

use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::Comma;
use syn::{Attribute, DataEnum, DataStruct, DeriveInput, Fields, Generics, Ident, Index, Member, Path, Result};

#[derive(Default)]
struct Context {
    variant_attrs_to_repeat: Option<MemberAttrs>,
    field_attrs_to_repeat: Option<(MemberAttrs, bool)>,
}

pub(crate) struct Struct<'a> {
    pub attrs: DataTypeAttrs,
    pub ident: &'a Ident,
    pub generics: &'a Generics,
    pub fields: Vec<Field>,
    pub named_fields: bool,
    pub unit: bool,
}

impl<'a> Struct<'a> {
    pub fn from_syn(node: &'a DeriveInput, data: &'a DataStruct) -> Result<Self> {
        let (attrs, bark) = attr::get_data_type_attrs(&node.attrs)?;
        let fields = Field::multiple_from_syn(&mut Default::default(), &data.fields, bark)?;
        Ok(Struct {
            attrs,
            ident: &node.ident,
            generics: &node.generics,
            fields,
            named_fields: matches!(&data.fields, Fields::Named(_)),
            unit: matches!(&data.fields, Fields::Unit),
        })
    }
}

#[derive(Clone)]
pub(crate) struct Field {
    pub attrs: MemberAttrs,
    pub idx: usize,
    pub member: Member,
    pub member_str: String,
    pub ty: Option<Path>
}

impl<'a> Field {
    fn multiple_from_syn(ctx: &mut Context, fields: &'a Fields, bark: bool) -> Result<Vec<Self>> {
        fields
            .iter()
            .enumerate()
            .map(move |(i, field)| {
                let mut field = Field::from_syn(i, field, bark)?;

                if field.attrs.stop_repeat {
                    ctx.field_attrs_to_repeat = None;
                }

                if let Some(repeat_attr) = &field.attrs.repeat {
                    if ctx.field_attrs_to_repeat.is_some() && !field.attrs.stop_repeat {
                        panic!("Previous #[repeat] instruction must be terminated with #[stop_repeat]")
                    }

                    ctx.field_attrs_to_repeat = Some((field.attrs.clone(), repeat_attr.permeate));
                } else if let Some(attrs_to_repeat) = &ctx.field_attrs_to_repeat {
                    field.attrs.merge(attrs_to_repeat.0.clone());
                }

                Ok(field)
            })
            .collect()
    }

    fn from_syn(idx: usize, node: &'a syn::Field, bark: bool) -> Result<Self> {
        let member = node.ident.clone().map(Member::Named).unwrap_or_else(|| {
            Member::Unnamed(Index {
                index: idx as u32,
                span: node.ty.span(),
            })
        });
        let member_str = member.to_token_stream().to_string();

        Ok(Field {
            attrs: attr::get_member_attrs(SynDataTypeMember::Field(node), bark)?,
            idx,
            member,
            member_str,
            ty: match &node.ty {
                syn::Type::Path(p) => Some(p.path.clone()),
                _ => None
            }
        })
    }
}

pub(crate) struct Enum<'a> {
    pub attrs: DataTypeAttrs,
    pub ident: &'a Ident,
    pub generics: &'a Generics,
    pub variants: Vec<Variant>,
}

impl<'a> Enum<'a> {
    pub fn from_syn(node: &'a DeriveInput, data: &'a DataEnum) -> Result<Self> {
        let (attrs, bark) = attr::get_data_type_attrs(&node.attrs)?;
        let variants = Variant::multiple_from_syn(&data.variants, bark)?;
        Ok(Enum { attrs, ident: &node.ident, generics: &node.generics, variants })
    }
}

pub(crate) struct Variant {
    pub attrs: MemberAttrs,
    pub ident: Ident,
    _idx: usize,
    pub fields: Vec<Field>,
    pub named_fields: bool,
    pub unit: bool,
}

impl<'a> Variant {
    fn multiple_from_syn(variants: &'a Punctuated<syn::Variant, Comma>, bark: bool) -> Result<Vec<Self>> {
        let mut ctx = Context { variant_attrs_to_repeat: None, field_attrs_to_repeat: None };

        variants
            .iter()
            .enumerate()
            .map(move |(i, variant)| {
                let mut variant = Variant::from_syn(&mut ctx, i, variant, bark)?;

                if variant.attrs.stop_repeat {
                    ctx.variant_attrs_to_repeat = None;
                }

                if variant.attrs.repeat.is_some() {
                    if ctx.variant_attrs_to_repeat.is_some() && !variant.attrs.stop_repeat {
                        panic!("Previous #[repeat] instruction must be terminated with #[stop_repeat]")
                    }

                    ctx.variant_attrs_to_repeat = Some(variant.attrs.clone());
                } else if let Some(attrs_to_repeat) = &ctx.variant_attrs_to_repeat {
                    variant.attrs.merge(attrs_to_repeat.clone());
                }

                Ok(variant)
            })
            .collect()
    }

    fn from_syn(ctx: &mut Context, i: usize, variant: &'a syn::Variant, bark: bool) -> Result<Self> {
        let fields = Field::multiple_from_syn(ctx, &variant.fields, bark)?;
        let attrs = attr::get_member_attrs(SynDataTypeMember::Variant(variant), bark)?;

        if let Some((_, permeating)) = &ctx.field_attrs_to_repeat {
            if !permeating {
                ctx.field_attrs_to_repeat = None;
            }
        }

        Ok(Variant {
            attrs,
            ident: variant.ident.clone(),
            _idx: i,
            fields,
            named_fields: matches!(&variant.fields, Fields::Named(_)),
            unit: matches!(&variant.fields, Fields::Unit),
        })
    }
}

pub(crate) enum DataType<'a> {
    Struct(&'a Struct<'a>),
    Enum(&'a Enum<'a>),
}

impl<'a> DataType<'a> {
    pub fn get_ident(&'a self) -> &Ident {
        match self {
            DataType::Struct(s) => s.ident,
            DataType::Enum(e) => e.ident,
        }
    }

    pub fn named_fields(&'a self) -> bool {
        match self {
            DataType::Struct(s) => s.named_fields,
            DataType::Enum(_) => panic!("Method 'named_fields' is not supposed to be called in the enum context."),
        }
    }

    pub fn get_attrs(&'a self) -> &'a DataTypeAttrs {
        match self {
            DataType::Struct(s) => &s.attrs,
            DataType::Enum(e) => &e.attrs,
        }
    }

    pub fn get_members(&'a self) -> Vec<DataTypeMember> {
        match self {
            DataType::Struct(s) => s.fields.iter().map(DataTypeMember::Field).collect(),
            DataType::Enum(e) => e.variants.iter().map(DataTypeMember::Variant).collect(),
        }
    }

    pub fn get_generics(&'a self) -> &'a Generics {
        match self {
            DataType::Struct(s) => s.generics,
            DataType::Enum(e) => e.generics,
        }
    }
}

pub(crate) enum SynDataTypeMember<'a> {
    Field(&'a syn::Field),
    Variant(&'a syn::Variant),
}

impl<'a> SynDataTypeMember<'a> {
    pub fn get_attrs(&'a self) -> &'a Vec<Attribute> {
        match self {
            SynDataTypeMember::Field(f) => &f.attrs,
            SynDataTypeMember::Variant(v) => &v.attrs,
        }
    }
}

#[derive(Clone, Copy)]
pub(crate) enum DataTypeMember<'a> {
    Field(&'a Field),
    Variant(&'a Variant),
}

impl<'a> DataTypeMember<'a> {
    pub fn get_attrs(&'a self) -> &'a MemberAttrs {
        match self {
            DataTypeMember::Field(f) => &f.attrs,
            DataTypeMember::Variant(v) => &v.attrs,
        }
    }

    pub fn get_span(&'a self) -> Span {
        match self {
            DataTypeMember::Field(f) => f.member.span(),
            DataTypeMember::Variant(v) => v.ident.span(),
        }
    }
}