rune_macros/
context.rs

1use std::cell::RefCell;
2
3use proc_macro2::Span;
4use proc_macro2::TokenStream;
5use quote::quote_spanned;
6use quote::{quote, ToTokens};
7use syn::parse::ParseStream;
8use syn::punctuated::Punctuated;
9use syn::spanned::Spanned as _;
10use syn::Token;
11
12use rune_core::protocol::Protocol;
13
14use super::RUNE;
15
16/// Parsed `#[rune(..)]` field attributes.
17#[derive(Default)]
18#[must_use = "Attributes must be used or explicitly ignored"]
19pub(crate) struct FieldAttrs {
20    /// A field that is an identifier. Should use `Default::default` to be
21    /// constructed and ignored during `ToTokens` and `Spanned`.
22    pub(crate) id: Option<Span>,
23    /// `#[rune(iter)]`
24    pub(crate) iter: Option<Span>,
25    /// `#[rune(skip)]`
26    pub(crate) skip: Option<Span>,
27    /// `#[rune(option)]`
28    pub(crate) option: Option<Span>,
29    /// `#[rune(meta)]`
30    pub(crate) meta: Option<Span>,
31    /// A single field marked with `#[rune(span)]`.
32    pub(crate) span: Option<Span>,
33    /// Custom parser `#[rune(parse_with = "..")]`.
34    pub(crate) parse_with: Option<syn::Ident>,
35    /// `#[rune(..)]` to generate a protocol function.
36    pub(crate) protocols: Vec<FieldProtocol>,
37    /// `#[rune(copy)]` to indicate that a field is copy and does not need to be
38    /// cloned.
39    pub(crate) copy: bool,
40    /// Whether this field should be known at compile time or not.
41    pub(crate) field: bool,
42}
43
44impl FieldAttrs {
45    /// Indicate if the field should be skipped.
46    pub(crate) fn skip(&self) -> bool {
47        self.skip.is_some() || self.id.is_some()
48    }
49}
50
51/// Parsed #[const_value(..)] field attributes.
52#[derive(Default)]
53#[must_use = "Attributes must be used or explicitly ignored"]
54pub(crate) struct ConstValueFieldAttrs {
55    /// Define a custom parsing method.
56    pub(crate) with: Option<syn::Path>,
57}
58
59/// The parsing implementations to build.
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub(crate) enum ParseKind {
62    /// Generate default functions.
63    Default,
64    /// Only generate meta parse function.
65    MetaOnly,
66}
67
68impl Default for ParseKind {
69    fn default() -> Self {
70        Self::Default
71    }
72}
73
74/// Parsed field attributes.
75#[derive(Default)]
76#[must_use = "Attributes must be used or explicitly ignored"]
77pub(crate) struct TypeAttr {
78    /// `#[rune(name = TypeName)]` to override the default type name.
79    pub(crate) name: Option<syn::Ident>,
80    /// `#[rune(module = <path>)]`.
81    pub(crate) module: Option<syn::Path>,
82    /// `#[rune(install_with = "...")]`.
83    pub(crate) install_with: Option<syn::Path>,
84    /// `#[rune(parse = "..")]` type attribute.
85    pub(crate) parse: ParseKind,
86    /// `#[rune(item = <path>)]`.
87    pub(crate) item: Option<syn::Path>,
88    /// `#[rune(constructor)]`.
89    pub(crate) constructor: Option<Span>,
90    /// Parsed documentation.
91    pub(crate) docs: Vec<syn::Expr>,
92    /// Method to use to convert from value.
93    pub(crate) impl_params: Option<syn::punctuated::Punctuated<syn::TypeParam, Token![,]>>,
94}
95
96/// Parsed #[const_value(..)] field attributes.
97#[derive(Default)]
98#[must_use = "Attributes must be used or explicitly ignored"]
99pub(crate) struct ConstValueTypeAttr {
100    /// `#[const_value(module = <path>)]`.
101    pub(crate) module: Option<syn::Path>,
102}
103
104/// Parsed variant attributes.
105#[derive(Default)]
106#[must_use = "Attributes must be used or explicitly ignored"]
107pub(crate) struct VariantAttrs {
108    /// `#[rune(constructor)]`.
109    pub(crate) constructor: Option<Span>,
110    /// Discovered documentation.
111    pub(crate) docs: Vec<syn::Expr>,
112}
113
114#[derive(Clone, Copy)]
115pub(crate) enum GenerateTarget<'a> {
116    Named {
117        field_ident: &'a syn::Ident,
118        field_name: &'a syn::LitStr,
119    },
120    Numbered {
121        field_index: &'a syn::LitInt,
122    },
123}
124
125#[derive(Clone)]
126pub(crate) struct Generate<'a> {
127    pub(crate) tokens: &'a Tokens,
128    pub(crate) attrs: &'a FieldAttrs,
129    pub(crate) protocol: &'a FieldProtocol,
130    pub(crate) field: &'a syn::Field,
131    pub(crate) ty: &'a syn::Type,
132    pub(crate) target: GenerateTarget<'a>,
133}
134
135pub(crate) struct FieldProtocol {
136    pub(crate) generate: fn(Generate<'_>) -> TokenStream,
137    custom: Option<syn::Path>,
138}
139
140#[derive(Default)]
141pub(crate) struct Context {
142    pub(crate) errors: RefCell<Vec<syn::Error>>,
143    pub(crate) module: Option<syn::Path>,
144}
145
146impl Context {
147    /// Construct a new context.
148    pub(crate) fn new() -> Self {
149        Self::default()
150    }
151
152    /// Construct a new context intended to resolve items inside of the crate
153    /// in which it was declared.
154    pub(crate) fn with_crate() -> Self {
155        let mut crate_module = syn::Path {
156            leading_colon: None,
157            segments: Punctuated::default(),
158        };
159        crate_module
160            .segments
161            .push(syn::PathSegment::from(<Token![crate]>::default()));
162
163        Self {
164            errors: RefCell::new(Vec::new()),
165            module: Some(crate_module),
166        }
167    }
168
169    /// Helper to build using a function that takes a context.
170    pub(super) fn build(f: impl FnOnce(&Self) -> Result<TokenStream, ()>) -> TokenStream {
171        let cx = Self::new();
172        cx.build_inner(f)
173    }
174
175    /// Helper to build using a function that takes a context internally.
176    pub(super) fn build_with_crate(
177        f: impl FnOnce(&Self) -> Result<TokenStream, ()>,
178    ) -> TokenStream {
179        let cx = Self::with_crate();
180        cx.build_inner(f)
181    }
182
183    fn build_inner(self, f: impl FnOnce(&Self) -> Result<TokenStream, ()>) -> TokenStream {
184        fn to_compile_errors<I>(errors: I) -> TokenStream
185        where
186            I: IntoIterator<Item = syn::Error>,
187        {
188            let mut stream = TokenStream::default();
189
190            for error in errors {
191                stream.extend(error.into_compile_error());
192            }
193
194            stream
195        }
196
197        let Ok(builder) = f(&self) else {
198            return to_compile_errors(self.errors.into_inner());
199        };
200
201        let errors = self.errors.into_inner();
202
203        if !errors.is_empty() {
204            return to_compile_errors(errors);
205        }
206
207        builder
208    }
209
210    /// Register an error.
211    pub(crate) fn error(&self, error: syn::Error) {
212        self.errors.borrow_mut().push(error)
213    }
214
215    /// Test if context has any errors.
216    pub(crate) fn has_errors(&self) -> bool {
217        !self.errors.borrow().is_empty()
218    }
219
220    /// Get a field identifier.
221    pub(crate) fn field_ident<'a>(&self, field: &'a syn::Field) -> Result<&'a syn::Ident, ()> {
222        let Some(ident) = &field.ident else {
223            self.error(syn::Error::new_spanned(
224                field,
225                "Unnamed fields are not supported",
226            ));
227            return Err(());
228        };
229
230        Ok(ident)
231    }
232
233    pub(crate) fn const_value_field_attrs(&self, input: &[syn::Attribute]) -> ConstValueFieldAttrs {
234        let mut attr = ConstValueFieldAttrs::default();
235
236        for a in input {
237            if !a.path().is_ident("const_value") {
238                continue;
239            }
240
241            let result = a.parse_nested_meta(|meta| {
242                if meta.path.is_ident("with") {
243                    meta.input.parse::<Token![=]>()?;
244                    attr.with = Some(meta.input.parse::<syn::Path>()?);
245                    return Ok(());
246                }
247
248                Err(syn::Error::new_spanned(
249                    &meta.path,
250                    "Unsupported field attribute",
251                ))
252            });
253
254            if let Err(e) = result {
255                self.error(e);
256            };
257        }
258
259        attr
260    }
261
262    /// Parse field attributes.
263    pub(crate) fn field_attrs(&self, input: &[syn::Attribute]) -> FieldAttrs {
264        macro_rules! generate_assign {
265            ($proto:ident, $op:tt) => {
266                |g| {
267                    let Generate {
268                        ty,
269                        target,
270                        field,
271                        protocol,
272                        ..
273                    } = g;
274
275                    let protocol_field = g.tokens.protocol(&Protocol::$proto);
276
277                    match target {
278                        GenerateTarget::Named { field_ident, field_name } => {
279                            if let Some(custom) = &protocol.custom {
280                                quote_spanned! { field.span() =>
281                                    module.field_function(&#protocol_field, #field_name, #custom)?;
282                                }
283                            } else {
284                                quote_spanned! { field.span() =>
285                                    module.field_function(&#protocol_field, #field_name, |s: &mut Self, value: #ty| {
286                                        s.#field_ident $op value;
287                                    })?;
288                                }
289                            }
290                        }
291                        GenerateTarget::Numbered { field_index } => {
292                            if let Some(custom) = &protocol.custom {
293                                quote_spanned! { field.span() =>
294                                    module.index_function(&#protocol_field, #field_index, #custom)?;
295                                }
296                            } else {
297                                quote_spanned! { field.span() =>
298                                    module.index_function(&#protocol_field, #field_index, |s: &mut Self, value: #ty| {
299                                        s.#field_index $op value;
300                                    })?;
301                                }
302                            }
303                        }
304                    }
305                }
306            };
307        }
308
309        macro_rules! generate {
310            ($proto:ident, $op:tt) => {
311                |g| {
312                    let Generate {
313                        ty,
314                        target,
315                        field,
316                        protocol,
317                        ..
318                    } = g;
319
320                    let protocol_field = g.tokens.protocol(&Protocol::$proto);
321
322                    match target {
323                        GenerateTarget::Named { field_ident, field_name } => {
324                            if let Some(custom) = &protocol.custom {
325                                quote_spanned! { field.span() =>
326                                    module.field_function(&#protocol_field, #field_name, #custom)?;
327                                }
328                            } else {
329                                quote_spanned! { field.span() =>
330                                    module.field_function(&#protocol_field, #field_name, |s: &mut Self, value: #ty| {
331                                        s.#field_ident $op value
332                                    })?;
333                                }
334                            }
335                        }
336                        GenerateTarget::Numbered { field_index } => {
337                            if let Some(custom) = &protocol.custom {
338                                quote_spanned! { field.span() =>
339                                    module.index_function(&#protocol_field, #field_index, #custom)?;
340                                }
341                            } else {
342                                quote_spanned! { field.span() =>
343                                    module.index_function(&#protocol_field, #field_index, |s: &mut Self, value: #ty| {
344                                        s.#field_index $op value
345                                    })?;
346                                }
347                            }
348                        }
349                    }
350                }
351            };
352        }
353
354        let mut attr = FieldAttrs::default();
355
356        for a in input {
357            if !a.path().is_ident(RUNE) {
358                continue;
359            }
360
361            let result = a.parse_nested_meta(|meta| {
362                macro_rules! field_functions {
363                    (
364                        $(
365                            $assign:literal, $assign_proto:ident, [$($assign_op:tt)*],
366                            $op:literal, $op_proto:ident, [$($op_op:tt)*],
367                        )*
368                    ) => {{
369                        $(
370                            if meta.path.is_ident($assign) {
371                                attr.protocols.push(FieldProtocol {
372                                    custom: self.parse_field_custom(meta.input)?,
373                                    generate: generate_assign!($assign_proto, $($assign_op)*),
374                                });
375
376                                return Ok(());
377                            }
378
379                            if meta.path.is_ident($op) {
380                                attr.protocols.push(FieldProtocol {
381                                    custom: self.parse_field_custom(meta.input)?,
382                                    generate: generate!($op_proto, $($op_op)*),
383                                });
384
385                                return Ok(());
386                            }
387                        )*
388                    }};
389                }
390
391                if meta.path.is_ident("id") {
392                    attr.id = Some(meta.path.span());
393                    return Ok(());
394                }
395
396                if meta.path.is_ident("iter") {
397                    attr.iter = Some(meta.path.span());
398                    return Ok(());
399                }
400
401                if meta.path.is_ident("skip") {
402                    attr.skip = Some(meta.path.span());
403                    return Ok(());
404                }
405
406                if meta.path.is_ident("option") {
407                    attr.option = Some(meta.path.span());
408                    return Ok(());
409                }
410
411                if meta.path.is_ident("meta") {
412                    attr.meta = Some(meta.path.span());
413                    return Ok(());
414                }
415
416                if meta.path.is_ident("span") {
417                    attr.span = Some(meta.path.span());
418                    return Ok(());
419                }
420
421                if meta.path.is_ident("copy") {
422                    attr.copy = true;
423                    return Ok(());
424                }
425
426                if meta.path.is_ident("parse_with") {
427                    if let Some(old) = &attr.parse_with {
428                        let mut error = syn::Error::new_spanned(
429                            &meta.path,
430                            "#[rune(parse_with = \"..\")] can only be used once",
431                        );
432
433                        error.combine(syn::Error::new_spanned(old, "previously defined here"));
434                        return Err(error);
435                    }
436
437                    meta.input.parse::<Token![=]>()?;
438                    let s = meta.input.parse::<syn::LitStr>()?;
439                    attr.parse_with = Some(syn::Ident::new(&s.value(), s.span()));
440                    return Ok(());
441                }
442
443                if meta.path.is_ident("get") {
444                    attr.field = true;
445                    attr.protocols.push(FieldProtocol {
446                        custom: self.parse_field_custom(meta.input)?,
447                        generate: |g| {
448                            let Generate {
449                                target,
450                                ..
451                            } = g;
452
453                            let Tokens {
454                                try_clone,
455                                vm_try,
456                                vm_result,
457                                ..
458                            } = g.tokens;
459
460                            match target {
461                                GenerateTarget::Named { field_ident, field_name } => {
462                                    let access = if g.attrs.copy {
463                                        quote!(s.#field_ident)
464                                    } else {
465                                        quote!(#vm_try!(#try_clone::try_clone(&s.#field_ident)))
466                                    };
467
468                                    let protocol = g.tokens.protocol(&Protocol::GET);
469
470                                    quote_spanned! { g.field.span() =>
471                                        module.field_function(&#protocol, #field_name, |s: &Self| #vm_result::Ok(#access))?;
472                                    }
473                                }
474                                GenerateTarget::Numbered { field_index } => {
475                                    let access = if g.attrs.copy {
476                                        quote!(s.#field_index)
477                                    } else {
478                                        quote!(#vm_try!(#try_clone::try_clone(&s.#field_index)))
479                                    };
480
481                                    let protocol = g.tokens.protocol(&Protocol::GET);
482
483                                    quote_spanned! { g.field.span() =>
484                                        module.index_function(&#protocol, #field_index, |s: &Self| #vm_result::Ok(#access))?;
485                                    }
486                                }
487                            }
488                        },
489                    });
490
491                    return Ok(());
492                }
493
494                if meta.path.is_ident("set") {
495                    attr.protocols.push(FieldProtocol {
496                        custom: self.parse_field_custom(meta.input)?,
497                        generate: |g| {
498                            let Generate {
499                                ty,
500                                target,
501                                ..
502                            } = g;
503
504                            let protocol = g.tokens.protocol(&Protocol::SET);
505
506                            match target {
507                                GenerateTarget::Named { field_ident, field_name } => {
508                                    quote_spanned! { g.field.span() =>
509                                        module.field_function(&#protocol, #field_name, |s: &mut Self, value: #ty| {
510                                            s.#field_ident = value;
511                                        })?;
512                                    }
513                                }
514                                GenerateTarget::Numbered { field_index } => {
515                                    quote_spanned! { g.field.span() =>
516                                        module.index_function(&#protocol, #field_index, |s: &mut Self, value: #ty| {
517                                            s.#field_index = value;
518                                        })?;
519                                    }
520                                }
521                            }
522                        },
523                    });
524
525                    return Ok(());
526                }
527
528                field_functions! {
529                    "add_assign", ADD_ASSIGN, [+=], "add", ADD, [+],
530                    "sub_assign", SUB_ASSIGN, [-=], "sub", SUB, [-],
531                    "div_assign", DIV_ASSIGN, [/=], "div", DIV, [/],
532                    "mul_assign", MUL_ASSIGN, [*=], "mul", MUL, [*],
533                    "rem_assign", REM_ASSIGN, [%=], "rem", REM, [%],
534                    "bit_and_assign", BIT_AND_ASSIGN, [&=], "bit_and", BIT_AND, [&],
535                    "bit_or_assign", BIT_OR_ASSIGN, [|=], "bit_or", BIT_OR, [|],
536                    "bit_xor_assign", BIT_XOR_ASSIGN, [^=], "bit_xor", BIT_XOR, [^],
537                    "shl_assign", SHL_ASSIGN, [<<=], "shl", SHL, [<<],
538                    "shr_assign", SHR_ASSIGN, [>>=], "shr", SHR, [>>],
539                }
540
541                Err(syn::Error::new_spanned(&meta.path, "Unsupported attribute"))
542            });
543
544            if let Err(e) = result {
545                self.error(e);
546            }
547        }
548
549        attr
550    }
551
552    pub(crate) fn const_value_type_attrs(&self, input: &[syn::Attribute]) -> ConstValueTypeAttr {
553        let mut attr = ConstValueTypeAttr::default();
554
555        for a in input {
556            if !a.path().is_ident("const_value") {
557                continue;
558            }
559
560            let result = a.parse_nested_meta(|meta| {
561                if meta.path.is_ident("module") || meta.path.is_ident("crate") {
562                    if meta.input.parse::<Option<Token![=]>>()?.is_some() {
563                        attr.module = Some(parse_path_compat(meta.input)?);
564                    } else {
565                        attr.module = Some(syn::parse_quote!(crate));
566                    }
567
568                    return Ok(());
569                }
570
571                Err(syn::Error::new_spanned(
572                    &meta.path,
573                    "Unsupported type attribute",
574                ))
575            });
576
577            if let Err(e) = result {
578                self.error(e);
579            };
580        }
581
582        attr
583    }
584
585    /// Parse field attributes.
586    pub(crate) fn type_attrs(&self, input: &[syn::Attribute]) -> TypeAttr {
587        let mut attr = TypeAttr::default();
588
589        for a in input {
590            if a.path().is_ident("doc") {
591                if let syn::Meta::NameValue(meta) = &a.meta {
592                    attr.docs.push(meta.value.clone());
593                }
594
595                continue;
596            }
597
598            if !a.path().is_ident(RUNE) {
599                continue;
600            }
601
602            let result = a.parse_nested_meta(|meta| {
603                if meta.path.is_ident("parse") {
604                    meta.input.parse::<Token![=]>()?;
605                    let s: syn::LitStr = meta.input.parse()?;
606
607                    match s.value().as_str() {
608                        "meta_only" => {
609                            attr.parse = ParseKind::MetaOnly;
610                        }
611                        other => {
612                            return Err(syn::Error::new(
613                                meta.input.span(),
614                                format!("Unsupported `#[rune(parse = ..)]` argument `{}`", other),
615                            ));
616                        }
617                    };
618
619                    return Ok(());
620                }
621
622                if meta.path.is_ident("item") {
623                    meta.input.parse::<Token![=]>()?;
624                    attr.item = Some(meta.input.parse()?);
625                    return Ok(());
626                }
627
628                if meta.path.is_ident("name") {
629                    meta.input.parse::<Token![=]>()?;
630                    attr.name = Some(meta.input.parse()?);
631                    return Ok(());
632                }
633
634                if meta.path.is_ident("module") || meta.path.is_ident("crate") {
635                    if meta.input.parse::<Option<Token![=]>>()?.is_some() {
636                        attr.module = Some(parse_path_compat(meta.input)?);
637                    } else {
638                        attr.module = Some(syn::parse_quote!(crate));
639                    }
640
641                    return Ok(());
642                }
643
644                if meta.path.is_ident("install_with") {
645                    meta.input.parse::<Token![=]>()?;
646                    attr.install_with = Some(parse_path_compat(meta.input)?);
647                    return Ok(());
648                }
649
650                if meta.path.is_ident("constructor") {
651                    if attr.constructor.is_some() {
652                        return Err(syn::Error::new(
653                            meta.path.span(),
654                            "#[rune(constructor)] must only be used once",
655                        ));
656                    }
657
658                    attr.constructor = Some(meta.path.span());
659                    return Ok(());
660                }
661
662                if meta.path.is_ident("impl_params") {
663                    meta.input.parse::<Token![=]>()?;
664                    let content;
665                    syn::bracketed!(content in meta.input);
666                    attr.impl_params =
667                        Some(syn::punctuated::Punctuated::parse_terminated(&content)?);
668                    return Ok(());
669                }
670
671                Err(syn::Error::new_spanned(
672                    &meta.path,
673                    "Unsupported type attribute",
674                ))
675            });
676
677            if let Err(e) = result {
678                self.error(e);
679            };
680        }
681
682        attr
683    }
684
685    /// Parse and extract variant attributes.
686    pub(crate) fn variant_attr(&self, input: &[syn::Attribute]) -> VariantAttrs {
687        let mut attr = VariantAttrs::default();
688
689        for a in input {
690            if a.path().is_ident("doc") {
691                if let syn::Meta::NameValue(meta) = &a.meta {
692                    attr.docs.push(meta.value.clone());
693                }
694
695                continue;
696            }
697
698            if !a.path().is_ident(RUNE) {
699                continue;
700            }
701
702            let result = a.parse_nested_meta(|meta| {
703                if meta.path.is_ident("constructor") {
704                    if attr.constructor.is_some() {
705                        return Err(syn::Error::new(
706                            meta.path.span(),
707                            "#[rune(constructor)] must only be used once",
708                        ));
709                    }
710
711                    attr.constructor = Some(meta.path.span());
712                } else {
713                    return Err(syn::Error::new_spanned(&meta.path, "Unsupported attribute"));
714                }
715
716                Ok(())
717            });
718
719            if let Err(e) = result {
720                self.error(e);
721            }
722        }
723
724        attr
725    }
726
727    /// Parse path to custom field function.
728    fn parse_field_custom(&self, input: ParseStream<'_>) -> Result<Option<syn::Path>, syn::Error> {
729        if !input.peek(Token![=]) {
730            return Ok(None);
731        };
732
733        input.parse::<Token![=]>()?;
734        Ok(Some(parse_path_compat(input)?))
735    }
736
737    pub(crate) fn tokens_with_module(&self, module: Option<&syn::Path>) -> Tokens {
738        let mut core = syn::Path {
739            leading_colon: Some(<Token![::]>::default()),
740            segments: Punctuated::default(),
741        };
742        core.segments.push(syn::PathSegment::from(syn::Ident::new(
743            "core",
744            Span::call_site(),
745        )));
746
747        let mut alloc = syn::Path {
748            leading_colon: Some(<Token![::]>::default()),
749            segments: Punctuated::default(),
750        };
751        alloc.segments.push(syn::PathSegment::from(syn::Ident::new(
752            "alloc",
753            Span::call_site(),
754        )));
755
756        let mut default_module;
757
758        let m = match module {
759            Some(module) => module,
760            None => match &self.module {
761                Some(module) => module,
762                None => {
763                    default_module = syn::Path {
764                        leading_colon: None,
765                        segments: Punctuated::default(),
766                    };
767                    default_module
768                        .segments
769                        .push(syn::PathSegment::from(syn::Ident::new(
770                            RUNE,
771                            Span::call_site(),
772                        )));
773                    &default_module
774                }
775            },
776        };
777
778        let core = &core;
779
780        Tokens {
781            alloc: path(m, ["alloc"]),
782            any_marker_t: path(m, ["__private", "AnyMarker"]),
783            any_t: path(m, ["Any"]),
784            any_type_info: path(m, ["runtime", "AnyTypeInfo"]),
785            arc: path(m, ["__private", "Arc"]),
786            compile_error: path(m, ["compile", "Error"]),
787            const_construct_t: path(m, ["runtime", "ConstConstruct"]),
788            const_value: path(m, ["runtime", "ConstValue"]),
789            context_error: path(m, ["compile", "ContextError"]),
790            double_ended_iterator: path(core, ["iter", "DoubleEndedIterator"]),
791            fmt: path(core, ["fmt"]),
792            from_const_value_t: path(m, ["runtime", "FromConstValue"]),
793            from_value: path(m, ["runtime", "FromValue"]),
794            hash: path(m, ["Hash"]),
795            id: path(m, ["parse", "Id"]),
796            install_with: path(m, ["__private", "InstallWith"]),
797            into_iterator: path(core, ["iter", "IntoIterator"]),
798            item: path(m, ["Item"]),
799            iterator: path(core, ["iter", "Iterator"]),
800            macro_context: path(m, ["macros", "MacroContext"]),
801            maybe_type_of: path(m, ["runtime", "MaybeTypeOf"]),
802            meta: path(m, ["compile", "meta"]),
803            module: path(m, ["__private", "Module"]),
804            named: path(m, ["compile", "Named"]),
805            non_null: path(core, ["ptr", "NonNull"]),
806            object: path(m, ["runtime", "Object"]),
807            opaque: path(m, ["parse", "Opaque"]),
808            option_spanned: path(m, ["ast", "OptionSpanned"]),
809            option: path(core, ["option", "Option"]),
810            owned_tuple: path(m, ["runtime", "OwnedTuple"]),
811            parse: path(m, ["parse", "Parse"]),
812            parser: path(m, ["parse", "Parser"]),
813            protocol: path(m, ["runtime", "Protocol"]),
814            raw_value_guard: path(m, ["runtime", "RawValueGuard"]),
815            result: path(core, ["result", "Result"]),
816            runtime_error: path(m, ["runtime", "RuntimeError"]),
817            span: path(m, ["ast", "Span"]),
818            spanned: path(m, ["ast", "Spanned"]),
819            string: path(m, ["alloc", "String"]),
820            to_const_value_t: path(m, ["runtime", "ToConstValue"]),
821            to_tokens: path(m, ["macros", "ToTokens"]),
822            to_value: path(m, ["runtime", "ToValue"]),
823            token_stream: path(m, ["macros", "TokenStream"]),
824            try_clone: path(m, ["alloc", "clone", "TryClone"]),
825            try_from: path(core, ["convert", "TryFrom"]),
826            tuple: path(m, ["runtime", "Tuple"]),
827            type_hash_t: path(m, ["runtime", "TypeHash"]),
828            type_name: path(core, ["any", "type_name"]),
829            type_of: path(m, ["runtime", "TypeOf"]),
830            type_value: path(m, ["runtime", "TypeValue"]),
831            unsafe_to_mut: path(m, ["runtime", "UnsafeToMut"]),
832            unsafe_to_ref: path(m, ["runtime", "UnsafeToRef"]),
833            unsafe_to_value: path(m, ["runtime", "UnsafeToValue"]),
834            value_mut_guard: path(m, ["runtime", "ValueMutGuard"]),
835            value_ref_guard: path(m, ["runtime", "ValueRefGuard"]),
836            value: path(m, ["runtime", "Value"]),
837            vec: path(m, ["alloc", "Vec"]),
838            vm_result: path(m, ["runtime", "VmResult"]),
839            vm_try: path(m, ["vm_try"]),
840            write: path(core, ["write"]),
841        }
842    }
843}
844
845fn parse_path_compat(input: ParseStream<'_>) -> syn::Result<syn::Path> {
846    if input.peek(syn::LitStr) {
847        let path = input
848            .parse::<syn::LitStr>()?
849            .parse_with(syn::Path::parse_mod_style)?;
850
851        return Err(syn::Error::new_spanned(
852            &path,
853            format_args!(
854                "String literals are no longer supported here, use a path like `{}`",
855                path.to_token_stream()
856            ),
857        ));
858    }
859
860    syn::Path::parse_mod_style(input)
861}
862
863fn path<const N: usize>(base: &syn::Path, path: [&'static str; N]) -> syn::Path {
864    let mut base = base.clone();
865
866    for s in path {
867        let ident = syn::Ident::new(s, base.span());
868        base.segments.push(syn::PathSegment::from(ident));
869    }
870
871    base
872}
873
874pub(crate) struct Tokens {
875    pub(crate) alloc: syn::Path,
876    pub(crate) any_marker_t: syn::Path,
877    pub(crate) any_t: syn::Path,
878    pub(crate) any_type_info: syn::Path,
879    pub(crate) arc: syn::Path,
880    pub(crate) compile_error: syn::Path,
881    pub(crate) const_construct_t: syn::Path,
882    pub(crate) const_value: syn::Path,
883    pub(crate) context_error: syn::Path,
884    pub(crate) double_ended_iterator: syn::Path,
885    pub(crate) fmt: syn::Path,
886    pub(crate) from_const_value_t: syn::Path,
887    pub(crate) from_value: syn::Path,
888    pub(crate) hash: syn::Path,
889    pub(crate) id: syn::Path,
890    pub(crate) install_with: syn::Path,
891    pub(crate) into_iterator: syn::Path,
892    pub(crate) item: syn::Path,
893    pub(crate) iterator: syn::Path,
894    pub(crate) macro_context: syn::Path,
895    pub(crate) maybe_type_of: syn::Path,
896    pub(crate) meta: syn::Path,
897    pub(crate) module: syn::Path,
898    pub(crate) named: syn::Path,
899    pub(crate) non_null: syn::Path,
900    pub(crate) object: syn::Path,
901    pub(crate) opaque: syn::Path,
902    pub(crate) option_spanned: syn::Path,
903    pub(crate) option: syn::Path,
904    pub(crate) owned_tuple: syn::Path,
905    pub(crate) parse: syn::Path,
906    pub(crate) parser: syn::Path,
907    pub(crate) protocol: syn::Path,
908    pub(crate) raw_value_guard: syn::Path,
909    pub(crate) result: syn::Path,
910    pub(crate) runtime_error: syn::Path,
911    pub(crate) span: syn::Path,
912    pub(crate) spanned: syn::Path,
913    pub(crate) string: syn::Path,
914    pub(crate) to_const_value_t: syn::Path,
915    pub(crate) to_tokens: syn::Path,
916    pub(crate) to_value: syn::Path,
917    pub(crate) token_stream: syn::Path,
918    pub(crate) try_clone: syn::Path,
919    pub(crate) try_from: syn::Path,
920    pub(crate) tuple: syn::Path,
921    pub(crate) type_hash_t: syn::Path,
922    pub(crate) type_name: syn::Path,
923    pub(crate) type_of: syn::Path,
924    pub(crate) type_value: syn::Path,
925    pub(crate) unsafe_to_mut: syn::Path,
926    pub(crate) unsafe_to_ref: syn::Path,
927    pub(crate) unsafe_to_value: syn::Path,
928    pub(crate) value_mut_guard: syn::Path,
929    pub(crate) value_ref_guard: syn::Path,
930    pub(crate) value: syn::Path,
931    pub(crate) vec: syn::Path,
932    pub(crate) vm_result: syn::Path,
933    pub(crate) vm_try: syn::Path,
934    pub(crate) write: syn::Path,
935}
936
937impl Tokens {
938    /// Define a tokenstream for the specified protocol
939    pub(crate) fn protocol(&self, sym: &Protocol) -> TokenStream {
940        let mut stream = TokenStream::default();
941        self.protocol.to_tokens(&mut stream);
942        <Token![::]>::default().to_tokens(&mut stream);
943        syn::Ident::new(sym.name, Span::call_site()).to_tokens(&mut stream);
944        stream
945    }
946}