@@ -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