tauri-interop-macro 2.2.1

Macros for the tauri-interop crate.
Documentation
use convert_case::{Case, Casing};
use proc_macro2::Ident;
use quote::format_ident;
use syn::{Attribute, Data, DeriveInput, Type};

pub(crate) mod emit;
pub(crate) mod listen;

struct EventStruct {
    name: Ident,
    mod_name: Ident,
    fields: Vec<EventField>,
}

struct EventField {
    field_name: Ident,
    parent_field_name: Ident,
    parent_field_ty: Type,
}

fn prepare_event(derive_input: DeriveInput) -> EventStruct {
    let data_struct = match derive_input.data {
        Data::Struct(data_struct) => data_struct,
        _ => panic!("The macro only works with structs"),
    };

    if data_struct.fields.is_empty() {
        panic!("No fields provided")
    }

    if data_struct.fields.iter().any(|field| field.ident.is_none()) {
        panic!("Tuple Structs aren't supported")
    }

    let auto_naming = derive_input
        .attrs
        .iter()
        .find(|attr| attr.path().is_ident("auto_naming"))
        .map(|attr| attr.parse_args::<Ident>().unwrap().to_string());

    let name = derive_input.ident.clone();
    let (naming_case, mod_name) = match auto_naming {
        Some(naming) if naming == "EnumLike" => (Case::Pascal, format!("{name}Field")),
        Some(naming) => panic!("No naming type found for: {naming}"),
        None => (Case::Snake, name.to_string()),
    };

    let mod_name = derive_input
        .attrs
        .iter()
        .find(|attr| attr.path().is_ident("mod_name"))
        .map(|attr| attr.parse_args::<Ident>().unwrap())
        .unwrap_or(format_ident!("{}", mod_name.to_case(naming_case)));

    let fields = data_struct
        .fields
        .iter()
        .map(|field| {
            let field_ident = field.ident.as_ref().unwrap();
            let field_name = format_ident!("F{}", field_ident.to_string().to_case(Case::Pascal));

            EventField {
                field_name,
                parent_field_name: field_ident.clone(),
                parent_field_ty: field.ty.clone(),
            }
        })
        .collect::<Vec<_>>();

    EventStruct {
        name,
        mod_name,
        fields,
    }
}

struct Field {
    name: Ident,
    attributes: FieldAttributes,
    event_name: String,
    get_cmd: Ident,
}

struct FieldAttributes {
    pub parent: Ident,
    pub parent_field_name: Option<Ident>,
    pub parent_field_ty: Type,
}

fn get_field_values(attrs: Vec<Attribute>) -> FieldAttributes {
    let parent = attrs
        .iter()
        .find(|a| a.path().is_ident("parent"))
        .expect("expected parent attribute")
        .parse_args()
        .unwrap();

    let parent_field_name = attrs
        .iter()
        .find(|a| a.path().is_ident("parent_field_name"))
        .and_then(|name| name.parse_args().ok());

    let parent_field_ty = attrs
        .iter()
        .find(|a| a.path().is_ident("parent_field_ty"))
        .expect("expected ty attribute")
        .parse_args()
        .unwrap();

    FieldAttributes {
        parent,
        parent_field_name,
        parent_field_ty,
    }
}

fn prepare_field(derive_input: DeriveInput) -> Field {
    let name = derive_input.ident.clone();
    let attributes = get_field_values(derive_input.attrs);
    let event_name = format!("{}::{}", &attributes.parent, &name);
    let get_cmd = format_ident!("get_{}_{}", &attributes.parent, name);

    Field {
        event_name,
        name,
        attributes,
        get_cmd,
    }
}