Skip to content

Commit 0e80a85

Browse files
committed
move the validation to separate function
1 parent 88e313e commit 0e80a85

1 file changed

Lines changed: 41 additions & 33 deletions

File tree

derive-macros/src/lib.rs

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -119,39 +119,8 @@ fn gen_schema_fields(data: &Data) -> TokenStream {
119119
}
120120
});
121121
if have_schema_null {
122-
// Check if the type is HashMap or Option<HashMap>
123-
let last_segment = type_path.path.segments.last();
124-
let is_valid = if let Some(seg) = last_segment {
125-
let last_ident = &seg.ident;
126-
if last_ident == "HashMap" {
127-
true
128-
} else if last_ident == "Option" {
129-
// Check if Option wraps HashMap
130-
if let PathArguments::AngleBracketed(args) = &seg.arguments {
131-
args.args.iter().any(|arg| {
132-
if let syn::GenericArgument::Type(Type::Path(inner_path)) = arg {
133-
inner_path.path.segments.last().map(|s| &s.ident) == Some(&syn::Ident::new("HashMap", Span::call_site()))
134-
} else {
135-
false
136-
}
137-
})
138-
} else {
139-
false
140-
}
141-
} else {
142-
false
143-
}
144-
} else {
145-
false
146-
};
147-
148-
if !is_valid {
149-
if let Some(last_ident) = last_segment.map(|seg| &seg.ident) {
150-
return Error::new(
151-
last_ident.span(),
152-
format!("Can only use allow_null_container_values on HashMap fields, not {last_ident}")
153-
).to_compile_error()
154-
}
122+
if let Err(err) = validate_null_container_values(type_path) {
123+
return err.to_compile_error();
155124
}
156125
quote_spanned! { field.span() => #(#type_path_quoted)* get_nullable_container_struct_field(stringify!(#name))}
157126
} else {
@@ -280,3 +249,42 @@ fn make_public(mut item: Item) -> Item {
280249

281250
item
282251
}
252+
253+
/// We allow only `HashMap` and `Option<HashMap>` to have `allow_null_container_values` set.
254+
fn validate_null_container_values(type_path: &syn::TypePath) -> Result<(), syn::Error> {
255+
let last = type_path.path.segments.last();
256+
match last.map(|seg| seg.ident.to_string()).as_deref() {
257+
Some("HashMap") => Ok(()),
258+
Some("Option") => {
259+
if let Some(syn::PathArguments::AngleBracketed(args)) = last.map(|s| &s.arguments) {
260+
if let Some(syn::GenericArgument::Type(syn::Type::Path(inner))) = args.args.first()
261+
{
262+
let inner_ident = inner
263+
.path
264+
.segments
265+
.last()
266+
.map(|s| s.ident.to_string())
267+
.unwrap_or_else(|| "Unknown".to_string());
268+
if inner_ident == "HashMap" {
269+
return Ok(());
270+
}
271+
return Err(syn::Error::new(
272+
args.span(),
273+
format!(
274+
"Can only use allow_null_container_values on Option<HashMap> fields, not Option<{}>",
275+
inner_ident,
276+
),
277+
));
278+
}
279+
}
280+
Err(syn::Error::new(
281+
type_path.span(),
282+
"Can only use allow_null_container_values on Option<HashMap> fields",
283+
))
284+
}
285+
_ => Err(syn::Error::new(
286+
type_path.span(),
287+
"Can only use allow_null_container_values on HashMap fields or Option<HashMap> fields",
288+
)),
289+
}
290+
}

0 commit comments

Comments
 (0)