Skip to content

Commit

Permalink
feat: support tuple/unit and generics in omit macro
Browse files Browse the repository at this point in the history
  • Loading branch information
skanehira committed Jan 25, 2024
1 parent d04fc2c commit 0fd6014
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 50 deletions.
58 changes: 29 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use proc_macro::TokenStream;
use quote::{quote, ToTokens as _};
use quote::quote;
use std::collections::HashMap;
use syn::{
bracketed,
parse::{Parse, ParseStream},
parse_macro_input, Ident, ItemStruct, Token,
parse_macro_input,
punctuated::Punctuated,
token, Field, Ident, ItemStruct, Token,
};

#[allow(dead_code)]
Expand Down Expand Up @@ -50,36 +52,34 @@ impl Parse for Omit {
#[proc_macro_attribute]
pub fn omit(attr: TokenStream, item: TokenStream) -> TokenStream {
let attr = parse_macro_input!(attr as Omit);
let struct_name = attr.name;
let mut item = parse_macro_input!(item as ItemStruct);

let item = parse_macro_input!(item as ItemStruct);
item.ident = syn::Ident::new(&attr.name.to_string(), item.ident.span());

let fields: Vec<_> = item
.fields
.into_iter()
.filter_map(|field| {
if let Some(ref ident) = field.ident {
if attr.fields.contains_key(ident) {
return None;
}
};
Some(field)
})
.collect();
let is_tuple = matches!(item.fields, syn::Fields::Unnamed(_));

let vis = item.vis.to_token_stream();
if !is_tuple {
let fields: Punctuated<Field, token::Comma> = item
.fields
.into_iter()
.filter(|field| {
if let Some(ref ident) = field.ident {
if attr.fields.contains_key(ident) {
return false;
}
};
true
})
.collect();

if fields.is_empty() {
quote! {
#vis struct #struct_name;
}
.into()
} else {
quote! {
#vis struct #struct_name {
#(#fields),*
}
}
.into()
item.fields = syn::Fields::Named(syn::FieldsNamed {
brace_token: syn::token::Brace::default(),
named: fields,
});
}

quote! {
#item
}
.into()
}
59 changes: 38 additions & 21 deletions tests/omit.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,72 @@
#![allow(dead_code)]
use types_rs::omit;

#[test]
fn in_progress() {}

#[test]
fn should_pass_omit() {
// omit partial field
{
mod foo {
mod x {
use super::*;
#[omit(NewFoo, [b])]
pub struct Foo {
#[omit(NewS, [b])]
pub struct S {
pub a: i32,
pub b: &str,
}
}
_ = foo::NewFoo { a: 1 };
_ = x::NewS { a: 1 };
}

// omit all fields
{
#[omit(NewFoo2, [a, b])]
struct Foo {
#[omit(NewS, [a, b])]
struct S {
a: i32,
b: &str,
}
_ = NewFoo2;
_ = NewS {};
}

// skip non-existent field
{
#[omit(NewFoo3, [c])]
struct Foo {
#[omit(NewS, [c])]
struct S {
a: i32,
b: &'static str,
}
_ = NewFoo3 { a: 1, b: "2" };
_ = NewS { a: 1, b: "2" };
}

// omit unit struct
// omit tuple struct
{
#[omit(NewPair)]
struct Pair(i32);
_ = NewPair(1);
}

// omit tuple struct that has no fields
{
#[omit(NewFoo4)]
struct Foo;
_ = NewFoo4;
struct Pair();
_ = NewFoo4();
}

// omit unit struct
{
#[omit(NewS)]
struct Unit;
_ = NewS {};
}

// TODO: support generics
// omit generic struct
//{
// #[omit(NewFoo5, [])]
// struct Foo<T> {
// a: T,
// }
// _ = NewFoo5 { a: 1 };
//}
{
#[omit(NewS)]
struct S<'a, T> {
a: &'a T,
}
let x = (1, 2, 3);
_ = NewS { a: &x };
}
}

0 comments on commit 0fd6014

Please sign in to comment.