1use std::collections::HashMap;
2use std::mem;
3
4use proc_macro2::Span;
5use syn::meta::ParseNestedMeta;
6use syn::parse::Parse;
7use syn::spanned::Spanned;
8use syn::Token;
9
10use crate::expander::NameMethod;
11use crate::expander::UnsizedMethod;
12use crate::internals::name::NameAll;
13use crate::internals::ATTR;
14use crate::internals::{Ctxt, Mode};
15
16#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
17pub(crate) enum ModeKind {
18 Binary,
19 Text,
20 Custom(Box<str>),
21}
22
23impl ModeKind {
24 pub(crate) fn default_name_all(&self) -> Option<NameAll> {
25 match self {
26 ModeKind::Binary => Some(NameAll::Index),
27 ModeKind::Text => Some(NameAll::Name),
28 ModeKind::Custom(_) => None,
29 }
30 }
31}
32
33#[derive(Debug, Clone)]
34pub(crate) struct ModeIdent {
35 pub(crate) ident: syn::Ident,
36 pub(crate) kind: ModeKind,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
40pub(crate) enum Only {
41 Encode,
42 Decode,
43}
44
45#[derive(Default)]
46struct OneOf<T> {
47 encode: T,
48 decode: T,
49 any: T,
50}
51
52#[derive(Clone, Copy)]
53pub(crate) enum EnumTagging<'a> {
54 Default,
57 Empty,
59 Internal { tag: &'a syn::Expr },
61 Adjacent {
63 tag: &'a syn::Expr,
64 content: &'a syn::Expr,
65 },
66}
67
68#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
70pub enum Packing {
71 #[default]
72 Tagged,
73 Packed,
74 Transparent,
75}
76
77macro_rules! merge {
78 ($self:expr, $cx:expr, $new:expr, $field:ident, $only:expr) => {{
79 for $field in $new.$field {
80 let out = match $only {
81 None => &mut $self.$field.any,
82 Some(Only::Decode) => &mut $self.$field.decode,
83 Some(Only::Encode) => &mut $self.$field.encode,
84 };
85
86 if out.is_some() {
87 $cx.error_span(
88 $field.0,
89 format_args!(
90 "#[{}] multiple {} attributes specified",
91 ATTR,
92 stringify!($field)
93 ),
94 );
95 } else {
96 *out = Some($field);
97 }
98 }
99 }};
100}
101
102macro_rules! layer {
103 ($attr:ident, $new:ident, $layer:ident {
104 $($(#[$($single_meta:meta)*])* $single:ident: $single_ty:ty,)* $(,)?
105 @multiple
106 $($(#[$($multiple_meta:meta)*])* $multiple:ident: $multiple_ty:ty,)* $(,)?
107 }) => {
108 #[derive(Default)]
109 pub(crate) struct $attr {
110 root: $layer,
111 modes: HashMap<ModeKind, $layer>,
112 }
113
114 impl $attr {
115 fn by_mode<A, O>(&self, mode: Mode<'_>, access: A) -> Option<&O>
116 where
117 A: Copy + Fn(&$layer) -> Option<&O>,
118 O: ?Sized,
119 {
120 if let Some(value) = mode.kind.and_then(|m| self.modes.get(m).and_then(access)) {
121 Some(value)
122 } else {
123 access(&self.root)
124 }
125 }
126
127 $(
128 #[allow(unused)]
129 pub(crate) fn $single(&self, mode: Mode<'_>) -> Option<&(Span, $single_ty)> {
130 self.by_mode(mode, |m| {
131 match mode.only {
132 Only::Encode if m.$single.encode.is_some() => m.$single.encode.as_ref(),
133 Only::Decode if m.$single.decode.is_some() => m.$single.decode.as_ref(),
134 _ => m.$single.any.as_ref(),
135 }
136 })
137 }
138 )*
139
140 $(
141 #[allow(unused)]
142 pub(crate) fn $multiple(&self, mode: Mode<'_>) -> &[(Span, $multiple_ty)] {
143 self.by_mode(mode, |m| {
144 match mode.only {
145 Only::Encode if !m.$multiple.encode.is_empty() => Some(&m.$multiple.encode[..]),
146 Only::Decode if !m.$multiple.decode.is_empty() => Some(&m.$multiple.decode[..]),
147 _ if !m.$multiple.any.is_empty() => Some(&m.$multiple.any[..]),
148 _ => None,
149 }
150 }).unwrap_or_default()
151 }
152 )*
153 }
154
155 #[derive(Default)]
156 struct $new {
157 $($(#[$($single_meta)*])* $single: Vec<(Span, $single_ty)>,)*
158 $($(#[$($multiple_meta)*])* $multiple: Vec<(Span, $multiple_ty)>,)*
159 }
160
161 #[derive(Default)]
162 struct $layer {
163 $($(#[$($single_meta)*])* $single: OneOf<Option<(Span, $single_ty)>>,)*
164 $($(#[$($multiple_meta)*])* $multiple: OneOf<Vec<(Span, $multiple_ty)>>,)*
165 }
166
167 impl $layer {
168 fn merge_with(&mut self, cx: &Ctxt, new: $new, only: Option<Only>) {
170 $(
171 merge!(self, cx, new, $single, only);
172 )*
173
174 $(
175 let list = match only {
176 None => {
177 &mut self.$multiple.any
178 }
179 Some(Only::Encode) => {
180 &mut self.$multiple.encode
181 }
182 Some(Only::Decode) => {
183 &mut self.$multiple.decode
184 }
185 };
186
187 list.extend(new.$multiple);
188 )*
189 }
190 }
191 }
192}
193
194layer! {
195 TypeAttr, TypeLayerNew, TypeLayer {
196 krate: syn::Path,
198 name_type: syn::Type,
200 name_all: NameAll,
202 name_method: NameMethod,
204 name_format_with: syn::Path,
206 tag: syn::Expr,
208 content: syn::Expr,
210 packing: Packing,
212 @multiple
213 bounds: syn::WherePredicate,
215 decode_bounds: syn::WherePredicate,
217 }
218}
219
220impl TypeAttr {
221 pub(crate) fn is_name_type_ambiguous(&self, mode: Mode<'_>) -> bool {
222 self.name_type(mode).is_none()
223 && self.name_all(mode).is_none()
224 && self.name_method(mode).is_none()
225 }
226
227 pub(crate) fn enum_tagging_span(&self, mode: Mode<'_>) -> Option<Span> {
228 let tag = self.tag(mode);
229 let content = self.content(mode);
230 Some(tag.or(content)?.0)
231 }
232
233 pub(crate) fn enum_tagging(&self, mode: Mode<'_>) -> Option<EnumTagging<'_>> {
235 let (_, tag) = self.tag(mode)?;
236
237 Some(match self.content(mode) {
238 Some((_, content)) => EnumTagging::Adjacent { tag, content },
239 _ => EnumTagging::Internal { tag },
240 })
241 }
242
243 pub(crate) fn crate_or_default(&self, default: &str) -> syn::Path {
245 if let Some((_, krate)) = self.root.krate.any.as_ref() {
246 return krate.clone();
247 }
248
249 let mut path = syn::Path::from(syn::Ident::new(default, Span::call_site()));
250 path.leading_colon = Some(<Token![::]>::default());
251 path
252 }
253}
254
255pub(crate) fn type_attrs(cx: &Ctxt, attrs: &[syn::Attribute]) -> TypeAttr {
256 let mut attr = TypeAttr::default();
257
258 for a in attrs {
259 if !a.path().is_ident(ATTR) {
260 continue;
261 }
262
263 let mut new = TypeLayerNew::default();
264 let mut mode = None;
265 let mut only = None;
266
267 let result = a.parse_nested_meta(|meta| {
268 if meta.path.is_ident("mode") {
270 meta.input.parse::<Token![=]>()?;
271 mode = Some(parse_mode(&meta)?);
272 return Ok(());
273 }
274
275 if meta.path.is_ident("encode_only") {
276 only = Some(Only::Encode);
277 return Ok(());
278 }
279
280 if meta.path.is_ident("decode_only") {
281 only = Some(Only::Decode);
282 return Ok(());
283 }
284
285 if meta.path.is_ident("tag") {
287 meta.input.parse::<Token![=]>()?;
288 new.tag.push((meta.path.span(), meta.input.parse()?));
289 return Ok(());
290 }
291
292 if meta.path.is_ident("content") {
294 meta.input.parse::<Token![=]>()?;
295 new.content.push((meta.path.span(), meta.input.parse()?));
296 return Ok(());
297 }
298
299 if meta.path.is_ident("crate") {
301 let path = if meta.input.parse::<Option<Token![=]>>()?.is_some() {
302 meta.input.parse()?
303 } else {
304 syn::parse_quote!(crate)
305 };
306
307 new.krate.push((meta.path.span(), path));
308 return Ok(());
309 }
310
311 if meta.path.is_ident("name_type") {
313 meta.input.parse::<Token![=]>()?;
314 new.name_type.push((meta.path.span(), meta.input.parse()?));
315 return Ok(());
316 }
317
318 if meta.path.is_ident("name_format_with") {
320 meta.input.parse::<Token![=]>()?;
321 new.name_format_with
322 .push((meta.path.span(), meta.input.parse()?));
323 return Ok(());
324 }
325
326 if meta.path.is_ident("bound") {
328 meta.input.parse::<Token![=]>()?;
329 parse_bounds(&meta, &mut new.bounds)?;
330 return Ok(());
331 }
332
333 if meta.path.is_ident("decode_bound") {
335 meta.input.parse::<Token![=]>()?;
336 parse_bounds(&meta, &mut new.decode_bounds)?;
337 return Ok(());
338 }
339
340 if meta.path.is_ident("packed") {
342 new.packing.push((meta.path.span(), Packing::Packed));
343 return Ok(());
344 }
345
346 if meta.path.is_ident("transparent") {
348 new.packing.push((meta.path.span(), Packing::Transparent));
349 return Ok(());
350 }
351
352 if meta.path.is_ident("name_all") {
354 new.name_all
355 .push((meta.path.span(), parse_name_all(&meta)?));
356 return Ok(());
357 }
358
359 if meta.path.is_ident("name_method") {
361 new.name_method
362 .push((meta.path.span(), parse_name_method(&meta)?));
363 return Ok(());
364 }
365
366 Err(syn::Error::new_spanned(
367 meta.path,
368 format_args!("#[{ATTR}] Unsupported type attribute"),
369 ))
370 });
371
372 if let Err(error) = result {
373 cx.syn_error(error);
374 }
375
376 let attr = match mode {
377 Some(mode) => {
378 let modes = attr.modes.entry(mode.kind.clone()).or_default();
379 cx.register_mode(mode);
380 modes
381 }
382 None => &mut attr.root,
383 };
384
385 attr.merge_with(cx, new, only);
386 }
387
388 attr
389}
390
391fn parse_name_method(meta: &syn::meta::ParseNestedMeta<'_>) -> Result<NameMethod, syn::Error> {
392 meta.input.parse::<Token![=]>()?;
393
394 let string: syn::LitStr = meta.input.parse()?;
395 let s = string.value();
396
397 match s.as_str() {
398 "value" => Ok(NameMethod::Value),
399 "unsized" => Ok(NameMethod::Unsized(UnsizedMethod::Default)),
400 "unsized_bytes" => Ok(NameMethod::Unsized(UnsizedMethod::Bytes)),
401 _ => Err(syn::Error::new_spanned(
402 string,
403 "#[musli(name_method = ..)]: Bad value, expected one of \"value\", \"unsized\", \"unsized_bytes\"",
404 )),
405 }
406}
407
408fn parse_name_all(meta: &syn::meta::ParseNestedMeta<'_>) -> Result<NameAll, syn::Error> {
409 meta.input.parse::<Token![=]>()?;
410
411 let string: syn::LitStr = meta.input.parse()?;
412 let s = string.value();
413
414 let Some(name_all) = NameAll::parse(s.as_str()) else {
415 let mut options = Vec::new();
416
417 for option in NameAll::ALL {
418 options.push(format!(r#""{option}""#));
419 }
420
421 let options = options.join(", ");
422
423 return Err(syn::Error::new_spanned(
424 string,
425 format_args!("#[{ATTR}(name_all = {s:?})]: Bad value, expected one of {options}"),
426 ));
427 };
428
429 Ok(name_all)
430}
431
432fn parse_bounds(
433 meta: &syn::meta::ParseNestedMeta,
434 out: &mut Vec<(Span, syn::WherePredicate)>,
435) -> syn::Result<()> {
436 let content;
437 syn::braced!(content in meta.input);
438 let where_clauses = content.parse_terminated(syn::WherePredicate::parse, Token![,])?;
439
440 for where_clause in where_clauses {
441 out.push((meta.path.span(), where_clause));
442 }
443
444 Ok(())
445}
446
447layer! {
448 VariantAttr, VariantLayerNew, VariantLayer {
449 name_type: syn::Type,
451 name_format_with: syn::Path,
453 name: syn::Expr,
455 pattern: syn::Pat,
457 name_all: NameAll,
459 name_method: NameMethod,
461 packing: Packing,
463 default_variant: (),
465 @multiple
466 }
467}
468
469impl VariantAttr {
470 pub(crate) fn is_name_type_ambiguous(&self, mode: Mode<'_>) -> bool {
471 self.name_type(mode).is_none()
472 && self.name_all(mode).is_none()
473 && self.name_method(mode).is_none()
474 }
475}
476
477pub(crate) fn variant_attrs(cx: &Ctxt, attrs: &[syn::Attribute]) -> VariantAttr {
479 let mut attr = VariantAttr::default();
480
481 for a in attrs {
482 if !a.path().is_ident(ATTR) {
483 continue;
484 }
485
486 let mut new = VariantLayerNew::default();
487 let mut mode = None;
488 let mut only = None;
489
490 let result = a.parse_nested_meta(|meta| {
491 if meta.path.is_ident("mode") {
493 meta.input.parse::<Token![=]>()?;
494 mode = Some(parse_mode(&meta)?);
495 return Ok(());
496 }
497
498 if meta.path.is_ident("encode_only") {
499 only = Some(Only::Encode);
500 return Ok(());
501 }
502
503 if meta.path.is_ident("decode_only") {
504 only = Some(Only::Decode);
505 return Ok(());
506 }
507
508 if meta.path.is_ident("name_type") {
510 meta.input.parse::<Token![=]>()?;
511 new.name_type.push((meta.path.span(), meta.input.parse()?));
512 return Ok(());
513 }
514
515 if meta.path.is_ident("name_format_with") {
517 meta.input.parse::<Token![=]>()?;
518 new.name_format_with
519 .push((meta.path.span(), meta.input.parse()?));
520 return Ok(());
521 }
522
523 if meta.path.is_ident("rename") {
524 return Err(syn::Error::new_spanned(
525 meta.path,
526 "#[musli(rename = ..)] has been changed to #[musli(name = ..)]",
527 ));
528 }
529
530 if meta.path.is_ident("name") {
532 meta.input.parse::<Token![=]>()?;
533 new.name.push((meta.path.span(), meta.input.parse()?));
534 return Ok(());
535 }
536
537 if meta.path.is_ident("pattern") {
539 meta.input.parse::<Token![=]>()?;
540 new.pattern
541 .push((meta.path.span(), meta.input.call(syn::Pat::parse_single)?));
542 return Ok(());
543 }
544
545 if meta.path.is_ident("default") {
547 new.default_variant.push((meta.path.span(), ()));
548 return Ok(());
549 }
550
551 if meta.path.is_ident("packed") {
553 new.packing.push((meta.path.span(), Packing::Packed));
554 return Ok(());
555 }
556
557 if meta.path.is_ident("transparent") {
559 new.packing.push((meta.path.span(), Packing::Transparent));
560 return Ok(());
561 }
562
563 if meta.path.is_ident("name_all") {
565 new.name_all
566 .push((meta.path.span(), parse_name_all(&meta)?));
567 return Ok(());
568 }
569
570 if meta.path.is_ident("name_method") {
572 new.name_method
573 .push((meta.path.span(), parse_name_method(&meta)?));
574 return Ok(());
575 }
576
577 Err(syn::Error::new_spanned(
578 meta.path,
579 format_args!("#[{ATTR}] Unsupported type attribute"),
580 ))
581 });
582
583 if let Err(error) = result {
584 cx.syn_error(error);
585 }
586
587 let attr = match mode {
588 Some(mode) => {
589 let out = attr.modes.entry(mode.kind.clone()).or_default();
590 cx.register_mode(mode);
591 out
592 }
593 None => &mut attr.root,
594 };
595
596 attr.merge_with(cx, new, only);
597 }
598
599 attr
600}
601
602#[derive(Default, Clone, Copy)]
603pub(crate) enum FieldEncoding {
604 Packed,
605 Bytes,
606 Trace,
607 #[default]
608 Default,
609}
610
611layer! {
612 Field, FieldNew, FieldLayer {
613 encode_path: syn::Path,
615 decode_path: syn::Path,
617 skip_encoding_if: syn::Path,
619 name: syn::Expr,
621 pattern: syn::Pat,
623 is_default: Option<syn::Path>,
625 skip: (),
627 encoding: FieldEncoding,
629 @multiple
630 }
631}
632
633impl Field {
634 pub(crate) fn encode_path_expanded(&self, mode: Mode<'_>, span: Span) -> (Span, syn::Path) {
636 let encode_path = self.encode_path(mode);
637
638 if let Some((span, encode_path)) = encode_path {
639 (*span, encode_path.clone())
640 } else {
641 let field_encoding = self.encoding(mode).map(|&(_, e)| e).unwrap_or_default();
642 let encode_path = mode.encode_t_encode(field_encoding);
643 (span, encode_path)
644 }
645 }
646
647 pub(crate) fn decode_path_expanded(&self, mode: Mode<'_>, span: Span) -> (Span, syn::Path) {
649 let decode_path = self.decode_path(mode);
650
651 if let Some((span, decode_path)) = decode_path {
652 (*span, decode_path.clone())
653 } else {
654 let field_encoding = self.encoding(mode).map(|&(_, e)| e).unwrap_or_default();
655 let decode_path = mode.decode_t_decode(field_encoding);
656 (span, decode_path)
657 }
658 }
659}
660
661pub(crate) fn field_attrs(cx: &Ctxt, attrs: &[syn::Attribute]) -> Field {
663 let mut attr = Field::default();
664
665 for a in attrs {
666 if !a.path().is_ident(ATTR) {
667 continue;
668 }
669
670 let mut new = FieldNew::default();
671 let mut mode = None;
672 let mut only = None;
673
674 let result = a.parse_nested_meta(|meta| {
675 if meta.path.is_ident("mode") {
677 meta.input.parse::<Token![=]>()?;
678 mode = Some(parse_mode(&meta)?);
679 return Ok(());
680 }
681
682 if meta.path.is_ident("encode_only") {
683 only = Some(Only::Encode);
684 return Ok(());
685 }
686
687 if meta.path.is_ident("decode_only") {
688 only = Some(Only::Decode);
689 return Ok(());
690 }
691
692 if meta.path.is_ident("with") {
694 meta.input.parse::<Token![=]>()?;
695 let mut path = meta.input.parse::<syn::Path>()?;
696
697 let (span, arguments) = match path.segments.last_mut() {
698 Some(s) => (
699 s.span(),
700 mem::replace(&mut s.arguments, syn::PathArguments::None),
701 ),
702 None => (path.span(), syn::PathArguments::None),
703 };
704
705 let mut encode_path = path.clone();
706
707 encode_path.segments.push({
708 let mut segment = syn::PathSegment::from(syn::Ident::new("encode", span));
709 segment.arguments = arguments.clone();
710 segment
711 });
712
713 let mut decode_path = path.clone();
714
715 decode_path.segments.push({
716 let mut segment = syn::PathSegment::from(syn::Ident::new("decode", span));
717 segment.arguments = arguments;
718 segment
719 });
720
721 new.encode_path.push((path.span(), encode_path));
722 new.decode_path.push((path.span(), decode_path));
723 return Ok(());
724 }
725
726 if meta.path.is_ident("skip_encoding_if") {
728 meta.input.parse::<Token![=]>()?;
729 new.skip_encoding_if
730 .push((meta.path.span(), meta.input.parse()?));
731 return Ok(());
732 }
733
734 if meta.path.is_ident("rename") {
735 return Err(syn::Error::new_spanned(
736 meta.path,
737 "#[musli(rename = ..)] has been changed to #[musli(name = ..)]",
738 ));
739 }
740
741 if meta.path.is_ident("name") {
743 meta.input.parse::<Token![=]>()?;
744 new.name.push((meta.path.span(), meta.input.parse()?));
745 return Ok(());
746 }
747
748 if meta.path.is_ident("pattern") {
750 meta.input.parse::<Token![=]>()?;
751 new.pattern
752 .push((meta.path.span(), meta.input.call(syn::Pat::parse_single)?));
753 return Ok(());
754 }
755
756 if meta.path.is_ident("default") {
758 if meta.input.parse::<Option<Token![=]>>()?.is_some() {
759 new.is_default
760 .push((meta.path.span(), Some(meta.input.parse()?)));
761 } else {
762 new.is_default.push((meta.path.span(), None));
763 }
764
765 return Ok(());
766 }
767
768 if meta.path.is_ident("skip") {
770 new.skip.push((meta.path.span(), ()));
771 return Ok(());
772 }
773
774 if meta.path.is_ident("trace") {
776 new.encoding.push((meta.path.span(), FieldEncoding::Trace));
777 return Ok(());
778 }
779
780 if meta.path.is_ident("bytes") {
782 new.encoding.push((meta.path.span(), FieldEncoding::Bytes));
783 return Ok(());
784 }
785
786 if meta.path.is_ident("packed") {
788 new.encoding.push((meta.path.span(), FieldEncoding::Packed));
789 return Ok(());
790 }
791
792 Err(syn::Error::new_spanned(
793 meta.path,
794 format_args!("#[{ATTR}] Unsupported field attribute"),
795 ))
796 });
797
798 if let Err(error) = result {
799 cx.syn_error(error);
800 }
801
802 let attr = match mode {
803 Some(mode) => {
804 let out = attr.modes.entry(mode.kind.clone()).or_default();
805 cx.register_mode(mode);
806 out
807 }
808 None => &mut attr.root,
809 };
810
811 attr.merge_with(cx, new, only);
812 }
813
814 attr
815}
816
817fn parse_mode(meta: &ParseNestedMeta<'_>) -> syn::Result<ModeIdent> {
818 let ident: syn::Ident = meta.input.parse()?;
819 let s = ident.to_string();
820
821 let kind = match s.as_str() {
822 "Binary" => ModeKind::Binary,
823 "Text" => ModeKind::Text,
824 other => ModeKind::Custom(other.into()),
825 };
826
827 Ok(ModeIdent { ident, kind })
828}