1use std::collections::BTreeSet;
22
23use proc_macro::TokenStream;
24use proc_macro_crate::FoundCrate;
25use proc_macro_crate::crate_name;
26use proc_macro2::Ident;
27use proc_macro2::Span;
28use proc_macro2::TokenStream as TokenStream2;
29use quote::ToTokens;
30use quote::quote;
31use serde_derive_internals::Ctxt;
32use serde_derive_internals::Derive;
33use serde_derive_internals::ast;
34use serde_derive_internals::attr;
35use serde_derive_internals::name::Name;
36use serde_derive_internals::ungroup;
37use syn::DeriveInput;
38use syn::GenericArgument;
39use syn::LitStr;
40use syn::Member;
41use syn::PathArguments;
42use syn::ReturnType;
43use syn::Type;
44use syn::TypeParamBound;
45use syn::parse_macro_input;
46use syn::parse_quote;
47
48mod shape_attr;
49
50use shape_attr::ShapeAttrs;
51use shape_attr::description;
52
53#[proc_macro_derive(SerializeShape, attributes(serde, serde_shape))]
55pub fn derive_serialize_shape(input: TokenStream) -> TokenStream {
56 let input = parse_macro_input!(input as DeriveInput);
57
58 match expand_serialize_shape(&input) {
59 Ok(tokens) => tokens.into(),
60 Err(err) => err.to_compile_error().into(),
61 }
62}
63
64#[proc_macro_derive(DeserializeShape, attributes(serde, serde_shape))]
66pub fn derive_deserialize_shape(input: TokenStream) -> TokenStream {
67 let input = parse_macro_input!(input as DeriveInput);
68
69 match expand_deserialize_shape(&input) {
70 Ok(tokens) => tokens.into(),
71 Err(err) => err.to_compile_error().into(),
72 }
73}
74
75fn expand_serialize_shape(input: &DeriveInput) -> syn::Result<TokenStream2> {
76 let serde_shape = serde_shape_crate()?;
77 let container = parse_container(input, Derive::Serialize)?;
78 let shape_attrs = ShapeAttrs::parse(&input.attrs)?;
79 validate_shape_attrs(&container)?;
80 let ident = &input.ident;
81 let mut generics = input.generics.clone();
82 add_serialize_shape_bounds(&mut generics, &container, &shape_attrs)?;
83 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
84 let body = serialize_shape_body(&container, &shape_attrs)?;
85
86 Ok(quote! {
87 const _: () = {
88 use #serde_shape as __serde_shape;
89
90 impl #impl_generics __serde_shape::SerializeShape for #ident #ty_generics #where_clause {
91 fn serialize_shape_in(
92 context: &mut __serde_shape::SerializeShapeContext,
93 ) -> __serde_shape::ShapeRef {
94 #body
95 }
96 }
97 };
98 })
99}
100
101fn expand_deserialize_shape(input: &DeriveInput) -> syn::Result<TokenStream2> {
102 let serde_shape = serde_shape_crate()?;
103 let container = parse_container(input, Derive::Deserialize)?;
104 let shape_attrs = ShapeAttrs::parse(&input.attrs)?;
105 validate_shape_attrs(&container)?;
106 let ident = &input.ident;
107 let mut generics = input.generics.clone();
108 add_deserialize_shape_bounds(&mut generics, &container, &shape_attrs)?;
109 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
110 let body = deserialize_shape_body(&container, &shape_attrs)?;
111
112 Ok(quote! {
113 const _: () = {
114 use #serde_shape as __serde_shape;
115
116 impl #impl_generics __serde_shape::DeserializeShape for #ident #ty_generics #where_clause {
117 fn deserialize_shape_in(
118 context: &mut __serde_shape::DeserializeShapeContext,
119 ) -> __serde_shape::ShapeRef {
120 #body
121 }
122 }
123 };
124 })
125}
126
127fn serde_shape_crate() -> syn::Result<TokenStream2> {
128 match crate_name("serde-shape") {
129 Ok(FoundCrate::Itself) => Ok(quote!(::serde_shape)),
130 Ok(FoundCrate::Name(name)) => {
131 let ident = Ident::new(&name.replace('-', "_"), Span::call_site());
132 Ok(quote!(::#ident))
133 }
134 Err(err) => Err(syn::Error::new(
135 Span::call_site(),
136 format!("serde-shape derive could not resolve the serde-shape crate: {err}"),
137 )),
138 }
139}
140
141fn parse_container<'a>(input: &'a DeriveInput, derive: Derive) -> syn::Result<ast::Container<'a>> {
142 let cx = Ctxt::new();
143 let private = Ident::new("__private", Span::call_site());
144 let Some(container) = ast::Container::from_ast(&cx, input, derive, &private) else {
145 cx.check()?;
146 return Err(syn::Error::new_spanned(
147 input,
148 "serde-shape could not parse this item",
149 ));
150 };
151 cx.check()?;
152
153 if matches!(derive, Derive::Serialize) {
154 let message = match container.attrs.identifier() {
155 attr::Identifier::No => None,
156 attr::Identifier::Field => Some("field identifiers cannot be serialized"),
157 attr::Identifier::Variant => Some("variant identifiers cannot be serialized"),
158 };
159 if let Some(message) = message {
160 return Err(syn::Error::new_spanned(input, message));
161 }
162 }
163
164 Ok(container)
165}
166
167fn validate_shape_attrs(container: &ast::Container<'_>) -> syn::Result<()> {
168 match &container.data {
169 ast::Data::Enum(variants) => {
170 for variant in variants {
171 validate_variant_shape_attrs(variant)?;
172 for field in &variant.fields {
173 validate_field_shape_attrs(field)?;
174 }
175 }
176 }
177 ast::Data::Struct(_, fields) => {
178 for field in fields {
179 validate_field_shape_attrs(field)?;
180 }
181 }
182 }
183 Ok(())
184}
185
186fn validate_variant_shape_attrs(variant: &ast::Variant<'_>) -> syn::Result<()> {
187 let attrs = ShapeAttrs::parse(&variant.original.attrs)?;
188 if attrs.has_bound() {
189 return Err(syn::Error::new_spanned(
190 variant.original,
191 "serde_shape bounds are supported on containers, not variants",
192 ));
193 }
194 Ok(())
195}
196
197fn validate_field_shape_attrs(field: &ast::Field<'_>) -> syn::Result<()> {
198 let attrs = ShapeAttrs::parse(&field.original.attrs)?;
199 if attrs.has_bound() {
200 return Err(syn::Error::new_spanned(
201 field.original,
202 "serde_shape bounds are supported on containers, not fields",
203 ));
204 }
205 Ok(())
206}
207
208fn add_serialize_shape_bounds(
209 generics: &mut syn::Generics,
210 container: &ast::Container<'_>,
211 shape_attrs: &ShapeAttrs,
212) -> syn::Result<()> {
213 if let Some(predicates) = shape_attrs.serialize_bound() {
214 generics
215 .make_where_clause()
216 .predicates
217 .extend(predicates.iter().cloned());
218 return Ok(());
219 }
220 let type_params: BTreeSet<_> = generics
221 .type_params()
222 .map(|param| param.ident.to_string())
223 .collect();
224 if shape_attrs.serialize_with().is_some() {
225 return Ok(());
226 }
227 if let Some(ty) = container.attrs.type_into() {
228 if type_uses_params(ty, &type_params) {
229 generics
230 .make_where_clause()
231 .predicates
232 .push(parse_quote!(#ty: __serde_shape::SerializeShape));
233 }
234 return Ok(());
235 }
236
237 let mut field_bound_types = Vec::new();
238
239 match &container.data {
240 ast::Data::Struct(_, fields) => {
241 collect_serialize_field_bound_types(fields, &type_params, &mut field_bound_types)?;
242 }
243 ast::Data::Enum(variants) => {
244 for variant in variants {
245 let variant_shape_attrs = ShapeAttrs::parse(&variant.original.attrs)?;
246 if variant.attrs.skip_serializing()
247 || variant.attrs.serialize_with().is_some()
248 || variant_shape_attrs.serialize_with().is_some()
249 {
250 continue;
251 }
252 collect_serialize_field_bound_types(
253 &variant.fields,
254 &type_params,
255 &mut field_bound_types,
256 )?;
257 }
258 }
259 }
260
261 for ty in field_bound_types {
262 generics
263 .make_where_clause()
264 .predicates
265 .push(parse_quote!(#ty: __serde_shape::SerializeShape));
266 }
267 Ok(())
268}
269
270fn add_deserialize_shape_bounds(
271 generics: &mut syn::Generics,
272 container: &ast::Container<'_>,
273 shape_attrs: &ShapeAttrs,
274) -> syn::Result<()> {
275 if let Some(predicates) = shape_attrs.deserialize_bound() {
276 generics
277 .make_where_clause()
278 .predicates
279 .extend(predicates.iter().cloned());
280 return Ok(());
281 }
282 let type_params: BTreeSet<_> = generics
283 .type_params()
284 .map(|param| param.ident.to_string())
285 .collect();
286 if shape_attrs.deserialize_with().is_some() {
287 return Ok(());
288 }
289 if let Some(ty) = container
290 .attrs
291 .type_from()
292 .or_else(|| container.attrs.type_try_from())
293 {
294 if type_uses_params(ty, &type_params) {
295 generics
296 .make_where_clause()
297 .predicates
298 .push(parse_quote!(#ty: __serde_shape::DeserializeShape));
299 }
300 return Ok(());
301 }
302
303 let mut field_bound_types = Vec::new();
304
305 match &container.data {
306 ast::Data::Struct(_, fields) => {
307 collect_deserialize_field_bound_types(fields, &type_params, &mut field_bound_types)?;
308 }
309 ast::Data::Enum(variants) => {
310 for variant in variants {
311 let variant_shape_attrs = ShapeAttrs::parse(&variant.original.attrs)?;
312 if variant.attrs.skip_deserializing()
313 || variant.attrs.deserialize_with().is_some()
314 || variant_shape_attrs.deserialize_with().is_some()
315 {
316 continue;
317 }
318 collect_deserialize_field_bound_types(
319 &variant.fields,
320 &type_params,
321 &mut field_bound_types,
322 )?;
323 }
324 }
325 }
326
327 for ty in field_bound_types {
328 generics
329 .make_where_clause()
330 .predicates
331 .push(parse_quote!(#ty: __serde_shape::DeserializeShape));
332 }
333 Ok(())
334}
335
336fn collect_serialize_field_bound_types(
337 fields: &[ast::Field<'_>],
338 type_params: &BTreeSet<String>,
339 field_bound_types: &mut Vec<Type>,
340) -> syn::Result<()> {
341 for field in fields {
342 let shape_attrs = ShapeAttrs::parse(&field.original.attrs)?;
343 if field.attrs.skip_serializing() {
344 continue;
345 }
346 if shape_attrs.serialize_with().is_none() && field.attrs.serialize_with().is_none() {
347 collect_shape_bound_types(field.ty, type_params, field_bound_types);
348 }
349 }
350 Ok(())
351}
352
353fn collect_deserialize_field_bound_types(
354 fields: &[ast::Field<'_>],
355 type_params: &BTreeSet<String>,
356 field_bound_types: &mut Vec<Type>,
357) -> syn::Result<()> {
358 for field in fields {
359 let shape_attrs = ShapeAttrs::parse(&field.original.attrs)?;
360 if field.attrs.skip_deserializing() {
361 continue;
362 }
363 if shape_attrs.deserialize_with().is_none() && field.attrs.deserialize_with().is_none() {
364 collect_shape_bound_types(field.ty, type_params, field_bound_types);
365 }
366 }
367 Ok(())
368}
369
370fn collect_shape_bound_types(
371 ty: &Type,
372 type_params: &BTreeSet<String>,
373 field_bound_types: &mut Vec<Type>,
374) {
375 match ty {
379 Type::Array(ty) => {
380 if !is_zero_length(&ty.len) {
381 collect_shape_bound_types(&ty.elem, type_params, field_bound_types);
382 }
383 }
384 Type::FnPtr(ty) => {
385 for input in &ty.inputs {
386 collect_shape_bound_types(&input.ty, type_params, field_bound_types);
387 }
388 collect_return_type_params(&ty.output, type_params, field_bound_types);
389 }
390 Type::Group(ty) => collect_shape_bound_types(&ty.elem, type_params, field_bound_types),
391 Type::ImplTrait(ty) => {
392 collect_type_param_bounds(&ty.bounds, type_params, field_bound_types);
393 }
394 Type::Paren(ty) => collect_shape_bound_types(&ty.elem, type_params, field_bound_types),
395 Type::Path(ty) => {
396 if ty
397 .path
398 .segments
399 .last()
400 .is_some_and(|segment| segment.ident == "PhantomData")
401 {
402 return;
403 }
404
405 let is_associated_type = ty.qself.as_ref().is_some_and(|qself| {
406 let mut qself_bounds = Vec::new();
407 collect_shape_bound_types(&qself.ty, type_params, &mut qself_bounds);
408 !qself_bounds.is_empty()
409 }) || (ty.path.leading_colon.is_none()
410 && ty.path.segments.len() > 1
411 && ty
412 .path
413 .segments
414 .first()
415 .is_some_and(|segment| type_params.contains(&segment.ident.to_string())));
416
417 if is_associated_type {
418 push_bound_type(field_bound_types, Type::Path(ty.clone()));
419 return;
420 }
421
422 if ty.qself.is_none()
423 && ty.path.leading_colon.is_none()
424 && ty.path.segments.len() == 1
425 && ty
426 .path
427 .segments
428 .first()
429 .is_some_and(|segment| type_params.contains(&segment.ident.to_string()))
430 {
431 push_bound_type(field_bound_types, Type::Path(ty.clone()));
432 return;
433 }
434
435 if let Some(qself) = &ty.qself {
436 collect_shape_bound_types(&qself.ty, type_params, field_bound_types);
437 }
438
439 for segment in &ty.path.segments {
440 collect_path_arguments(&segment.arguments, type_params, field_bound_types);
441 }
442 }
443 Type::Ptr(ty) => collect_shape_bound_types(&ty.elem, type_params, field_bound_types),
444 Type::Reference(ty) => collect_shape_bound_types(&ty.elem, type_params, field_bound_types),
445 Type::Slice(ty) => collect_shape_bound_types(&ty.elem, type_params, field_bound_types),
446 Type::TraitObject(ty) => {
447 collect_type_param_bounds(&ty.bounds, type_params, field_bound_types);
448 }
449 Type::Tuple(ty) => {
450 for elem in &ty.elems {
451 collect_shape_bound_types(elem, type_params, field_bound_types);
452 }
453 }
454 Type::Infer(_) | Type::Macro(_) | Type::Never(_) | Type::Verbatim(_) => {}
455 _ => {}
456 }
457}
458
459fn is_zero_length(expr: &syn::Expr) -> bool {
460 match expr {
461 syn::Expr::Group(expr) => is_zero_length(&expr.expr),
462 syn::Expr::Lit(expr) => {
463 matches!(&expr.lit, syn::Lit::Int(value) if value
464 .base10_parse::<usize>()
465 .is_ok_and(|value| value == 0))
466 }
467 syn::Expr::Paren(expr) => is_zero_length(&expr.expr),
468 _ => false,
469 }
470}
471
472fn type_uses_params(ty: &Type, type_params: &BTreeSet<String>) -> bool {
473 let mut bound_types = Vec::new();
474 collect_shape_bound_types(ty, type_params, &mut bound_types);
475 !bound_types.is_empty()
476}
477
478fn collect_path_arguments(
479 arguments: &PathArguments,
480 type_params: &BTreeSet<String>,
481 field_bound_types: &mut Vec<Type>,
482) {
483 match arguments {
484 PathArguments::None => {}
485 PathArguments::AngleBracketed(arguments) => {
486 for argument in &arguments.args {
487 match argument {
488 GenericArgument::Type(ty) => {
489 collect_shape_bound_types(ty, type_params, field_bound_types);
490 }
491 GenericArgument::AssocType(assoc) => {
492 collect_shape_bound_types(&assoc.ty, type_params, field_bound_types);
493 }
494 GenericArgument::Constraint(constraint) => {
495 collect_type_param_bounds(
496 &constraint.bounds,
497 type_params,
498 field_bound_types,
499 );
500 }
501 GenericArgument::Lifetime(_)
502 | GenericArgument::Const(_)
503 | GenericArgument::AssocConst(_) => {}
504 _ => {}
505 }
506 }
507 }
508 PathArguments::Parenthesized(arguments) => {
509 for input in &arguments.inputs {
510 collect_shape_bound_types(&input.ty, type_params, field_bound_types);
511 }
512 collect_return_type_params(&arguments.output, type_params, field_bound_types);
513 }
514 }
515}
516
517fn collect_type_param_bounds(
518 bounds: &syn::punctuated::Punctuated<TypeParamBound, syn::Token![+]>,
519 type_params: &BTreeSet<String>,
520 field_bound_types: &mut Vec<Type>,
521) {
522 for bound in bounds {
523 if let TypeParamBound::Trait(bound) = bound {
524 for segment in &bound.path.segments {
525 collect_path_arguments(&segment.arguments, type_params, field_bound_types);
526 }
527 }
528 }
529}
530
531fn collect_return_type_params(
532 return_type: &ReturnType,
533 type_params: &BTreeSet<String>,
534 field_bound_types: &mut Vec<Type>,
535) {
536 if let ReturnType::Type(_, ty) = return_type {
537 collect_shape_bound_types(ty, type_params, field_bound_types);
538 }
539}
540
541fn push_bound_type(field_bound_types: &mut Vec<Type>, ty: Type) {
542 let tokens = ty.to_token_stream().to_string();
543 if field_bound_types
544 .iter()
545 .all(|existing| existing.to_token_stream().to_string() != tokens)
546 {
547 field_bound_types.push(ty);
548 }
549}
550
551fn serialize_shape_body(
552 container: &ast::Container<'_>,
553 shape_attrs: &ShapeAttrs,
554) -> syn::Result<TokenStream2> {
555 if let Some(function) = shape_attrs.serialize_with() {
556 return Ok(quote!(#function(context)));
557 }
558 if let Some(ty) = container.attrs.type_into() {
559 return Ok(quote!(<#ty as __serde_shape::SerializeShape>::serialize_shape_in(context)));
560 }
561
562 let name = lit_name(container.attrs.name().serialize_name());
563 let description = description(&container.original.attrs);
564 let description = option_lit(description.as_deref());
565 let kind = serialize_definition_kind(container)?;
566
567 Ok(quote! {
568 context.define_named_type_with_description(
569 __serde_shape::TypeName::of::<Self>(#name),
570 #description,
571 |context| {
572 #kind
573 },
574 )
575 })
576}
577
578fn deserialize_shape_body(
579 container: &ast::Container<'_>,
580 shape_attrs: &ShapeAttrs,
581) -> syn::Result<TokenStream2> {
582 if let Some(function) = shape_attrs.deserialize_with() {
583 return Ok(quote!(#function(context)));
584 }
585 if let Some(ty) = container
586 .attrs
587 .type_from()
588 .or_else(|| container.attrs.type_try_from())
589 {
590 return Ok(quote!(<#ty as __serde_shape::DeserializeShape>::deserialize_shape_in(context)));
591 }
592
593 let name = lit_name(container.attrs.name().deserialize_name());
594 let description = description(&container.original.attrs);
595 let description = option_lit(description.as_deref());
596 let kind = deserialize_definition_kind(container)?;
597
598 Ok(quote! {
599 context.define_named_type_with_description(
600 __serde_shape::TypeName::of::<Self>(#name),
601 #description,
602 |context| {
603 #kind
604 },
605 )
606 })
607}
608
609fn serialize_definition_kind(container: &ast::Container<'_>) -> syn::Result<TokenStream2> {
610 let attributes = serialize_container_attributes(&container.attrs);
611 Ok(match &container.data {
612 ast::Data::Struct(style, fields) => {
613 let style = fields_style(*style);
614 let fields = fields
615 .iter()
616 .map(serialize_field_shape)
617 .collect::<syn::Result<Vec<_>>>()?;
618 quote! {
619 __serde_shape::SerializeDefinitionKind::Struct(__serde_shape::SerializeStructShape {
620 style: #style,
621 fields: __serde_shape::__private::vec![#(#fields),*],
622 attributes: #attributes,
623 })
624 }
625 }
626 ast::Data::Enum(variants) => {
627 let repr = tagging(container.attrs.tag());
628 let variants = variants
629 .iter()
630 .map(serialize_variant_shape)
631 .collect::<syn::Result<Vec<_>>>()?;
632 quote! {
633 __serde_shape::SerializeDefinitionKind::Enum(__serde_shape::SerializeEnumShape {
634 repr: #repr,
635 variants: __serde_shape::__private::vec![#(#variants),*],
636 attributes: #attributes,
637 })
638 }
639 }
640 })
641}
642
643fn deserialize_definition_kind(container: &ast::Container<'_>) -> syn::Result<TokenStream2> {
644 let attributes = deserialize_container_attributes(&container.attrs);
645 Ok(match &container.data {
646 ast::Data::Struct(style, fields) => {
647 let style = fields_style(*style);
648 let fields = fields
649 .iter()
650 .map(deserialize_field_shape)
651 .collect::<syn::Result<Vec<_>>>()?;
652 quote! {
653 __serde_shape::DeserializeDefinitionKind::Struct(__serde_shape::DeserializeStructShape {
654 style: #style,
655 fields: __serde_shape::__private::vec![#(#fields),*],
656 attributes: #attributes,
657 })
658 }
659 }
660 ast::Data::Enum(variants) => {
661 let repr = deserialize_tagging(&container.attrs);
662 let variants = variants
663 .iter()
664 .map(deserialize_variant_shape)
665 .collect::<syn::Result<Vec<_>>>()?;
666 quote! {
667 __serde_shape::DeserializeDefinitionKind::Enum(__serde_shape::DeserializeEnumShape {
668 repr: #repr,
669 variants: __serde_shape::__private::vec![#(#variants),*],
670 attributes: #attributes,
671 })
672 }
673 }
674 })
675}
676
677fn serialize_container_attributes(attrs: &attr::Container) -> TokenStream2 {
678 let non_exhaustive = attrs.non_exhaustive();
679
680 quote! {
681 __serde_shape::SerializeContainerAttributes {
682 non_exhaustive: #non_exhaustive,
683 }
684 }
685}
686
687fn deserialize_container_attributes(attrs: &attr::Container) -> TokenStream2 {
688 let deny_unknown_fields = attrs.deny_unknown_fields();
689 let default = default_shape(attrs.default());
690 let expecting = option_lit(attrs.expecting());
691 let non_exhaustive = attrs.non_exhaustive();
692
693 quote! {
694 __serde_shape::DeserializeContainerAttributes {
695 deny_unknown_fields: #deny_unknown_fields,
696 default: #default,
697 expecting: #expecting,
698 non_exhaustive: #non_exhaustive,
699 }
700 }
701}
702
703fn serialize_variant_shape(variant: &ast::Variant<'_>) -> syn::Result<TokenStream2> {
704 let shape_attrs = ShapeAttrs::parse(&variant.original.attrs)?;
705 let rust_name = lit(variant.ident.to_string());
706 let name = lit_name(variant.attrs.name().serialize_name());
707 let description = description(&variant.original.attrs);
708 let description = option_lit(description.as_deref());
709 let style = fields_style(variant.style);
710 let skip = variant.attrs.skip_serializing();
711 let untagged = variant.attrs.untagged();
712 let content = if skip {
713 quote!(__serde_shape::SerializeVariantContent::Omitted)
714 } else if let Some(function) = shape_attrs.serialize_with() {
715 quote!(__serde_shape::SerializeVariantContent::Shape(#function(context)))
716 } else if let Some(custom_serializer) = variant.attrs.serialize_with() {
717 let detail = option_path(Some(custom_serializer));
718 quote! {
719 __serde_shape::SerializeVariantContent::Custom(__serde_shape::OpaqueShape {
720 type_name: ::core::any::type_name::<Self>(),
721 reason: __serde_shape::OpaqueReason::CustomSerializer,
722 detail: #detail,
723 })
724 }
725 } else {
726 let fields = variant
727 .fields
728 .iter()
729 .map(serialize_field_shape)
730 .collect::<syn::Result<Vec<_>>>()?;
731 quote! {
732 __serde_shape::SerializeVariantContent::Fields(
733 __serde_shape::__private::vec![#(#fields),*],
734 )
735 }
736 };
737
738 Ok(quote! {
739 __serde_shape::SerializeVariantShape {
740 rust_name: #rust_name,
741 name: #name,
742 description: #description,
743 style: #style,
744 content: #content,
745 untagged: #untagged,
746 }
747 })
748}
749
750fn deserialize_variant_shape(variant: &ast::Variant<'_>) -> syn::Result<TokenStream2> {
751 let shape_attrs = ShapeAttrs::parse(&variant.original.attrs)?;
752 let rust_name = lit(variant.ident.to_string());
753 let name = lit_name(variant.attrs.name().deserialize_name());
754 let aliases = aliases(variant.attrs.aliases());
755 let description = description(&variant.original.attrs);
756 let description = option_lit(description.as_deref());
757 let style = fields_style(variant.style);
758 let skip = variant.attrs.skip_deserializing();
759 let other = variant.attrs.other();
760 let untagged = variant.attrs.untagged();
761 let content = if skip {
762 quote!(__serde_shape::DeserializeVariantContent::Omitted)
763 } else if let Some(function) = shape_attrs.deserialize_with() {
764 quote!(__serde_shape::DeserializeVariantContent::Shape(#function(context)))
765 } else if let Some(custom_deserializer) = variant.attrs.deserialize_with() {
766 let detail = option_path(Some(custom_deserializer));
767 quote! {
768 __serde_shape::DeserializeVariantContent::Custom(__serde_shape::OpaqueShape {
769 type_name: ::core::any::type_name::<Self>(),
770 reason: __serde_shape::OpaqueReason::CustomDeserializer,
771 detail: #detail,
772 })
773 }
774 } else {
775 let fields = variant
776 .fields
777 .iter()
778 .map(deserialize_field_shape)
779 .collect::<syn::Result<Vec<_>>>()?;
780 quote! {
781 __serde_shape::DeserializeVariantContent::Fields(
782 __serde_shape::__private::vec![#(#fields),*],
783 )
784 }
785 };
786
787 Ok(quote! {
788 __serde_shape::DeserializeVariantShape {
789 rust_name: #rust_name,
790 name: #name,
791 aliases: #aliases,
792 description: #description,
793 style: #style,
794 content: #content,
795 other: #other,
796 untagged: #untagged,
797 }
798 })
799}
800
801fn serialize_field_shape(field: &ast::Field<'_>) -> syn::Result<TokenStream2> {
802 let shape_attrs = ShapeAttrs::parse(&field.original.attrs)?;
803 let member = field_member(&field.member);
804 let name = lit_name(field.attrs.name().serialize_name());
805 let description = description(&field.original.attrs);
806 let description = option_lit(description.as_deref());
807 let skip = field.attrs.skip_serializing();
808 let skip_if = option_path(field.attrs.skip_serializing_if());
809 let flatten = field.attrs.flatten();
810 let transparent = field.attrs.transparent();
811 let ty = field.ty;
812 let wire_shape = if skip {
813 quote!(__serde_shape::FieldWireShape::Omitted)
814 } else {
815 let value_shape = if let Some(function) = shape_attrs.serialize_with() {
816 quote!(#function(context))
817 } else if let Some(custom_serializer) = field.attrs.serialize_with() {
818 let detail = option_path(Some(custom_serializer));
819 quote! {
820 __serde_shape::ShapeRef::Opaque(__serde_shape::OpaqueShape {
821 type_name: ::core::any::type_name::<#ty>(),
822 reason: __serde_shape::OpaqueReason::CustomSerializer,
823 detail: #detail,
824 })
825 }
826 } else {
827 quote!(<#ty as __serde_shape::SerializeShape>::serialize_shape_in(context))
828 };
829
830 if transparent {
831 quote!(__serde_shape::FieldWireShape::Inline(#value_shape))
832 } else if flatten {
833 quote!(__serde_shape::FieldWireShape::Flatten(#value_shape))
834 } else {
835 quote!(__serde_shape::FieldWireShape::Value(#value_shape))
836 }
837 };
838
839 Ok(quote! {
840 __serde_shape::SerializeFieldShape {
841 member: #member,
842 name: #name,
843 description: #description,
844 wire_shape: #wire_shape,
845 skip_if: #skip_if,
846 }
847 })
848}
849
850fn deserialize_field_shape(field: &ast::Field<'_>) -> syn::Result<TokenStream2> {
851 let shape_attrs = ShapeAttrs::parse(&field.original.attrs)?;
852 let borrowed_cow_shape = borrowed_cow_shape(field)?;
853 let member = field_member(&field.member);
854 let name = lit_name(field.attrs.name().deserialize_name());
855 let aliases = aliases(field.attrs.aliases());
856 let description = description(&field.original.attrs);
857 let description = option_lit(description.as_deref());
858 let skip = field.attrs.skip_deserializing();
859 let default = default_shape(field.attrs.default());
860 let flatten = field.attrs.flatten();
861 let transparent = field.attrs.transparent();
862 let ty = field.ty;
863 let wire_shape = if skip {
864 quote!(__serde_shape::FieldWireShape::Omitted)
865 } else {
866 let value_shape = if let Some(function) = shape_attrs.deserialize_with() {
867 quote!(#function(context))
868 } else if let Some(shape) = borrowed_cow_shape {
869 shape
870 } else if let Some(custom_deserializer) = field.attrs.deserialize_with() {
871 let detail = option_path(Some(custom_deserializer));
872 quote! {
873 __serde_shape::ShapeRef::Opaque(__serde_shape::OpaqueShape {
874 type_name: ::core::any::type_name::<#ty>(),
875 reason: __serde_shape::OpaqueReason::CustomDeserializer,
876 detail: #detail,
877 })
878 }
879 } else {
880 quote!(<#ty as __serde_shape::DeserializeShape>::deserialize_shape_in(context))
881 };
882
883 if transparent {
884 quote!(__serde_shape::FieldWireShape::Inline(#value_shape))
885 } else if flatten {
886 quote!(__serde_shape::FieldWireShape::Flatten(#value_shape))
887 } else {
888 quote!(__serde_shape::FieldWireShape::Value(#value_shape))
889 }
890 };
891
892 Ok(quote! {
893 __serde_shape::DeserializeFieldShape {
894 member: #member,
895 name: #name,
896 aliases: #aliases,
897 description: #description,
898 wire_shape: #wire_shape,
899 default: #default,
900 }
901 })
902}
903
904fn field_member(member: &Member) -> TokenStream2 {
905 match member {
906 Member::Named(ident) => {
907 let ident = lit(ident.to_string());
908 quote!(__serde_shape::FieldMember::Named(#ident))
909 }
910 Member::Unnamed(index) => {
911 let index = index.index as usize;
912 quote!(__serde_shape::FieldMember::Unnamed(#index))
913 }
914 }
915}
916
917fn fields_style(style: ast::Style) -> TokenStream2 {
918 match style {
919 ast::Style::Struct => quote!(__serde_shape::FieldsStyle::Struct),
920 ast::Style::Tuple => quote!(__serde_shape::FieldsStyle::Tuple),
921 ast::Style::Newtype => quote!(__serde_shape::FieldsStyle::Newtype),
922 ast::Style::Unit => quote!(__serde_shape::FieldsStyle::Unit),
923 }
924}
925
926fn tagging(tag: &attr::TagType) -> TokenStream2 {
927 match tag {
928 attr::TagType::External => quote!(__serde_shape::Tagging::External),
929 attr::TagType::Internal { tag } => {
930 let tag = lit(tag);
931 quote!(__serde_shape::Tagging::Internal { tag: #tag })
932 }
933 attr::TagType::Adjacent { tag, content } => {
934 let tag = lit(tag);
935 let content = lit(content);
936 quote!(__serde_shape::Tagging::Adjacent {
937 tag: #tag,
938 content: #content,
939 })
940 }
941 attr::TagType::None => quote!(__serde_shape::Tagging::Untagged),
942 }
943}
944
945fn deserialize_tagging(attrs: &attr::Container) -> TokenStream2 {
946 match attrs.identifier() {
947 attr::Identifier::No => tagging(attrs.tag()),
948 attr::Identifier::Field => quote!(__serde_shape::Tagging::FieldIdentifier),
949 attr::Identifier::Variant => quote!(__serde_shape::Tagging::VariantIdentifier),
950 }
951}
952
953fn default_shape(default: &attr::Default) -> TokenStream2 {
954 match default {
955 attr::Default::None => quote!(__serde_shape::DefaultShape::None),
956 attr::Default::Default => quote!(__serde_shape::DefaultShape::Default),
957 attr::Default::Path(path) => {
958 let path = lit(path.to_token_stream().to_string());
959 quote!(__serde_shape::DefaultShape::Path(#path))
960 }
961 }
962}
963
964fn aliases(aliases: &BTreeSet<Name>) -> TokenStream2 {
965 let aliases = aliases.iter().map(lit_name);
966 quote!(__serde_shape::__private::vec![#(#aliases),*])
967}
968
969fn borrowed_cow_shape(field: &ast::Field<'_>) -> syn::Result<Option<TokenStream2>> {
970 if field.attrs.borrowed_lifetimes().is_empty()
974 || has_explicit_serde_deserializer(&field.original.attrs)?
975 {
976 return Ok(None);
977 }
978
979 let Some(element) = cow_element_type(field.ty) else {
980 return Ok(None);
981 };
982 if is_primitive_type(element, "str") {
983 Ok(Some(quote!(__serde_shape::ShapeRef::String)))
984 } else if is_byte_slice(element) {
985 Ok(Some(quote!(__serde_shape::ShapeRef::Bytes)))
986 } else {
987 Ok(None)
988 }
989}
990
991fn has_explicit_serde_deserializer(attrs: &[syn::Attribute]) -> syn::Result<bool> {
992 for attr in attrs.iter().filter(|attr| attr.path().is_ident("serde")) {
993 let metas = attr.parse_args_with(
994 syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated,
995 )?;
996 if metas
997 .iter()
998 .any(|meta| meta.path().is_ident("deserialize_with") || meta.path().is_ident("with"))
999 {
1000 return Ok(true);
1001 }
1002 }
1003 Ok(false)
1004}
1005
1006fn cow_element_type(ty: &Type) -> Option<&Type> {
1007 let Type::Path(ty) = ungroup(ty) else {
1008 return None;
1009 };
1010 let segment = ty.path.segments.last()?;
1011 let PathArguments::AngleBracketed(arguments) = &segment.arguments else {
1012 return None;
1013 };
1014 let mut arguments = arguments.args.iter();
1015 match (arguments.next(), arguments.next(), arguments.next()) {
1016 (Some(GenericArgument::Lifetime(_)), Some(GenericArgument::Type(element)), None)
1017 if segment.ident == "Cow" =>
1018 {
1019 Some(element)
1020 }
1021 _ => None,
1022 }
1023}
1024
1025fn is_byte_slice(ty: &Type) -> bool {
1026 match ungroup(ty) {
1027 Type::Slice(slice) => is_primitive_type(&slice.elem, "u8"),
1028 _ => false,
1029 }
1030}
1031
1032fn is_primitive_type(ty: &Type, name: &str) -> bool {
1033 let Type::Path(ty) = ungroup(ty) else {
1034 return false;
1035 };
1036 ty.qself.is_none()
1037 && ty.path.leading_colon.is_none()
1038 && ty.path.segments.len() == 1
1039 && ty.path.segments[0].ident == name
1040 && ty.path.segments[0].arguments.is_empty()
1041}
1042
1043fn lit_name(value: &Name) -> LitStr {
1044 LitStr::new(&value.value, value.span)
1045}
1046
1047fn option_lit(value: Option<&str>) -> TokenStream2 {
1048 match value {
1049 Some(value) => {
1050 let value = lit(value);
1051 quote!(::core::option::Option::Some(#value))
1052 }
1053 None => quote!(::core::option::Option::None),
1054 }
1055}
1056
1057fn option_path(value: Option<&syn::ExprPath>) -> TokenStream2 {
1058 match value {
1059 Some(value) => {
1060 let value = lit(value.to_token_stream().to_string());
1061 quote!(::core::option::Option::Some(#value))
1062 }
1063 None => quote!(::core::option::Option::None),
1064 }
1065}
1066
1067fn lit(value: impl AsRef<str>) -> LitStr {
1068 LitStr::new(value.as_ref(), proc_macro2::Span::call_site())
1069}