musli_macros/internals/
mode.rs

1//! Helper for determining the mode we're currently in.
2
3use proc_macro2::Span;
4use syn::punctuated::Punctuated;
5use syn::spanned::Spanned;
6use syn::Token;
7
8use super::attr::{FieldEncoding, ModeKind};
9use super::tokens::Tokens;
10use super::Only;
11
12#[derive(Clone, Copy)]
13pub(crate) enum ModePath<'a> {
14    Ident(&'a syn::Ident),
15    Musli(&'a syn::Path, &'a syn::Ident),
16}
17
18impl ModePath<'_> {
19    pub(crate) fn as_path(self) -> syn::Path {
20        match self {
21            ModePath::Ident(ident) => syn::Path::from(ident.clone()),
22            ModePath::Musli(base, ident) => {
23                let mut path = base.clone();
24                path.segments.push(syn::PathSegment::from(syn::Ident::new(
25                    "mode",
26                    Span::call_site(),
27                )));
28                path.segments.push(syn::PathSegment::from(ident.clone()));
29                path
30            }
31        }
32    }
33}
34
35#[derive(Clone, Copy)]
36pub(crate) struct Mode<'a> {
37    pub(crate) kind: Option<&'a ModeKind>,
38    pub(crate) mode_path: ModePath<'a>,
39    pub(crate) tokens: &'a Tokens,
40    pub(crate) only: Only,
41}
42
43impl<'a> Mode<'a> {
44    /// Construct a typed encode call.
45    pub(crate) fn encode_t_encode(&self, encoding: FieldEncoding) -> syn::Path {
46        let (mut encode_t, name) = match encoding {
47            FieldEncoding::Packed => (self.tokens.encode_packed_t.clone(), "encode_packed"),
48            FieldEncoding::Bytes => (self.tokens.encode_bytes_t.clone(), "encode_bytes"),
49            FieldEncoding::Trace => (self.tokens.trace_encode_t.clone(), "trace_encode"),
50            FieldEncoding::Default => (self.tokens.encode_t.clone(), "encode"),
51        };
52
53        if let Some(segment) = encode_t.segments.last_mut() {
54            add_mode_argument(&self.mode_path, segment);
55        }
56
57        encode_t
58            .segments
59            .push(syn::PathSegment::from(syn::Ident::new(
60                name,
61                encode_t.span(),
62            )));
63
64        encode_t
65    }
66
67    /// Construct a typed decode call.
68    pub(crate) fn decode_t_decode(&self, encoding: FieldEncoding) -> syn::Path {
69        let (mut decode_t, name) = match encoding {
70            FieldEncoding::Packed => (self.tokens.decode_packed_t.clone(), "decode_packed"),
71            FieldEncoding::Bytes => (self.tokens.decode_bytes_t.clone(), "decode_bytes"),
72            FieldEncoding::Trace => (self.tokens.trace_decode_t.clone(), "trace_decode"),
73            FieldEncoding::Default => (self.tokens.decode_t.clone(), "decode"),
74        };
75
76        if let Some(segment) = decode_t.segments.last_mut() {
77            add_mode_argument(&self.mode_path, segment);
78        }
79
80        decode_t
81            .segments
82            .push(syn::PathSegment::from(syn::Ident::new(
83                name,
84                decode_t.span(),
85            )));
86
87        decode_t
88    }
89}
90
91fn add_mode_argument(moded_ident: &ModePath<'_>, last: &mut syn::PathSegment) {
92    let mut arguments = syn::AngleBracketedGenericArguments {
93        colon2_token: Some(<Token![::]>::default()),
94        lt_token: <Token![<]>::default(),
95        args: Punctuated::default(),
96        gt_token: <Token![>]>::default(),
97    };
98
99    arguments
100        .args
101        .push(syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
102            qself: None,
103            path: moded_ident.as_path(),
104        })));
105
106    last.arguments = syn::PathArguments::AngleBracketed(arguments);
107}