Skip to content

Commit

Permalink
feat: more arguments for patch and view
Browse files Browse the repository at this point in the history
wip: clone view
  • Loading branch information
NexRX committed Feb 9, 2024
1 parent eb4613f commit c359d83
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 1 deletion.
105 changes: 105 additions & 0 deletions src/clone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::*;
use proc_macro2::{Ident, TokenStream, TokenTree};
use quote::quote;
use syn::{self, Attribute, DeriveInput};

struct CloneModelArgs {
name: Ident,
derives: Vec<Ident>,
}

pub fn impl_clone_model(ast: &DeriveInput, attr: &Attribute) -> TokenStream {
let CloneModelArgs { name, derives } = parse_clone_attributes(attr);

let attrs: Vec<_> = ast
.attrs
.iter()
.filter(|v| is_attribute(v, "view"))
.filter(|v| is_attribute(v, "patch"))
.filter(|v| is_attribute(v, "clone"))
.collect();
let vis = &ast.vis;
#[allow(unused_assignments)]
let mut data_type = TokenStream::default();
let data = match &ast.data {
syn::Data::Struct(v) => {
data_type = quote!(struct);
let fields = &v.fields;
quote!(#fields)
}
syn::Data::Enum(v) => {
data_type = quote!(enum);
let fields = &v.variants;
quote!(#fields)
}
syn::Data::Union(v) => {
data_type = quote!(v.union_token.clone());
let fields = &v.fields;
quote!(#fields)
}
};

quote! {
#[derive(#(#derives),*)]
#( #attrs )*
#vis #data_type #name
#data
}
}

// TODO: Impl this for struct, union, and enum
fn impl_from_trait(
original_name: &Ident,
name: &Ident,
field_from_mapping: 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),*
}
}
}
}
} else {
quote! {
impl ::core::convert::From<#name> for #original_name {
fn from(value: #name) -> Self {
match value {
#(#field_from_mapping),*
}
}
}
}
}
}

fn parse_clone_attributes(attr: &Attribute) -> CloneModelArgs {
let tks: Vec<TokenTree> = attr
.meta
.require_list()
.unwrap()
.to_owned()
.tokens
.into_iter()
.collect::<Vec<_>>();

let name = match &tks[0] {
TokenTree::Ident(v) => v.clone(),
x => {
abort!(
x,
"First argument must be an identifier (name) of the struct for the clone"
)
}
};

let mut args_slice = tks[2..].to_vec();
let derives = parse_derives(&mut args_slice);
abort_unexpected_args(vec!["derive"], &args_slice);

CloneModelArgs { name, derives }
}
11 changes: 10 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

mod patch;
mod view;
mod clone;

use proc_macro::TokenStream;
use proc_macro2::{Group, Ident, TokenTree};
Expand Down Expand Up @@ -74,7 +75,7 @@ use syn::Attribute;
///
/// For more information, read the crate level documentation.
#[proc_macro_error]
#[proc_macro_derive(Models, attributes(view, patch))]
#[proc_macro_derive(Models, attributes(view, patch, clone))]
pub fn models(input: TokenStream) -> TokenStream {
let ast = syn::parse_macro_input!(input as syn::DeriveInput);

Expand All @@ -94,9 +95,17 @@ pub fn models(input: TokenStream) -> TokenStream {
.map(|a| patch::impl_patch_model(&ast, a, &oai_attr))
.collect();

// let clones: Vec<proc_macro2::TokenStream> = ast
// .attrs
// .iter()
// .filter(|v| is_attribute(v, "clone"))
// .map(|a| clone::impl_clone_model(&ast, a))
// .collect();

let gen = quote::quote!(
#(#views)*
#(#patches)*
// #(#clones)*
);

gen.into()
Expand Down
12 changes: 12 additions & 0 deletions tests/clone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use restructed::Models;

#[derive(Models)]
#[clone(UserClone, derive(Clone))]
struct User {
/// This should be omitted
id: i32,
/// This shouldn't be omitted
display_name: String,
bio: String,
password: String,
}

0 comments on commit c359d83

Please sign in to comment.