extruct-macros 0.2.1

Implementation detail of the `extruct` crate. Use https://crates.io/crates/extruct in your code.
Documentation
use crate::fields::Ast;

use syn::{Fields, FieldsNamed, Generics, Ident};

pub(crate) struct Model {
    pub ident: Ident,
    pub generics: Generics,
    pub fields: Vec<String>,
}

pub(crate) fn analyze(ast: Ast) -> Model {
    let fields = match ast.fields {
        Fields::Named(FieldsNamed { ref named, .. }) => named
            .iter()
            .filter_map(|f| f.ident.clone().map(|ident| ident.to_string()))
            .collect::<Vec<_>>(),
        _ => vec![],
    };

    Model {
        ident: ast.ident,
        generics: ast.generics,
        fields,
    }
}

#[cfg(test)]
mod tests {
    use syn::parse_quote;

    use super::*;

    #[test]
    fn can_get_fields_from_nonempty_named_struct() {
        let model = analyze(parse_quote!(
            struct NamedStruct {
                first: u64,
                second: String,
                third: Vec<char>,
            }
        ));

        let expected: Vec<_> = ["first", "second", "third"]
            .iter()
            .map(|s| s.to_owned())
            .collect();

        assert_eq!("NamedStruct", model.ident.to_string());
        assert!(model.generics.type_params().next().is_none());
        assert!(model.generics.const_params().next().is_none());
        assert_eq!(expected, model.fields);
    }

    #[test]
    fn can_get_fields_from_generic_named_struct() {
        let model = analyze(parse_quote!(
            struct GenericStruct<'a, T, E, S, const N: usize> {
                value: T + 'a,
                error: E,
                size: S,
            }
        ));

        let expected: Vec<_> = ["value", "error", "size"]
            .iter()
            .map(|s| s.to_owned())
            .collect();

        assert_eq!("GenericStruct", model.ident.to_string());
        assert_eq!(model.generics.type_params().count(), 3);
        assert_eq!(model.generics.const_params().count(), 1);
        assert_eq!(expected, model.fields);
    }

    #[test]
    fn can_get_fields_from_empty_named_struct() {
        let model = analyze(parse_quote!(
            struct EmptyNamedStruct {}
        ));

        assert_eq!("EmptyNamedStruct", model.ident.to_string());
        assert!(model.generics.type_params().next().is_none());
        assert!(model.generics.const_params().next().is_none());
        assert!(model.fields.is_empty());
    }

    #[test]
    fn can_get_fields_from_empty_unnamed_struct() {
        let model = analyze(parse_quote!(
            struct UnnamedStruct();
        ));

        assert_eq!("UnnamedStruct", model.ident.to_string());
        assert!(model.generics.type_params().next().is_none());
        assert!(model.generics.const_params().next().is_none());
        assert!(model.fields.is_empty());
    }

    #[test]
    fn can_get_fields_from_unit_struct() {
        let model = analyze(parse_quote!(
            struct UnitStruct;
        ));

        assert_eq!("UnitStruct", model.ident.to_string());
        assert!(model.generics.type_params().next().is_none());
        assert!(model.generics.const_params().next().is_none());
        assert!(model.fields.is_empty());
    }
}