1use proc_macro::TokenStream;
18use quote::quote;
19use syn::{
20 Data, DeriveInput, Fields, GenericParam, Ident, Lifetime, LifetimeParam, Type,
21 parse_macro_input, spanned::Spanned,
22};
23
24#[derive(Default)]
30struct FieldAttrs {
31 rename: Option<String>,
32 skip: bool,
33 default: bool,
34 skip_if_none: bool,
35}
36
37#[derive(Default)]
38struct ContainerAttrs {
39 rename_all: Option<String>,
40 lenient: bool,
43 tag: Option<String>,
45 content: Option<String>,
46 untagged: bool,
47}
48
49enum EnumMode {
51 External,
52 Internal(String),
53 Adjacent(String, String),
54 Untagged,
55}
56
57impl ContainerAttrs {
58 fn enum_mode(&self) -> EnumMode {
59 if self.untagged {
60 EnumMode::Untagged
61 } else if let (Some(t), Some(c)) = (&self.tag, &self.content) {
62 EnumMode::Adjacent(t.clone(), c.clone())
63 } else if let Some(t) = &self.tag {
64 EnumMode::Internal(t.clone())
65 } else {
66 EnumMode::External
67 }
68 }
69}
70
71fn parse_field_attrs(attrs: &[syn::Attribute]) -> syn::Result<FieldAttrs> {
72 let mut out = FieldAttrs::default();
73 for attr in attrs {
74 if !attr.path().is_ident("bourne") {
75 continue;
76 }
77 attr.parse_nested_meta(|meta| {
78 if meta.path.is_ident("rename") {
79 let v = meta.value()?;
80 let s: syn::LitStr = v.parse()?;
81 out.rename = Some(s.value());
82 } else if meta.path.is_ident("skip") {
83 out.skip = true;
84 } else if meta.path.is_ident("default") {
85 out.default = true;
86 } else if meta.path.is_ident("skip_if_none") {
87 out.skip_if_none = true;
88 } else {
89 return Err(meta.error("unknown bourne field attribute"));
90 }
91 Ok(())
92 })?;
93 }
94 Ok(out)
95}
96
97fn parse_container_attrs(attrs: &[syn::Attribute]) -> syn::Result<ContainerAttrs> {
98 let mut out = ContainerAttrs::default();
99 for attr in attrs {
100 if !attr.path().is_ident("bourne") {
101 continue;
102 }
103 attr.parse_nested_meta(|meta| {
104 if meta.path.is_ident("rename_all") {
105 let v = meta.value()?;
106 let s: syn::LitStr = v.parse()?;
107 out.rename_all = Some(s.value());
108 } else if meta.path.is_ident("deny_unknown_fields") {
109 if let Ok(v) = meta.value() {
111 let b: syn::LitBool = v.parse()?;
112 out.lenient = !b.value();
116 } else {
117 out.lenient = false;
118 }
119 } else if meta.path.is_ident("tag") {
120 let v = meta.value()?;
121 let s: syn::LitStr = v.parse()?;
122 out.tag = Some(s.value());
123 } else if meta.path.is_ident("content") {
124 let v = meta.value()?;
125 let s: syn::LitStr = v.parse()?;
126 out.content = Some(s.value());
127 } else if meta.path.is_ident("untagged") {
128 out.untagged = true;
129 } else {
130 return Err(meta.error("unknown bourne container attribute"));
131 }
132 Ok(())
133 })?;
134 }
135 Ok(out)
136}
137
138fn is_option(ty: &Type) -> bool {
145 if let Type::Path(tp) = ty {
146 if let Some(seg) = tp.path.segments.last() {
147 return seg.ident == "Option";
148 }
149 }
150 false
151}
152
153fn key_expr(
157 name: &Ident,
158 rename: &Option<String>,
159 rename_all: &Option<String>,
160) -> proc_macro2::TokenStream {
161 if let Some(r) = rename {
162 quote! { #r }
163 } else if let Some(case) = rename_all {
164 let name_str = name.to_string();
165 quote! {{
166 const __BOURNE_KEY: &str =
167 ::json_bourne::__Casing::rename(#name_str, #case).as_str();
168 __BOURNE_KEY
169 }}
170 } else {
171 let name_str = name.to_string();
172 quote! { #name_str }
173 }
174}
175
176fn parse_variant_rename(attrs: &[syn::Attribute]) -> syn::Result<Option<String>> {
178 let mut rename = None;
179 for attr in attrs {
180 if !attr.path().is_ident("bourne") {
181 continue;
182 }
183 attr.parse_nested_meta(|meta| {
184 if meta.path.is_ident("rename") {
185 let v = meta.value()?;
186 let s: syn::LitStr = v.parse()?;
187 rename = Some(s.value());
188 Ok(())
189 } else {
190 Err(meta.error("unsupported variant attribute in prototype"))
191 }
192 })?;
193 }
194 Ok(rename)
195}
196
197enum VShape<'a> {
199 Unit,
200 Newtype(&'a Type),
201 Tuple(Vec<&'a Type>),
202 Struct(Vec<(&'a Ident, &'a Type)>),
203}
204
205fn classify_variant(v: &syn::Variant) -> VShape<'_> {
206 match &v.fields {
207 Fields::Unit => VShape::Unit,
208 Fields::Unnamed(u) if u.unnamed.len() == 1 => VShape::Newtype(&u.unnamed[0].ty),
209 Fields::Unnamed(u) => VShape::Tuple(u.unnamed.iter().map(|f| &f.ty).collect()),
210 Fields::Named(n) => VShape::Struct(
211 n.named
212 .iter()
213 .map(|f| (f.ident.as_ref().unwrap(), &f.ty))
214 .collect(),
215 ),
216 }
217}
218
219fn acquire_expr(ty: &Type) -> proc_macro2::TokenStream {
223 let ty_str = quote!(#ty).to_string().replace(' ', "");
224 let int_narrow = |t: &str| {
225 let t: proc_macro2::TokenStream = t.parse().unwrap();
226 quote! {
227 <#t>::try_from(__lex.parse_i64_value()?).map_err(|_| {
228 ::json_bourne::Error::new(
229 ::json_bourne::ErrorKind::NumberOutOfRange,
230 __lex.position(),
231 )
232 })?
233 }
234 };
235 match ty_str.as_str() {
236 "&str" | "&'inputstr" => quote! { __lex.parse_str_value()? },
237 "i64" => quote! { __lex.parse_i64_value()? },
238 "i8" => int_narrow("i8"),
239 "i16" => int_narrow("i16"),
240 "i32" => int_narrow("i32"),
241 "isize" => int_narrow("isize"),
242 "u8" => int_narrow("u8"),
243 "u16" => int_narrow("u16"),
244 "u32" => int_narrow("u32"),
245 "u64" => int_narrow("u64"),
246 "usize" => int_narrow("usize"),
247 _ => quote! {
248 <#ty as ::json_bourne::FromJson<'_>>::from_lex(__lex)?
249 },
250 }
251}
252
253struct GenericsPlan {
261 input_lt: Lifetime,
262 impl_generics: proc_macro2::TokenStream,
264 ty_generics: proc_macro2::TokenStream,
266 where_clause: proc_macro2::TokenStream,
267}
268
269fn plan_generics(input: &DeriveInput) -> GenericsPlan {
270 let generics = &input.generics;
271 let name = &input.ident;
272
273 let existing_lt = generics.params.iter().find_map(|p| match p {
274 GenericParam::Lifetime(lt) => Some(lt.lifetime.clone()),
275 _ => None,
276 });
277
278 let (input_lt, needs_fresh) = match existing_lt {
279 Some(lt) => (lt, false),
280 None => (Lifetime::new("'input", name.span()), true),
281 };
282
283 let mut impl_params: Vec<proc_macro2::TokenStream> = Vec::new();
285 if needs_fresh {
286 let lp = LifetimeParam::new(input_lt.clone());
287 impl_params.push(quote!(#lp));
288 }
289 for p in &generics.params {
290 impl_params.push(quote!(#p));
291 }
292
293 let ty_params: Vec<proc_macro2::TokenStream> = generics
295 .params
296 .iter()
297 .map(|p| match p {
298 GenericParam::Lifetime(lt) => {
299 let l = <.lifetime;
300 quote!(#l)
301 }
302 GenericParam::Type(t) => {
303 let id = &t.ident;
304 quote!(#id)
305 }
306 GenericParam::Const(c) => {
307 let id = &c.ident;
308 quote!(#id)
309 }
310 })
311 .collect();
312
313 let ty_generics = if ty_params.is_empty() {
314 quote!()
315 } else {
316 quote!(< #(#ty_params),* >)
317 };
318
319 let type_param_bounds: Vec<proc_macro2::TokenStream> = generics
323 .params
324 .iter()
325 .filter_map(|p| match p {
326 GenericParam::Type(t) => {
327 let id = &t.ident;
328 Some(quote!(#id: ::json_bourne::FromJson<#input_lt>))
329 }
330 _ => None,
331 })
332 .collect();
333
334 let where_clause = if type_param_bounds.is_empty() {
335 quote!()
336 } else {
337 quote!(where #(#type_param_bounds),*)
338 };
339
340 GenericsPlan {
341 input_lt,
342 impl_generics: quote!(< #(#impl_params),* >),
343 ty_generics,
344 where_clause,
345 }
346}
347
348#[proc_macro_derive(FromJson, attributes(bourne))]
353pub fn derive_from_json(input: TokenStream) -> TokenStream {
354 let input = parse_macro_input!(input as DeriveInput);
355 match from_json_impl(&input) {
356 Ok(ts) => ts.into(),
357 Err(e) => e.to_compile_error().into(),
358 }
359}
360
361fn from_json_impl(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
362 let name = &input.ident;
363 let container = parse_container_attrs(&input.attrs)?;
364 let plan = plan_generics(input);
365 let input_lt = &plan.input_lt;
366 let impl_generics = &plan.impl_generics;
367 let ty_generics = &plan.ty_generics;
368 let where_clause = &plan.where_clause;
369
370 let body = match &input.data {
371 Data::Struct(s) => match &s.fields {
372 Fields::Named(named) => from_json_named(&named.named, &container)?,
373 Fields::Unnamed(unnamed) => from_json_tuple(&unnamed.unnamed)?,
374 Fields::Unit => {
375 return Err(syn::Error::new(
376 input.span(),
377 "unit structs have no JSON representation",
378 ));
379 }
380 },
381 Data::Enum(e) => from_json_enum(name, &e.variants, &container)?,
382 Data::Union(_) => {
383 return Err(syn::Error::new(input.span(), "unions are unsupported"));
384 }
385 };
386
387 Ok(quote! {
388 impl #impl_generics ::json_bourne::FromJson<#input_lt> for #name #ty_generics
389 #where_clause
390 {
391 fn from_lex(
392 __lex: &mut ::json_bourne::Lexer<#input_lt>,
393 ) -> ::core::result::Result<Self, ::json_bourne::Error> {
394 #body
395 }
396 }
397 })
398}
399
400fn from_json_named(
401 fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>,
402 container: &ContainerAttrs,
403) -> syn::Result<proc_macro2::TokenStream> {
404 let mut decls = Vec::new();
405 let mut arms = Vec::new();
406 let mut assigns = Vec::new();
407
408 for field in fields {
409 let name = field.ident.as_ref().unwrap();
410 let ty = &field.ty;
411 let fa = parse_field_attrs(&field.attrs)?;
412
413 if fa.skip {
414 assigns.push(quote! { #name: ::core::default::Default::default(), });
415 continue;
416 }
417
418 decls.push(quote! {
419 let mut #name: ::core::option::Option<#ty> = ::core::option::Option::None;
420 });
421
422 let key = key_expr(name, &fa.rename, &container.rename_all);
423 let acquire = acquire_expr(ty);
424 arms.push(quote! {
425 __bourne_k if __bourne_k == #key => {
426 if #name.is_some() {
427 return ::core::result::Result::Err(::json_bourne::Error::new(
428 ::json_bourne::ErrorKind::DuplicateKey,
429 __lex.position(),
430 ));
431 }
432 #name = ::core::option::Option::Some(#acquire);
433 }
434 });
435
436 let fin = if fa.default {
438 quote! { #name.unwrap_or_else(::core::default::Default::default) }
439 } else if is_option(ty) {
440 quote! { #name.unwrap_or(::core::option::Option::None) }
441 } else {
442 quote! {
443 #name.ok_or_else(|| ::json_bourne::Error::new(
444 ::json_bourne::ErrorKind::MissingField,
445 __lex.position(),
446 ))?
447 }
448 };
449 assigns.push(quote! { #name: #fin, });
450 }
451
452 let unknown_arm = if container.lenient {
453 quote! { _ => { __lex.skip_value()?; } }
455 } else {
456 quote! {
457 _ => {
458 return ::core::result::Result::Err(::json_bourne::Error::new(
459 ::json_bourne::ErrorKind::UnknownField,
460 __lex.position(),
461 ));
462 }
463 }
464 };
465
466 Ok(quote! {
467 __lex.object_start()?;
468 #(#decls)*
469 let mut __maybe_key = __lex.object_first_key_lex()?;
470 while let ::core::option::Option::Some(__key_js) = __maybe_key {
471 let __key_cow = ::json_bourne::key_to_cow(__key_js, __lex)?;
472 match __key_cow.as_ref() {
473 #(#arms)*
474 #unknown_arm
475 }
476 __maybe_key = __lex.object_next_key_lex()?;
477 }
478 ::core::result::Result::Ok(Self { #(#assigns)* })
479 })
480}
481
482fn from_json_tuple(
483 fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>,
484) -> syn::Result<proc_macro2::TokenStream> {
485 let n = fields.len();
486 if n == 1 {
487 let ty = &fields[0].ty;
488 return Ok(quote! {
489 ::core::result::Result::Ok(Self(
490 <#ty as ::json_bourne::FromJson<'_>>::from_lex(__lex)?,
491 ))
492 });
493 }
494
495 let mut reads = Vec::new();
497 let mut idents = Vec::new();
498 for (i, field) in fields.iter().enumerate() {
499 let ty = &field.ty;
500 let id = Ident::new(&format!("__elem_{i}"), field.span());
501 if i == 0 {
502 reads.push(quote! {
503 let #id = <#ty as ::json_bourne::FromJson<'_>>::from_lex(__lex)?;
504 });
505 } else {
506 reads.push(quote! {
507 if __lex.array_continue(b']')? {
508 return ::core::result::Result::Err(::json_bourne::Error::new(
509 ::json_bourne::ErrorKind::TypeMismatch,
510 __lex.position(),
511 ));
512 }
513 let #id = <#ty as ::json_bourne::FromJson<'_>>::from_lex(__lex)?;
514 });
515 }
516 idents.push(id);
517 }
518
519 Ok(quote! {
520 if __lex.array_start()? {
521 return ::core::result::Result::Err(::json_bourne::Error::new(
522 ::json_bourne::ErrorKind::TypeMismatch,
523 __lex.position(),
524 ));
525 }
526 #(#reads)*
527 if !__lex.array_continue(b']')? {
528 return ::core::result::Result::Err(::json_bourne::Error::new(
529 ::json_bourne::ErrorKind::TypeMismatch,
530 __lex.position(),
531 ));
532 }
533 ::core::result::Result::Ok(Self( #(#idents),* ))
534 })
535}
536
537fn from_json_enum(
543 name: &Ident,
544 variants: &syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>,
545 container: &ContainerAttrs,
546) -> syn::Result<proc_macro2::TokenStream> {
547 match container.enum_mode() {
548 EnumMode::External => from_json_enum_external(name, variants, container),
549 EnumMode::Internal(tag) => from_json_enum_internal(name, variants, &tag),
550 EnumMode::Adjacent(tag, content) => from_json_enum_adjacent(name, variants, &tag, &content),
551 EnumMode::Untagged => from_json_enum_untagged(name, variants),
552 }
553}
554
555fn tuple_variant_read(ctor: &proc_macro2::TokenStream, tys: &[&Type]) -> proc_macro2::TokenStream {
558 let mut reads = Vec::new();
559 let mut idents = Vec::new();
560 for (i, ty) in tys.iter().enumerate() {
561 let id = Ident::new(&format!("__elem_{i}"), name_span());
562 if i == 0 {
563 reads.push(quote! {
564 let #id = <#ty as ::json_bourne::FromJson<'_>>::from_lex(__lex)?;
565 });
566 } else {
567 reads.push(quote! {
568 if __lex.array_continue(b']')? {
569 return ::core::result::Result::Err(::json_bourne::Error::new(
570 ::json_bourne::ErrorKind::TypeMismatch, __lex.position()));
571 }
572 let #id = <#ty as ::json_bourne::FromJson<'_>>::from_lex(__lex)?;
573 });
574 }
575 idents.push(id);
576 }
577 quote! {
578 if __lex.array_start()? {
579 return ::core::result::Result::Err(::json_bourne::Error::new(
580 ::json_bourne::ErrorKind::TypeMismatch, __lex.position()));
581 }
582 #(#reads)*
583 if !__lex.array_continue(b']')? {
584 return ::core::result::Result::Err(::json_bourne::Error::new(
585 ::json_bourne::ErrorKind::TypeMismatch, __lex.position()));
586 }
587 #ctor( #(#idents),* )
588 }
589}
590
591fn name_span() -> proc_macro2::Span {
592 proc_macro2::Span::call_site()
593}
594
595fn struct_variant_read(
598 ctor: &proc_macro2::TokenStream,
599 fields: &[(&Ident, &Type)],
600) -> proc_macro2::TokenStream {
601 let mut decls = Vec::new();
602 let mut arms = Vec::new();
603 let mut assigns = Vec::new();
604 for (fname, ty) in fields {
605 let key = fname.to_string();
606 let acquire = acquire_expr(ty);
607 decls.push(quote! {
608 let mut #fname: ::core::option::Option<#ty> = ::core::option::Option::None;
609 });
610 arms.push(quote! {
611 __bourne_k if __bourne_k == #key => {
612 if #fname.is_some() {
613 return ::core::result::Result::Err(::json_bourne::Error::new(
614 ::json_bourne::ErrorKind::DuplicateKey, __lex.position()));
615 }
616 #fname = ::core::option::Option::Some(#acquire);
617 }
618 });
619 let fin = if is_option(ty) {
620 quote! { #fname.unwrap_or(::core::option::Option::None) }
621 } else {
622 quote! {
623 #fname.ok_or_else(|| ::json_bourne::Error::new(
624 ::json_bourne::ErrorKind::MissingField, __lex.position()))?
625 }
626 };
627 assigns.push(quote! { #fname: #fin, });
628 }
629 quote! {{
630 __lex.object_start()?;
631 #(#decls)*
632 let mut __maybe_key = __lex.object_first_key_lex()?;
633 while let ::core::option::Option::Some(__key_js) = __maybe_key {
634 let __key_cow = ::json_bourne::key_to_cow(__key_js, __lex)?;
635 match __key_cow.as_ref() {
636 #(#arms)*
637 _ => {
638 return ::core::result::Result::Err(::json_bourne::Error::new(
639 ::json_bourne::ErrorKind::UnknownField, __lex.position()));
640 }
641 }
642 __maybe_key = __lex.object_next_key_lex()?;
643 }
644 #ctor { #(#assigns)* }
645 }}
646}
647
648fn from_json_enum_external(
649 name: &Ident,
650 variants: &syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>,
651 container: &ContainerAttrs,
652) -> syn::Result<proc_macro2::TokenStream> {
653 let mut unit_arms = Vec::new();
654 let mut tagged_arms = Vec::new();
655 for v in variants {
656 let vname = &v.ident;
657 let rename = parse_variant_rename(&v.attrs)?;
658 let key = key_expr(vname, &rename, &container.rename_all);
659 let ctor = quote!( #name::#vname );
660 match classify_variant(v) {
661 VShape::Unit => unit_arms.push(quote! {
662 __bourne_t if __bourne_t == #key => ::core::result::Result::Ok(#ctor),
663 }),
664 VShape::Newtype(ty) => tagged_arms.push(quote! {
665 __bourne_t if __bourne_t == #key =>
666 #ctor(<#ty as ::json_bourne::FromJson<'_>>::from_lex(__lex)?),
667 }),
668 VShape::Tuple(tys) => {
669 let body = tuple_variant_read(&ctor, &tys);
670 tagged_arms.push(quote! {
671 __bourne_t if __bourne_t == #key => { #body },
672 });
673 }
674 VShape::Struct(fields) => {
675 let body = struct_variant_read(&ctor, &fields);
676 tagged_arms.push(quote! {
677 __bourne_t if __bourne_t == #key => #body,
678 });
679 }
680 }
681 }
682
683 let object_dispatch = if tagged_arms.is_empty() {
684 quote!()
685 } else {
686 quote! {
687 ::json_bourne::ValueKind::Object => {
688 __lex.object_start()?;
689 let __key_js = __lex.object_first_key_lex()?.ok_or_else(|| {
690 ::json_bourne::Error::new(::json_bourne::ErrorKind::UnknownField, __lex.position())
691 })?;
692 let __key_cow = ::json_bourne::key_to_cow(__key_js, __lex)?;
693 let __value = match __key_cow.as_ref() {
694 #(#tagged_arms)*
695 _ => return ::core::result::Result::Err(::json_bourne::Error::new(
696 ::json_bourne::ErrorKind::UnknownField, __lex.position())),
697 };
698 if __lex.object_next_key_lex()?.is_some() {
699 return ::core::result::Result::Err(::json_bourne::Error::new(
700 ::json_bourne::ErrorKind::UnknownField, __lex.position()));
701 }
702 ::core::result::Result::Ok(__value)
703 }
704 }
705 };
706
707 Ok(quote! {
708 match __lex.peek_value_kind()? {
709 ::json_bourne::ValueKind::String => {
710 let __tag = __lex.parse_str_value()?;
711 match __tag {
712 #(#unit_arms)*
713 _ => ::core::result::Result::Err(::json_bourne::Error::new(
714 ::json_bourne::ErrorKind::UnknownField, __lex.position())),
715 }
716 }
717 #object_dispatch
718 _ => ::core::result::Result::Err(::json_bourne::Error::new(
719 ::json_bourne::ErrorKind::TypeMismatch, __lex.position())),
720 }
721 })
722}
723
724fn from_json_enum_internal(
725 name: &Ident,
726 variants: &syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>,
727 tag: &str,
728) -> syn::Result<proc_macro2::TokenStream> {
729 let mut arms = Vec::new();
730 for v in variants {
731 let vname = &v.ident;
732 let rename = parse_variant_rename(&v.attrs)?;
733 let key = key_expr(vname, &rename, &None);
734 let ctor = quote!( #name::#vname );
735 match classify_variant(v) {
736 VShape::Unit => arms.push(quote! {
737 __t if __t == #key => {
738 __lex.object_start()?;
740 let mut __mk = __lex.object_first_key_lex()?;
741 while let ::core::option::Option::Some(__kjs) = __mk {
742 let __kc = ::json_bourne::key_to_cow(__kjs, __lex)?;
743 if __kc.as_ref() == #tag {
744 __lex.skip_value()?;
745 } else {
746 return ::core::result::Result::Err(::json_bourne::Error::new(
747 ::json_bourne::ErrorKind::UnknownField, __lex.position()));
748 }
749 __mk = __lex.object_next_key_lex()?;
750 }
751 ::core::result::Result::Ok(#ctor)
752 }
753 }),
754 VShape::Struct(fields) => {
755 let body = internal_struct_variant_read(&ctor, &fields, tag);
756 arms.push(quote! { __t if __t == #key => #body, });
757 }
758 _ => {
759 return Err(syn::Error::new(
760 v.ident.span(),
761 "internally-tagged enums support only unit and struct variants",
762 ));
763 }
764 }
765 }
766
767 Ok(quote! {{
768 let __cp = __lex.checkpoint();
769 __lex.object_start()?;
770 let mut __maybe_key = __lex.object_first_key_lex()?;
771 let __tag_value: &str = loop {
772 let ::core::option::Option::Some(__key_js) = __maybe_key else {
773 return ::core::result::Result::Err(::json_bourne::Error::new(
774 ::json_bourne::ErrorKind::MissingField, __lex.position()));
775 };
776 let __key_cow = ::json_bourne::key_to_cow(__key_js, __lex)?;
777 if __key_cow.as_ref() == #tag {
778 break __lex.parse_str_value()?;
779 }
780 __lex.skip_value()?;
781 __maybe_key = __lex.object_next_key_lex()?;
782 };
783 __lex.restore(__cp);
784 match __tag_value {
785 #(#arms)*
786 _ => ::core::result::Result::Err(::json_bourne::Error::new(
787 ::json_bourne::ErrorKind::UnknownField, __lex.position())),
788 }
789 }})
790}
791
792fn internal_struct_variant_read(
795 ctor: &proc_macro2::TokenStream,
796 fields: &[(&Ident, &Type)],
797 tag: &str,
798) -> proc_macro2::TokenStream {
799 let mut decls = Vec::new();
800 let mut arms = Vec::new();
801 let mut assigns = Vec::new();
802 for (fname, ty) in fields {
803 let key = fname.to_string();
804 let acquire = acquire_expr(ty);
805 decls.push(quote! {
806 let mut #fname: ::core::option::Option<#ty> = ::core::option::Option::None;
807 });
808 arms.push(quote! {
809 __bourne_k if __bourne_k == #key => {
810 if #fname.is_some() {
811 return ::core::result::Result::Err(::json_bourne::Error::new(
812 ::json_bourne::ErrorKind::DuplicateKey, __lex.position()));
813 }
814 #fname = ::core::option::Option::Some(#acquire);
815 }
816 });
817 let fin = if is_option(ty) {
818 quote! { #fname.unwrap_or(::core::option::Option::None) }
819 } else {
820 quote! {
821 #fname.ok_or_else(|| ::json_bourne::Error::new(
822 ::json_bourne::ErrorKind::MissingField, __lex.position()))?
823 }
824 };
825 assigns.push(quote! { #fname: #fin, });
826 }
827 quote! {{
828 __lex.object_start()?;
829 #(#decls)*
830 let mut __maybe_key = __lex.object_first_key_lex()?;
831 while let ::core::option::Option::Some(__key_js) = __maybe_key {
832 let __key_cow = ::json_bourne::key_to_cow(__key_js, __lex)?;
833 match __key_cow.as_ref() {
834 #(#arms)*
835 __bourne_k if __bourne_k == #tag => { __lex.skip_value()?; }
836 _ => {
837 return ::core::result::Result::Err(::json_bourne::Error::new(
838 ::json_bourne::ErrorKind::UnknownField, __lex.position()));
839 }
840 }
841 __maybe_key = __lex.object_next_key_lex()?;
842 }
843 ::core::result::Result::Ok(#ctor { #(#assigns)* })
844 }}
845}
846
847fn from_json_enum_adjacent(
848 name: &Ident,
849 variants: &syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>,
850 tag: &str,
851 content: &str,
852) -> syn::Result<proc_macro2::TokenStream> {
853 let mut arms = Vec::new();
854 for v in variants {
855 let vname = &v.ident;
856 let rename = parse_variant_rename(&v.attrs)?;
857 let key = key_expr(vname, &rename, &None);
858 let ctor = quote!( #name::#vname );
859 match classify_variant(v) {
860 VShape::Unit => arms.push(quote! {
861 __t if __t == #key => {
862 if __content_cp.is_some() {
863 ::core::result::Result::Err(::json_bourne::Error::new(
864 ::json_bourne::ErrorKind::UnknownField, __lex.position()))
865 } else {
866 ::core::result::Result::Ok(#ctor)
867 }
868 }
869 }),
870 VShape::Newtype(ty) => arms.push(quote! {
871 __t if __t == #key => match __content_cp {
872 ::core::option::Option::Some(__c) => {
873 __lex.restore(__c);
874 ::core::result::Result::Ok(#ctor(
875 <#ty as ::json_bourne::FromJson<'_>>::from_lex(__lex)?))
876 }
877 ::core::option::Option::None => ::core::result::Result::Err(
878 ::json_bourne::Error::new(::json_bourne::ErrorKind::MissingField, __lex.position())),
879 }
880 }),
881 VShape::Tuple(tys) => {
882 let body = tuple_variant_read(&ctor, &tys);
883 arms.push(quote! {
884 __t if __t == #key => match __content_cp {
885 ::core::option::Option::Some(__c) => {
886 __lex.restore(__c);
887 ::core::result::Result::Ok({ #body })
888 }
889 ::core::option::Option::None => ::core::result::Result::Err(
890 ::json_bourne::Error::new(::json_bourne::ErrorKind::MissingField, __lex.position())),
891 }
892 });
893 }
894 VShape::Struct(fields) => {
895 let body = struct_variant_read(&ctor, &fields);
896 arms.push(quote! {
897 __t if __t == #key => match __content_cp {
898 ::core::option::Option::Some(__c) => {
899 __lex.restore(__c);
900 ::core::result::Result::Ok(#body)
901 }
902 ::core::option::Option::None => ::core::result::Result::Err(
903 ::json_bourne::Error::new(::json_bourne::ErrorKind::MissingField, __lex.position())),
904 }
905 });
906 }
907 }
908 }
909
910 Ok(quote! {{
911 __lex.object_start()?;
912 let mut __tag_value: ::core::option::Option<&str> = ::core::option::Option::None;
913 let mut __content_cp: ::core::option::Option<::json_bourne::Checkpoint> =
914 ::core::option::Option::None;
915 let mut __maybe_key = __lex.object_first_key_lex()?;
916 while let ::core::option::Option::Some(__key_js) = __maybe_key {
917 let __key_cow = ::json_bourne::key_to_cow(__key_js, __lex)?;
918 if __key_cow.as_ref() == #tag {
919 if __tag_value.is_some() {
920 return ::core::result::Result::Err(::json_bourne::Error::new(
921 ::json_bourne::ErrorKind::DuplicateKey, __lex.position()));
922 }
923 __tag_value = ::core::option::Option::Some(__lex.parse_str_value()?);
924 } else if __key_cow.as_ref() == #content {
925 if __content_cp.is_some() {
926 return ::core::result::Result::Err(::json_bourne::Error::new(
927 ::json_bourne::ErrorKind::DuplicateKey, __lex.position()));
928 }
929 __content_cp = ::core::option::Option::Some(__lex.checkpoint());
930 __lex.skip_value()?;
931 } else {
932 return ::core::result::Result::Err(::json_bourne::Error::new(
933 ::json_bourne::ErrorKind::UnknownField, __lex.position()));
934 }
935 __maybe_key = __lex.object_next_key_lex()?;
936 }
937 let __tag = __tag_value.ok_or_else(|| ::json_bourne::Error::new(
938 ::json_bourne::ErrorKind::MissingField, __lex.position()))?;
939 let __post_cp = __lex.checkpoint();
940 let __value = match __tag {
941 #(#arms)*
942 _ => ::core::result::Result::Err(::json_bourne::Error::new(
943 ::json_bourne::ErrorKind::UnknownField, __lex.position())),
944 }?;
945 __lex.restore(__post_cp);
946 ::core::result::Result::Ok(__value)
947 }})
948}
949
950fn from_json_enum_untagged(
951 name: &Ident,
952 variants: &syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>,
953) -> syn::Result<proc_macro2::TokenStream> {
954 let mut attempts = Vec::new();
955 for v in variants {
956 let vname = &v.ident;
957 let ctor = quote!( #name::#vname );
958 let try_body = match classify_variant(v) {
959 VShape::Unit => quote! {
960 <() as ::json_bourne::FromJson<'_>>::from_lex(__lex)?;
961 ::core::result::Result::Ok(#ctor)
962 },
963 VShape::Newtype(ty) => quote! {
964 ::core::result::Result::Ok(#ctor(
965 <#ty as ::json_bourne::FromJson<'_>>::from_lex(__lex)?))
966 },
967 VShape::Tuple(tys) => {
968 let body = tuple_variant_read(&ctor, &tys);
969 quote! { ::core::result::Result::Ok({ #body }) }
970 }
971 VShape::Struct(fields) => {
972 let body = struct_variant_read(&ctor, &fields);
973 quote! { ::core::result::Result::Ok(#body) }
974 }
975 };
976 attempts.push(quote! {
977 __lex.restore(__cp);
978 let __try: ::core::result::Result<Self, ::json_bourne::Error> = (|| { #try_body })();
979 if let ::core::result::Result::Ok(__v) = __try {
980 return ::core::result::Result::Ok(__v);
981 }
982 });
983 }
984 Ok(quote! {{
985 let __cp = __lex.checkpoint();
986 #(#attempts)*
987 ::core::result::Result::Err(::json_bourne::Error::new(
988 ::json_bourne::ErrorKind::TypeMismatch, __lex.position()))
989 }})
990}
991
992#[proc_macro_derive(ToJson, attributes(bourne))]
997pub fn derive_to_json(input: TokenStream) -> TokenStream {
998 let input = parse_macro_input!(input as DeriveInput);
999 match to_json_impl(&input) {
1000 Ok(ts) => ts.into(),
1001 Err(e) => e.to_compile_error().into(),
1002 }
1003}
1004
1005fn to_json_impl(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
1006 let name = &input.ident;
1007 let container = parse_container_attrs(&input.attrs)?;
1008
1009 let generics = &input.generics;
1012 let (impl_g, ty_g, _where_g) = generics.split_for_impl();
1013 let type_param_bounds: Vec<proc_macro2::TokenStream> = generics
1014 .params
1015 .iter()
1016 .filter_map(|p| match p {
1017 GenericParam::Type(t) => {
1018 let id = &t.ident;
1019 Some(quote!(#id: ::json_bourne::ToJson))
1020 }
1021 _ => None,
1022 })
1023 .collect();
1024 let where_clause = if type_param_bounds.is_empty() {
1025 quote!()
1026 } else {
1027 quote!(where #(#type_param_bounds),*)
1028 };
1029
1030 let body = match &input.data {
1031 Data::Struct(s) => match &s.fields {
1032 Fields::Named(named) => to_json_named(&named.named, &container)?,
1033 Fields::Unnamed(unnamed) => to_json_tuple(unnamed.unnamed.len()),
1034 Fields::Unit => {
1035 return Err(syn::Error::new(input.span(), "unit structs unsupported"));
1036 }
1037 },
1038 Data::Enum(e) => to_json_enum(name, &e.variants, &container)?,
1039 Data::Union(_) => {
1040 return Err(syn::Error::new(input.span(), "unions are unsupported"));
1041 }
1042 };
1043
1044 Ok(quote! {
1045 impl #impl_g ::json_bourne::ToJson for #name #ty_g #where_clause {
1046 fn write_json<__W: ::json_bourne::JsonWrite + ?::core::marker::Sized>(
1047 &self,
1048 __w: &mut __W,
1049 ) -> ::core::result::Result<(), __W::Error> {
1050 #body
1051 }
1052 }
1053 })
1054}
1055
1056fn to_json_named(
1057 fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>,
1058 container: &ContainerAttrs,
1059) -> syn::Result<proc_macro2::TokenStream> {
1060 let mut stmts = Vec::new();
1065 stmts.push(quote! { __w.write_raw_bytes(b"{")?; });
1066 stmts.push(quote! {
1067 #[allow(unused_assignments, unused_mut, unused_variables)]
1068 let mut __first: bool = true;
1069 });
1070
1071 #[derive(Clone, Copy, PartialEq)]
1077 enum StaticFirst {
1078 Yes,
1079 No,
1080 Maybe,
1081 }
1082 let mut sf = StaticFirst::Yes;
1083
1084 for field in fields {
1085 let name = field.ident.as_ref().unwrap();
1086 let ty = &field.ty;
1087 let fa = parse_field_attrs(&field.attrs)?;
1088 if fa.skip {
1089 continue;
1090 }
1091
1092 let plain = fa.rename.is_none() && container.rename_all.is_none();
1093
1094 if fa.skip_if_none && is_option(ty) {
1095 let key = key_expr(name, &fa.rename, &container.rename_all);
1097 let comma = match sf {
1098 StaticFirst::Yes => quote! {},
1099 StaticFirst::No => quote! { __w.write_raw_bytes(b",")?; },
1100 StaticFirst::Maybe => quote! { if !__first { __w.write_raw_bytes(b",")?; } },
1101 };
1102 stmts.push(quote! {
1103 if let ::core::option::Option::Some(ref __v) = self.#name {
1104 #comma
1105 __w.write_escaped_str(#key)?;
1106 __w.write_raw_bytes(b":")?;
1107 ::json_bourne::ToJson::write_json(__v, __w)?;
1108 __first = false;
1109 }
1110 });
1111 sf = StaticFirst::Maybe;
1112 continue;
1113 }
1114
1115 if plain && sf != StaticFirst::Maybe {
1116 let name_str = name.to_string();
1119 let lit = match sf {
1120 StaticFirst::Yes => format!("\"{name_str}\":"),
1121 _ => format!(",\"{name_str}\":"),
1122 };
1123 stmts.push(quote! {
1124 __w.write_raw_bytes(#lit.as_bytes())?;
1125 ::json_bourne::ToJson::write_json(&self.#name, __w)?;
1126 });
1127 sf = StaticFirst::No;
1128 } else {
1129 let key = key_expr(name, &fa.rename, &container.rename_all);
1132 let comma = match sf {
1133 StaticFirst::Yes => quote! {},
1134 StaticFirst::No => quote! { __w.write_raw_bytes(b",")?; },
1135 StaticFirst::Maybe => quote! { if !__first { __w.write_raw_bytes(b",")?; } },
1136 };
1137 stmts.push(quote! {
1138 #comma
1139 __w.write_escaped_str(#key)?;
1140 __w.write_raw_bytes(b":")?;
1141 ::json_bourne::ToJson::write_json(&self.#name, __w)?;
1142 __first = false;
1143 });
1144 sf = if sf == StaticFirst::Maybe {
1145 StaticFirst::Maybe
1146 } else {
1147 StaticFirst::No
1148 };
1149 }
1150 }
1151
1152 stmts.push(quote! { __w.write_raw_bytes(b"}")?; });
1153 stmts.push(quote! { ::core::result::Result::Ok(()) });
1154 Ok(quote! { #(#stmts)* })
1155}
1156
1157fn to_json_tuple(n: usize) -> proc_macro2::TokenStream {
1158 if n == 1 {
1159 return quote! {
1160 ::json_bourne::ToJson::write_json(&self.0, __w)
1161 };
1162 }
1163 let mut stmts = Vec::new();
1164 stmts.push(quote! { __w.write_raw_bytes(b"[")?; });
1165 for i in 0..n {
1166 let idx = syn::Index::from(i);
1167 if i > 0 {
1168 stmts.push(quote! { __w.write_raw_bytes(b",")?; });
1169 }
1170 stmts.push(quote! { ::json_bourne::ToJson::write_json(&self.#idx, __w)?; });
1171 }
1172 stmts.push(quote! { __w.write_raw_bytes(b"]")?; });
1173 stmts.push(quote! { ::core::result::Result::Ok(()) });
1174 quote! { #(#stmts)* }
1175}
1176
1177fn variant_field_idents(n: usize) -> Vec<Ident> {
1186 (0..n)
1187 .map(|i| Ident::new(&format!("__f{i}"), name_span()))
1188 .collect()
1189}
1190
1191fn to_json_enum(
1192 name: &Ident,
1193 variants: &syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>,
1194 container: &ContainerAttrs,
1195) -> syn::Result<proc_macro2::TokenStream> {
1196 let mode = container.enum_mode();
1197 let mut arms = Vec::new();
1198 for v in variants {
1199 let vname = &v.ident;
1200 let rename = parse_variant_rename(&v.attrs)?;
1201 let tagkey = key_expr(vname, &rename, &container.rename_all);
1202 arms.push(to_json_variant_arm(name, v, vname, &tagkey, &mode)?);
1203 }
1204 Ok(quote! {
1205 match self {
1206 #(#arms)*
1207 }
1208 })
1209}
1210
1211fn write_named_fields(fields: &[(&Ident, Ident)]) -> proc_macro2::TokenStream {
1213 let mut stmts = Vec::new();
1215 stmts.push(quote! { let mut __first = true; });
1216 for (key_ident, bind) in fields {
1217 let key = key_ident.to_string();
1218 let lit = format!("\"{key}\":");
1219 let lit_comma = format!(",\"{key}\":");
1220 stmts.push(quote! {
1221 if __first {
1222 __w.write_raw_bytes(#lit.as_bytes())?;
1223 __first = false;
1224 } else {
1225 __w.write_raw_bytes(#lit_comma.as_bytes())?;
1226 }
1227 ::json_bourne::ToJson::write_json(#bind, __w)?;
1228 });
1229 }
1230 quote! { #(#stmts)* }
1231}
1232
1233fn to_json_variant_arm(
1234 name: &Ident,
1235 v: &syn::Variant,
1236 vname: &Ident,
1237 tagkey: &proc_macro2::TokenStream,
1238 mode: &EnumMode,
1239) -> syn::Result<proc_macro2::TokenStream> {
1240 let shape = classify_variant(v);
1241 Ok(match (mode, &shape) {
1243 (EnumMode::Untagged, VShape::Unit) => quote! {
1245 #name::#vname => { __w.write_raw_bytes(b"null")?; ::core::result::Result::Ok(()) }
1246 },
1247 (EnumMode::Untagged, VShape::Newtype(_)) => quote! {
1248 #name::#vname(__inner) => {
1249 ::json_bourne::ToJson::write_json(__inner, __w)?;
1250 ::core::result::Result::Ok(())
1251 }
1252 },
1253 (EnumMode::Untagged, VShape::Tuple(tys)) => {
1254 let binds = variant_field_idents(tys.len());
1255 let writes = tuple_payload_writes(&binds);
1256 quote! {
1257 #name::#vname( #(#binds),* ) => { #writes ::core::result::Result::Ok(()) }
1258 }
1259 }
1260 (EnumMode::Untagged, VShape::Struct(fields)) => {
1261 let (pat, pairs) = struct_pat_and_pairs(fields);
1262 let body = write_named_fields(&pairs);
1263 quote! {
1264 #name::#vname { #pat } => {
1265 __w.write_raw_bytes(b"{")?;
1266 #body
1267 __w.write_raw_bytes(b"}")?;
1268 ::core::result::Result::Ok(())
1269 }
1270 }
1271 }
1272
1273 (EnumMode::External, VShape::Unit) => quote! {
1275 #name::#vname => {
1276 __w.write_raw_bytes(b"\"")?;
1277 __w.write_str_raw(#tagkey)?;
1278 __w.write_raw_bytes(b"\"")?;
1279 ::core::result::Result::Ok(())
1280 }
1281 },
1282 (EnumMode::External, VShape::Newtype(_)) => quote! {
1283 #name::#vname(__inner) => {
1284 __w.write_raw_bytes(b"{")?;
1285 __w.write_escaped_str(#tagkey)?;
1286 __w.write_raw_bytes(b":")?;
1287 ::json_bourne::ToJson::write_json(__inner, __w)?;
1288 __w.write_raw_bytes(b"}")?;
1289 ::core::result::Result::Ok(())
1290 }
1291 },
1292 (EnumMode::External, VShape::Tuple(tys)) => {
1293 let binds = variant_field_idents(tys.len());
1294 let writes = tuple_payload_writes(&binds);
1295 quote! {
1296 #name::#vname( #(#binds),* ) => {
1297 __w.write_raw_bytes(b"{")?;
1298 __w.write_escaped_str(#tagkey)?;
1299 __w.write_raw_bytes(b":")?;
1300 #writes
1301 __w.write_raw_bytes(b"}")?;
1302 ::core::result::Result::Ok(())
1303 }
1304 }
1305 }
1306 (EnumMode::External, VShape::Struct(fields)) => {
1307 let (pat, pairs) = struct_pat_and_pairs(fields);
1308 let body = write_named_fields(&pairs);
1309 quote! {
1310 #name::#vname { #pat } => {
1311 __w.write_raw_bytes(b"{")?;
1312 __w.write_escaped_str(#tagkey)?;
1313 __w.write_raw_bytes(b":{")?;
1314 #body
1315 __w.write_raw_bytes(b"}}")?;
1316 ::core::result::Result::Ok(())
1317 }
1318 }
1319 }
1320
1321 (EnumMode::Internal(tag), VShape::Unit) => quote! {
1323 #name::#vname => {
1324 __w.write_raw_bytes(b"{")?;
1325 __w.write_escaped_str(#tag)?;
1326 __w.write_raw_bytes(b":\"")?;
1327 __w.write_str_raw(#tagkey)?;
1328 __w.write_raw_bytes(b"\"}")?;
1329 ::core::result::Result::Ok(())
1330 }
1331 },
1332 (EnumMode::Internal(tag), VShape::Struct(fields)) => {
1333 let (pat, pairs) = struct_pat_and_pairs(fields);
1334 let mut stmts = Vec::new();
1337 for (key_ident, bind) in &pairs {
1338 let key = key_ident.to_string();
1339 let lit = format!(",\"{key}\":");
1340 stmts.push(quote! {
1341 __w.write_raw_bytes(#lit.as_bytes())?;
1342 ::json_bourne::ToJson::write_json(#bind, __w)?;
1343 });
1344 }
1345 quote! {
1346 #name::#vname { #pat } => {
1347 __w.write_raw_bytes(b"{")?;
1348 __w.write_escaped_str(#tag)?;
1349 __w.write_raw_bytes(b":\"")?;
1350 __w.write_str_raw(#tagkey)?;
1351 __w.write_raw_bytes(b"\"")?;
1352 #(#stmts)*
1353 __w.write_raw_bytes(b"}")?;
1354 ::core::result::Result::Ok(())
1355 }
1356 }
1357 }
1358 (EnumMode::Internal(_), _) => {
1359 return Err(syn::Error::new(
1360 v.ident.span(),
1361 "internally-tagged enums support only unit and struct variants",
1362 ));
1363 }
1364
1365 (EnumMode::Adjacent(tag, _content), VShape::Unit) => quote! {
1367 #name::#vname => {
1368 __w.write_raw_bytes(b"{")?;
1369 __w.write_escaped_str(#tag)?;
1370 __w.write_raw_bytes(b":\"")?;
1371 __w.write_str_raw(#tagkey)?;
1372 __w.write_raw_bytes(b"\"}")?;
1373 ::core::result::Result::Ok(())
1374 }
1375 },
1376 (EnumMode::Adjacent(tag, content), VShape::Newtype(_)) => quote! {
1377 #name::#vname(__inner) => {
1378 __w.write_raw_bytes(b"{")?;
1379 __w.write_escaped_str(#tag)?;
1380 __w.write_raw_bytes(b":\"")?;
1381 __w.write_str_raw(#tagkey)?;
1382 __w.write_raw_bytes(b"\",")?;
1383 __w.write_escaped_str(#content)?;
1384 __w.write_raw_bytes(b":")?;
1385 ::json_bourne::ToJson::write_json(__inner, __w)?;
1386 __w.write_raw_bytes(b"}")?;
1387 ::core::result::Result::Ok(())
1388 }
1389 },
1390 (EnumMode::Adjacent(tag, content), VShape::Tuple(tys)) => {
1391 let binds = variant_field_idents(tys.len());
1392 let writes = tuple_payload_writes(&binds);
1393 quote! {
1394 #name::#vname( #(#binds),* ) => {
1395 __w.write_raw_bytes(b"{")?;
1396 __w.write_escaped_str(#tag)?;
1397 __w.write_raw_bytes(b":\"")?;
1398 __w.write_str_raw(#tagkey)?;
1399 __w.write_raw_bytes(b"\",")?;
1400 __w.write_escaped_str(#content)?;
1401 __w.write_raw_bytes(b":")?;
1402 #writes
1403 __w.write_raw_bytes(b"}")?;
1404 ::core::result::Result::Ok(())
1405 }
1406 }
1407 }
1408 (EnumMode::Adjacent(tag, content), VShape::Struct(fields)) => {
1409 let (pat, pairs) = struct_pat_and_pairs(fields);
1410 let body = write_named_fields(&pairs);
1411 quote! {
1412 #name::#vname { #pat } => {
1413 __w.write_raw_bytes(b"{")?;
1414 __w.write_escaped_str(#tag)?;
1415 __w.write_raw_bytes(b":\"")?;
1416 __w.write_str_raw(#tagkey)?;
1417 __w.write_raw_bytes(b"\",")?;
1418 __w.write_escaped_str(#content)?;
1419 __w.write_raw_bytes(b":{")?;
1420 #body
1421 __w.write_raw_bytes(b"}}")?;
1422 ::core::result::Result::Ok(())
1423 }
1424 }
1425 }
1426 })
1427}
1428
1429fn tuple_payload_writes(binds: &[Ident]) -> proc_macro2::TokenStream {
1431 let mut stmts = Vec::new();
1432 stmts.push(quote! { __w.write_raw_bytes(b"[")?; });
1433 for (i, b) in binds.iter().enumerate() {
1434 if i > 0 {
1435 stmts.push(quote! { __w.write_raw_bytes(b",")?; });
1436 }
1437 stmts.push(quote! { ::json_bourne::ToJson::write_json(#b, __w)?; });
1438 }
1439 stmts.push(quote! { __w.write_raw_bytes(b"]")?; });
1440 quote! { #(#stmts)* }
1441}
1442
1443fn struct_pat_and_pairs<'a>(
1446 fields: &'a [(&'a Ident, &'a Type)],
1447) -> (proc_macro2::TokenStream, Vec<(&'a Ident, Ident)>) {
1448 let mut pat = Vec::new();
1449 let mut pairs = Vec::new();
1450 for (i, (fname, _ty)) in fields.iter().enumerate() {
1451 let bind = Ident::new(&format!("__f{i}"), name_span());
1452 pat.push(quote! { #fname: #bind });
1453 pairs.push((*fname, bind));
1454 }
1455 (quote! { #(#pat),* }, pairs)
1456}