Skip to content

Commit f7759e4

Browse files
committed
define empty value for native type
1 parent 9ba53ef commit f7759e4

File tree

2 files changed

+92
-7
lines changed

2 files changed

+92
-7
lines changed

struct-patch-derive/src/filler.rs

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use proc_macro2::{Ident, Span, TokenStream};
22
use quote::{quote, ToTokens};
33
use std::str::FromStr;
4-
use syn::{parenthesized, DeriveInput, LitStr, Result, Type};
4+
use syn::meta::ParseNestedMeta;
5+
use syn::spanned::Spanned;
6+
use syn::{parenthesized, DeriveInput, Error, Lit, LitStr, Result, Type};
57

68
const FILLER: &str = "filler";
79
const ATTRIBUTE: &str = "attribute";
810
const EXTENDABLE: &str = "extendable";
11+
const EMPTY_VALUE: &str = "empty_value";
912

1013
pub(crate) struct Filler {
1114
visibility: syn::Visibility,
@@ -16,18 +19,27 @@ pub(crate) struct Filler {
1619
fields: Vec<Field>,
1720
}
1821

19-
#[derive(Debug, PartialEq)]
2022
enum FillerType {
2123
Option,
24+
/// The type with `Default`, `Extend`, `IntoIterator` and `is_empty` implementations
2225
Extendable(Ident),
26+
/// The type defined a value for empty
27+
NativeValue(Lit),
2328
}
2429

2530
impl FillerType {
2631
fn inner(&self) -> &Ident {
2732
if let FillerType::Extendable(ident) = self {
2833
ident
2934
} else {
30-
panic!("FillerType::Option has no inner indent")
35+
panic!("Only FillerType::Extendable has inner indent")
36+
}
37+
}
38+
fn value(&self) -> &Lit {
39+
if let FillerType::NativeValue(lit) = self {
40+
lit
41+
} else {
42+
panic!("Only FillerType::NativeValue has value")
3143
}
3244
}
3345
}
@@ -58,7 +70,7 @@ impl Filler {
5870

5971
let option_field_names = fields
6072
.iter()
61-
.filter(|f| f.fty == FillerType::Option)
73+
.filter(|f| matches!(f.fty, FillerType::Option))
6274
.map(|f| f.ident.as_ref())
6375
.collect::<Vec<_>>();
6476

@@ -74,6 +86,18 @@ impl Filler {
7486
.map(|f| f.fty.inner())
7587
.collect::<Vec<_>>();
7688

89+
let native_value_field_names = fields
90+
.iter()
91+
.filter(|f| matches!(f.fty, FillerType::NativeValue(_)))
92+
.map(|f| f.ident.as_ref())
93+
.collect::<Vec<_>>();
94+
95+
let native_value_field_values = fields
96+
.iter()
97+
.filter(|f| matches!(f.fty, FillerType::NativeValue(_)))
98+
.map(|f| f.fty.value())
99+
.collect::<Vec<_>>();
100+
77101
let mapped_attributes = attributes
78102
.iter()
79103
.map(|a| {
@@ -105,6 +129,11 @@ impl Filler {
105129
return false
106130
}
107131
)*
132+
#(
133+
if self.#native_value_field_names != #native_value_field_values {
134+
return false
135+
}
136+
)*
108137
true
109138
}
110139
}
@@ -115,6 +144,11 @@ impl Filler {
115144
let filler_impl = quote! {
116145
impl #generics struct_patch::traits::Filler< #name #generics > for #struct_name #generics #where_clause {
117146
fn apply(&mut self, filler: #name #generics) {
147+
#(
148+
if self.#native_value_field_names == #native_value_field_values {
149+
self.#native_value_field_names = filler.#native_value_field_names;
150+
}
151+
)*
118152
#(
119153
if self.#extendable_field_names.is_empty() {
120154
self.#extendable_field_names.extend(filler.#extendable_field_names.into_iter());
@@ -133,6 +167,7 @@ impl Filler {
133167
#name {
134168
#(#option_field_names: None,)*
135169
#(#extendable_field_names: #extendable_field_types::default(),)*
170+
#(#native_value_field_names: #native_value_field_values,)*
136171
}
137172
}
138173
}
@@ -282,7 +317,24 @@ impl Field {
282317
}
283318
EXTENDABLE => {
284319
// #[filler(extendable)]
285-
fty = Some(FillerType::Extendable(extendable_filler_type(&ty)));
320+
if fty.is_some() {
321+
return Err(meta
322+
.error("The field is already the field of filler, we can't defined more than once"));
323+
}
324+
fty = Some(FillerType::Extendable(none_option_filler_type(&ty)));
325+
}
326+
EMPTY_VALUE => {
327+
// #[filler(empty_value=some value)]
328+
if fty.is_some() {
329+
return Err(meta
330+
.error("The field is already the field of filler, we can't defined more than once"));
331+
}
332+
if let Some(lit) = get_lit(path, &meta)? {
333+
fty = Some(FillerType::NativeValue(lit));
334+
} else {
335+
return Err(meta
336+
.error("empty_value needs a clear value to define empty"));
337+
}
286338
}
287339
_ => {
288340
return Err(meta.error(format_args!(
@@ -342,10 +394,29 @@ fn filler_type(ty: &Type) -> Option<FillerType> {
342394
None
343395
}
344396

345-
fn extendable_filler_type(ty: &Type) -> Ident {
397+
fn none_option_filler_type(ty: &Type) -> Ident {
346398
if let Type::Path(type_path) = ty {
347399
type_path.path.segments[0].ident.clone()
348400
} else {
349401
panic!("#[filler(extendable)] should use on a type")
350402
}
351403
}
404+
405+
fn get_lit(attr_name: String, meta: &ParseNestedMeta) -> syn::Result<Option<syn::Lit>> {
406+
let expr: syn::Expr = meta.value()?.parse()?;
407+
let mut value = &expr;
408+
while let syn::Expr::Group(e) = value {
409+
value = &e.expr;
410+
}
411+
if let syn::Expr::Lit(syn::ExprLit { lit, .. }) = value {
412+
Ok(Some(lit.clone()))
413+
} else {
414+
Err(Error::new(
415+
expr.span(),
416+
format!(
417+
"expected serde {} attribute to be lit: `{} = \"...\"`",
418+
attr_name, attr_name
419+
),
420+
))
421+
}
422+
}

struct-patch/examples/filler.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ impl WrapVec {
3434
#[filler(attribute(derive(Debug, Default)))]
3535
struct Item {
3636
field_complete: bool,
37+
// Will check the field is equal to the value to define the field is empty or not
38+
#[filler(empty_value = 0)]
3739
field_int: usize,
40+
// Will check the field is equal to String::default() to define the field is empty or not
41+
// #[filler(empty=default)]
3842
field_string: String,
3943
maybe_field_int: Option<usize>,
4044
maybe_field_string: Option<String>,
@@ -81,7 +85,7 @@ fn main() {
8185

8286
assert_eq!(
8387
format!("{filler:?}"),
84-
"ItemFiller { maybe_field_int: Some(7), maybe_field_string: None, list: [], _deque: [], _linked_list: [], _set: {}, _bset: {}, _heap: [], _wrap: WrapVec { inner: [] } }"
88+
"ItemFiller { field_int: 0, maybe_field_int: Some(7), maybe_field_string: None, list: [], _deque: [], _linked_list: [], _set: {}, _bset: {}, _heap: [], _wrap: WrapVec { inner: [] } }"
8589
);
8690

8791
item.apply(filler);
@@ -115,4 +119,14 @@ fn main() {
115119
filler.list = vec![3, 4];
116120
item.apply(filler);
117121
assert_eq!(item.list, vec![1, 2]);
122+
123+
let mut filler: ItemFiller = Item::new_empty_filler();
124+
filler.field_int = 7;
125+
item.apply(filler);
126+
assert_eq!(item.field_int, 7);
127+
128+
let mut filler: ItemFiller = Item::new_empty_filler();
129+
filler.field_int = 5;
130+
item.apply(filler);
131+
assert_eq!(item.field_int, 7);
118132
}

0 commit comments

Comments
 (0)