Skip to content

Commit

Permalink
feat: TryFrom impl for enums (gen into original)
Browse files Browse the repository at this point in the history
fix: base field not merging correctly with generated model's fields
  • Loading branch information
Nex-Coder committed Mar 21, 2024
1 parent 8d633c4 commit 5ed0dae
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 17 deletions.
13 changes: 5 additions & 8 deletions src/logic/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,6 @@ impl FieldsArg {
let field_arg = take_ident_group("fields", args);
let omit_args = take_ident_group("omit", args);

if field_arg.is_some() && omit_args.is_some() {
abort!(
attr_spanned,
"Cannot have both `fields` and `omit` arguments"
)
}

// Parse the fields argument into a TokenStream, skip checking for commas coz lazy
match (field_arg, omit_args) {
(Some(g), None) => Self::Fields(extract_idents(g)),
Expand Down Expand Up @@ -236,7 +229,11 @@ impl FieldsArg {
let base_fields = model_args.base.as_ref().and_then(|v| v.fields.clone());
if let Some(base) = base_fields {
let final_fields: Vec<_> = match (fields, base) {
(Fields(f), Fields(b)) => f.into_iter().filter(|v| b.contains(v)).collect(),
(Fields(f), Fields(ref b)) => f
.into_iter()
.filter(|v| !b.contains(v))
.chain(b.clone().into_iter())
.collect(),
(Fields(f), Omit(b)) => f.into_iter().filter(|v| !b.contains(v)).collect(),
(Omit(f), Fields(b)) => b.into_iter().filter(|v| !f.contains(v)).collect(),
(Omit(f), Omit(mut b)) => {
Expand Down
43 changes: 34 additions & 9 deletions src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ pub fn impl_view_model(
let original_name = &ast.ident;
let is_struct = matches!(&ast.data, syn::Data::Struct(_));
let mut field_mapping: Vec<TokenStream> = vec![]; // Will contain each fields `From` trait impl
let mut field_mapping_reverse: Vec<TokenStream> = vec![];

// Generate Implementation
let field_tokens: Vec<_> = match &ast.data {
syn::Data::Struct(data) => impl_for_struct(data, &mut field_mapping, &args),
syn::Data::Enum(data) => impl_for_enum(data, &mut field_mapping, &args, original_name),
syn::Data::Struct(data) => impl_for_struct(data, &mut field_mapping, &mut field_mapping_reverse, &args),
syn::Data::Enum(data) => impl_for_enum(data, &mut field_mapping, &mut field_mapping_reverse, &args, original_name),
syn::Data::Union(_) => abort!(attr, "Patch Model can only be derived for `struct` & `enum`, NOT `union`"),
};

Expand All @@ -41,7 +42,7 @@ pub fn impl_view_model(
let attributes = attributes_with.gen_top_attributes(ast);
let derives = gen_derive(derive.as_ref());

let impl_from = impl_from_trait(original_name, &name, field_mapping, is_struct);
let impl_from = impl_from_trait(original_name, &name, field_mapping, field_mapping_reverse, is_struct);

let doc_string = format!("This is a restructured (View) model of ['{original_name}']. Refer to the original model for more structual documentation.");
quote! {
Expand All @@ -59,15 +60,16 @@ pub fn impl_view_model(
fn impl_from_trait(
original_name: &Ident,
name: &Ident,
field_from_mapping: Vec<TokenStream>,
field_mapping: Vec<TokenStream>,
field_mapping_reverse: Vec<TokenStream>,
is_struct: bool,
) -> proc_macro2::TokenStream {
if is_struct {
quote! {
impl ::core::convert::From<#original_name> for #name {
fn from(value: #original_name) -> Self {
Self {
#(#field_from_mapping),*
#(#field_mapping),*
}
}
}
Expand All @@ -77,16 +79,27 @@ fn impl_from_trait(
impl ::core::convert::From<#name> for #original_name {
fn from(value: #name) -> Self {
match value {
#(#field_from_mapping),*
#(#field_mapping),*
}
}
}

impl ::core::convert::TryFrom<#original_name> for #name {
type Error = ();

fn try_from(value: #original_name) -> Result<Self, Self::Error> {
Ok(match value {
#(#field_mapping_reverse, )*
_ => return Err(())
})
}
}
}
}
}


fn impl_for_struct(data: &DataStruct, field_mapping: &mut Vec<TokenStream>, args: &AttrArgs) -> Vec<TokenStream> {
fn impl_for_struct(data: &DataStruct, field_mapping: &mut Vec<TokenStream>, field_mapping_reverse: &mut Vec<TokenStream>, args: &AttrArgs) -> Vec<TokenStream> {
let AttrArgs {
name: _,
fields,
Expand All @@ -110,7 +123,10 @@ fn impl_for_struct(data: &DataStruct, field_mapping: &mut Vec<TokenStream>, args

let field_attr = attributes_with.gen_field_attributes(field.attrs.clone());

field_mapping.push(quote!(#field_name: value.#field_name));
let mapping = quote!(#field_name: value.#field_name);
field_mapping.push(mapping.clone());
field_mapping_reverse.push(mapping);

quote! {
#docs
#(#field_attr)*
Expand All @@ -120,7 +136,7 @@ fn impl_for_struct(data: &DataStruct, field_mapping: &mut Vec<TokenStream>, args
.collect()
}

fn impl_for_enum(data: &DataEnum, field_mapping: &mut Vec<TokenStream>, args: &AttrArgs, original_name: &Ident) -> Vec<TokenStream> {
fn impl_for_enum(data: &DataEnum, field_mapping: &mut Vec<TokenStream>, field_mapping_reverse: &mut Vec<TokenStream>, args: &AttrArgs, original_name: &Ident) -> Vec<TokenStream> {
let AttrArgs {
name,
fields,
Expand All @@ -144,6 +160,9 @@ fn impl_for_enum(data: &DataEnum, field_mapping: &mut Vec<TokenStream>, args: &A
field_mapping.push(quote!{
#name::#field_name => #original_name::#field_name
});
field_mapping_reverse.push(quote!{
#original_name::#field_name => #name::#field_name
});
},
syn::Fields::Unnamed(_) => {
let variant_args: Vec<_> = field
Expand All @@ -161,6 +180,9 @@ fn impl_for_enum(data: &DataEnum, field_mapping: &mut Vec<TokenStream>, args: &A
field_mapping.push(quote!{
#name::#field_name(#(#variant_args),*) => #original_name::#field_name(#(#variant_args),*)
});
field_mapping_reverse.push(quote!{
#original_name::#field_name(#(#variant_args),*) => #name::#field_name(#(#variant_args),*)
});
}
syn::Fields::Named(n) => {
let variant_args: Vec<_> = n
Expand All @@ -176,6 +198,9 @@ fn impl_for_enum(data: &DataEnum, field_mapping: &mut Vec<TokenStream>, args: &A
field_mapping.push(quote!{
#name::#field_name{#(#variant_args),*} => #original_name::#field_name{#(#variant_args),*}
});
field_mapping_reverse.push(quote!{
#original_name::#field_name(#(#variant_args),*) => #name::#field_name(#(#variant_args),*)
});
},
};

Expand Down

0 comments on commit 5ed0dae

Please sign in to comment.