xavier-derive 0.1.7

Derive module of Xavier. Xavier is a lightweight and versatile XML parsing library designed to streamline the process of handling XML data with ease and efficiency.
Documentation
use proc_macro2::Ident;
use quote::quote;
use syn::Data::Struct;
use syn::{DeriveInput, Fields};
use crate::common::meta::{MetaInfo, MetaName};
use crate::common::naming::names::XmlNames;
use crate::deserialize::parser::complex::tokens::constructor::{Constructor, ConstructorField};
use crate::deserialize::parser::complex::tokens::declaration::FieldDecl;
use crate::deserialize::parser::complex::tokens::setters::attribute::FieldAttributeSetter;
use crate::deserialize::parser::complex::tokens::setters::field::FieldSetter;
use crate::deserialize::parser::complex::tokens::setters::sibling::SiblingSetter;
use crate::deserialize::parser::complex::tokens::setters::value::ValueSetter;
use crate::deserialize::parser::complex::tokens::setters::xmlns::FieldXmlnsSetter;
use crate::deserialize::parser::complex::tokens::types::TypeParser;

pub struct TokenSegments {
    pub declarations: Vec<FieldDecl>,
    pub attribute_setters: Vec<FieldAttributeSetter>,
    pub field_setters: Vec<FieldSetter>,
    pub sibling_setters: Vec<SiblingSetter>,
    pub value_setters: Vec<ValueSetter>,
    pub xmlns_setter: Option<FieldXmlnsSetter>,
    pub constructor: Constructor
}

impl TokenSegments {

    pub fn tokens_from(input: &DeriveInput, obj_meta_info: Option<&MetaInfo>) -> TokenSegments {

        let mut declarations: Vec<FieldDecl> = vec![];

        let mut field_setters: Vec<FieldSetter> = vec![];
        let mut sibling_setters: Vec<SiblingSetter> = vec![];
        let mut attribute_setters: Vec<FieldAttributeSetter> = vec![];
        let mut value_setters: Vec<ValueSetter> = vec![];
        let mut xmlns_setter: Option<FieldXmlnsSetter> = None;

        let mut constructors: Vec<ConstructorField> = vec![];
        let mut field_names: Vec<Ident> = vec![];

        if let Struct(struct_item) = &input.data {
            if let Fields::Named(fields) = &struct_item.fields {

                for field in fields.named.iter() {

                    if let Some(ident) = &field.ident {

                        let field_meta = MetaInfo::from_name(&field.attrs, MetaName::XML).unwrap_or(MetaInfo::empty());
                        let inner_type = TypeParser::unbox_and_unwrap_type(&field.ty);
                        let is_flatten = field_meta.contains("tree") || field_meta.contains("flatten");
                        let is_sibling = TypeParser::is_vec(&field.ty) && is_flatten;

                        let optional_type = if field_meta.contains("inner") && TypeParser::is_vec(&field.ty) {
                            quote! { Option<#inner_type> }
                        } else {
                            quote! { Option<#inner_type> }
                        };

                        declarations.push(FieldDecl {
                            name: ident.clone(),
                            optional_type,
                        });

                        if field_meta.contains("attribute") {
                            let field_attr_name = XmlNames::attribute(&ident, obj_meta_info, &field_meta);
                            attribute_setters.push(FieldAttributeSetter {
                                is_string: TypeParser::is_string_type(&inner_type),
                                name: ident.clone(),
                                attr_name: field_attr_name
                            });
                        } else if field_meta.contains("xmlns") {
                            xmlns_setter = Some(FieldXmlnsSetter { field: ident.clone() })
                        } else if field_meta.contains("value") {
                            value_setters.push(ValueSetter { field: ident.clone(), unwrapped_type: TypeParser::unwrapped_type(&field.ty) })
                        } else if is_sibling {
                            let field_tag_name = XmlNames::tag(&ident, obj_meta_info, Some(&field_meta));
                            sibling_setters.push(SiblingSetter {
                                name: ident.clone(),
                                tag_name: field_tag_name,
                                inner_type: TypeParser::ty_from_vec(&TypeParser::unbox_and_unwrap_type(&field.ty)),
                            });
                        } else {
                            if !field_meta.contains("skip") {
                                let field_tag_name = XmlNames::tag(&ident, obj_meta_info, Some(&field_meta));
                                let inner_tag_name = XmlNames::inner(obj_meta_info, Some(&field_meta));
                                field_setters.push(FieldSetter {
                                    name: ident.clone(),
                                    is_flatten,
                                    inner_tag_name,
                                    tag_name: field_tag_name,
                                    inner_type: TypeParser::unbox_and_unwrap_type(&field.ty),
                                });
                            }
                        }

                        field_names.push(ident.clone());
                        constructors.push(ConstructorField {
                            path_idents: TypeParser::type_path_idents(&field.ty),
                            field: ident.clone(),
                        })
                    }
                }
            }
        }
        Self { declarations, field_setters, sibling_setters, attribute_setters, value_setters, xmlns_setter, constructor: Constructor { values: constructors } }
    }
}