xso_proc/
types.rs

1// Copyright (c) 2024 Jonas Schäfer <jonas@zombofant.net>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7//! Module with specific [`syn::Type`] constructors.
8
9use proc_macro2::Span;
10use syn::{spanned::Spanned, *};
11
12/// Construct a [`syn::Type`] referring to `::xso::exports::rxml::Namespace`.
13pub(crate) fn namespace_ty(span: Span) -> Type {
14    Type::Path(TypePath {
15        qself: None,
16        path: Path {
17            leading_colon: Some(syn::token::PathSep {
18                spans: [span, span],
19            }),
20            segments: [
21                PathSegment {
22                    ident: Ident::new("xso", span),
23                    arguments: PathArguments::None,
24                },
25                PathSegment {
26                    ident: Ident::new("exports", span),
27                    arguments: PathArguments::None,
28                },
29                PathSegment {
30                    ident: Ident::new("rxml", span),
31                    arguments: PathArguments::None,
32                },
33                PathSegment {
34                    ident: Ident::new("Namespace", span),
35                    arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
36                        colon2_token: None,
37                        lt_token: token::Lt { spans: [span] },
38                        args: [GenericArgument::Lifetime(Lifetime {
39                            apostrophe: Span::call_site(),
40                            ident: Ident::new("static", Span::call_site()),
41                        })]
42                        .into_iter()
43                        .collect(),
44                        gt_token: token::Gt { spans: [span] },
45                    }),
46                },
47            ]
48            .into_iter()
49            .collect(),
50        },
51    })
52}
53
54/// Construct a [`syn::Type`] referring to `::xso::exports::rxml::NcNameStr`.
55pub(crate) fn ncnamestr_ty(span: Span) -> Type {
56    Type::Path(TypePath {
57        qself: None,
58        path: Path {
59            leading_colon: Some(syn::token::PathSep {
60                spans: [span, span],
61            }),
62            segments: [
63                PathSegment {
64                    ident: Ident::new("xso", span),
65                    arguments: PathArguments::None,
66                },
67                PathSegment {
68                    ident: Ident::new("exports", span),
69                    arguments: PathArguments::None,
70                },
71                PathSegment {
72                    ident: Ident::new("rxml", span),
73                    arguments: PathArguments::None,
74                },
75                PathSegment {
76                    ident: Ident::new("NcNameStr", span),
77                    arguments: PathArguments::None,
78                },
79            ]
80            .into_iter()
81            .collect(),
82        },
83    })
84}
85
86/// Construct a [`syn::Type`] referring to `Cow<#lifetime, #ty>`.
87pub(crate) fn cow_ty(ty: Type, lifetime: Lifetime) -> Type {
88    let span = ty.span();
89    Type::Path(TypePath {
90        qself: None,
91        path: Path {
92            leading_colon: Some(syn::token::PathSep {
93                spans: [span, span],
94            }),
95            segments: [
96                PathSegment {
97                    ident: Ident::new("xso", span),
98                    arguments: PathArguments::None,
99                },
100                PathSegment {
101                    ident: Ident::new("exports", span),
102                    arguments: PathArguments::None,
103                },
104                PathSegment {
105                    ident: Ident::new("alloc", span),
106                    arguments: PathArguments::None,
107                },
108                PathSegment {
109                    ident: Ident::new("borrow", span),
110                    arguments: PathArguments::None,
111                },
112                PathSegment {
113                    ident: Ident::new("Cow", span),
114                    arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
115                        colon2_token: None,
116                        lt_token: token::Lt { spans: [span] },
117                        args: [
118                            GenericArgument::Lifetime(lifetime),
119                            GenericArgument::Type(ty),
120                        ]
121                        .into_iter()
122                        .collect(),
123                        gt_token: token::Gt { spans: [span] },
124                    }),
125                },
126            ]
127            .into_iter()
128            .collect(),
129        },
130    })
131}
132
133/// Construct a [`syn::Type`] referring to
134/// `Cow<#lifetime, ::rxml::NcNameStr>`.
135pub(crate) fn ncnamestr_cow_ty(ty_span: Span, lifetime: Lifetime) -> Type {
136    cow_ty(ncnamestr_ty(ty_span), lifetime)
137}
138
139/// Construct a [`syn::Expr`] referring to
140/// `<#ty as ::xso::FromXmlText>::from_xml_text`.
141pub(crate) fn from_xml_text_fn(ty: Type) -> Expr {
142    let span = ty.span();
143    Expr::Path(ExprPath {
144        attrs: Vec::new(),
145        qself: Some(QSelf {
146            lt_token: syn::token::Lt { spans: [span] },
147            ty: Box::new(ty),
148            position: 2,
149            as_token: Some(syn::token::As { span }),
150            gt_token: syn::token::Gt { spans: [span] },
151        }),
152        path: Path {
153            leading_colon: Some(syn::token::PathSep {
154                spans: [span, span],
155            }),
156            segments: [
157                PathSegment {
158                    ident: Ident::new("xso", span),
159                    arguments: PathArguments::None,
160                },
161                PathSegment {
162                    ident: Ident::new("FromXmlText", span),
163                    arguments: PathArguments::None,
164                },
165                PathSegment {
166                    ident: Ident::new("from_xml_text", span),
167                    arguments: PathArguments::None,
168                },
169            ]
170            .into_iter()
171            .collect(),
172        },
173    })
174}
175
176/// Construct a [`syn::Expr`] referring to
177/// `<#ty as ::xso::AsOptionalXmlText>::as_optional_xml_text`.
178pub(crate) fn as_optional_xml_text_fn(ty: Type) -> Expr {
179    let span = ty.span();
180    Expr::Path(ExprPath {
181        attrs: Vec::new(),
182        qself: Some(QSelf {
183            lt_token: syn::token::Lt { spans: [span] },
184            ty: Box::new(ty),
185            position: 2,
186            as_token: Some(syn::token::As { span }),
187            gt_token: syn::token::Gt { spans: [span] },
188        }),
189        path: Path {
190            leading_colon: Some(syn::token::PathSep {
191                spans: [span, span],
192            }),
193            segments: [
194                PathSegment {
195                    ident: Ident::new("xso", span),
196                    arguments: PathArguments::None,
197                },
198                PathSegment {
199                    ident: Ident::new("AsOptionalXmlText", span),
200                    arguments: PathArguments::None,
201                },
202                PathSegment {
203                    ident: Ident::new("as_optional_xml_text", span),
204                    arguments: PathArguments::None,
205                },
206            ]
207            .into_iter()
208            .collect(),
209        },
210    })
211}
212
213/// Construct a [`syn::Expr`] referring to
214/// `<#of_ty as ::core::default::Default>::default`.
215pub(crate) fn default_fn(of_ty: Type) -> Expr {
216    let span = of_ty.span();
217    Expr::Path(ExprPath {
218        attrs: Vec::new(),
219        qself: Some(QSelf {
220            lt_token: syn::token::Lt { spans: [span] },
221            ty: Box::new(of_ty),
222            position: 3,
223            as_token: Some(syn::token::As { span }),
224            gt_token: syn::token::Gt { spans: [span] },
225        }),
226        path: Path {
227            leading_colon: Some(syn::token::PathSep {
228                spans: [span, span],
229            }),
230            segments: [
231                PathSegment {
232                    ident: Ident::new("core", span),
233                    arguments: PathArguments::None,
234                },
235                PathSegment {
236                    ident: Ident::new("default", span),
237                    arguments: PathArguments::None,
238                },
239                PathSegment {
240                    ident: Ident::new("Default", span),
241                    arguments: PathArguments::None,
242                },
243                PathSegment {
244                    ident: Ident::new("default", span),
245                    arguments: PathArguments::None,
246                },
247            ]
248            .into_iter()
249            .collect(),
250        },
251    })
252}
253
254/// Construct a [`syn::Type`] referring to `::alloc::string::String`.
255pub(crate) fn string_ty(span: Span) -> Type {
256    Type::Path(TypePath {
257        qself: None,
258        path: Path {
259            leading_colon: Some(syn::token::PathSep {
260                spans: [span, span],
261            }),
262            segments: [
263                PathSegment {
264                    ident: Ident::new("xso", span),
265                    arguments: PathArguments::None,
266                },
267                PathSegment {
268                    ident: Ident::new("exports", span),
269                    arguments: PathArguments::None,
270                },
271                PathSegment {
272                    ident: Ident::new("alloc", span),
273                    arguments: PathArguments::None,
274                },
275                PathSegment {
276                    ident: Ident::new("string", span),
277                    arguments: PathArguments::None,
278                },
279                PathSegment {
280                    ident: Ident::new("String", span),
281                    arguments: PathArguments::None,
282                },
283            ]
284            .into_iter()
285            .collect(),
286        },
287    })
288}
289
290/// Construct a [`syn::Expr`] referring to
291/// `<#ty as ::xso::AsXmlText>::as_xml_text`.
292pub(crate) fn as_xml_text_fn(ty: Type) -> Expr {
293    let span = ty.span();
294    Expr::Path(ExprPath {
295        attrs: Vec::new(),
296        qself: Some(QSelf {
297            lt_token: syn::token::Lt { spans: [span] },
298            ty: Box::new(ty),
299            position: 2,
300            as_token: Some(syn::token::As { span }),
301            gt_token: syn::token::Gt { spans: [span] },
302        }),
303        path: Path {
304            leading_colon: Some(syn::token::PathSep {
305                spans: [span, span],
306            }),
307            segments: [
308                PathSegment {
309                    ident: Ident::new("xso", span),
310                    arguments: PathArguments::None,
311                },
312                PathSegment {
313                    ident: Ident::new("AsXmlText", span),
314                    arguments: PathArguments::None,
315                },
316                PathSegment {
317                    ident: Ident::new("as_xml_text", span),
318                    arguments: PathArguments::None,
319                },
320            ]
321            .into_iter()
322            .collect(),
323        },
324    })
325}
326
327/// Construct a [`syn::Path`] referring to `::xso::TextCodec::<#for_ty>`,
328/// returning the span of `for_ty` alongside it.
329///
330/// The span used is `codec_span`, in order to ensure that error messages
331/// about a missing implementation point at the codec, not at the type.
332fn text_codec_of(for_ty: Type, codec_span: Span) -> Path {
333    let span = codec_span;
334    Path {
335        leading_colon: Some(syn::token::PathSep {
336            spans: [span, span],
337        }),
338        segments: [
339            PathSegment {
340                ident: Ident::new("xso", span),
341                arguments: PathArguments::None,
342            },
343            PathSegment {
344                ident: Ident::new("TextCodec", span),
345                arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
346                    colon2_token: Some(syn::token::PathSep {
347                        spans: [span, span],
348                    }),
349                    lt_token: syn::token::Lt { spans: [span] },
350                    args: [GenericArgument::Type(for_ty)].into_iter().collect(),
351                    gt_token: syn::token::Gt { spans: [span] },
352                }),
353            },
354        ]
355        .into_iter()
356        .collect(),
357    }
358}
359
360/// Construct a [`syn::Expr`] referring to
361/// `::xso::TextCodec::<#for_ty>::encode`.
362///
363/// The span used is `codec_span`, in order to ensure that error messages
364/// about a missing implementation point at the codec, not at the type.
365pub(crate) fn text_codec_encode_fn(for_ty: Type, codec_span: Span) -> Expr {
366    let mut path = text_codec_of(for_ty, codec_span);
367    path.segments.push(PathSegment {
368        ident: Ident::new("encode", codec_span),
369        arguments: PathArguments::None,
370    });
371    Expr::Path(ExprPath {
372        attrs: Vec::new(),
373        qself: None,
374        path,
375    })
376}
377
378/// Construct a [`syn::Expr`] referring to
379/// `::xso::TextCodec::<#for_ty>::decode`.
380///
381/// The span used is `codec_span`, in order to ensure that error messages
382/// about a missing implementation point at the codec, not at the type.
383pub(crate) fn text_codec_decode_fn(for_ty: Type, codec_span: Span) -> Expr {
384    let mut path = text_codec_of(for_ty, codec_span);
385    path.segments.push(PathSegment {
386        ident: Ident::new("decode", codec_span),
387        arguments: PathArguments::None,
388    });
389    Expr::Path(ExprPath {
390        attrs: Vec::new(),
391        qself: None,
392        path,
393    })
394}
395
396/// Construct a [`syn::Type`] for `&#lifetime #ty`.
397pub(crate) fn ref_ty(ty: Type, lifetime: Lifetime) -> Type {
398    let span = ty.span();
399    Type::Reference(TypeReference {
400        and_token: token::And { spans: [span] },
401        lifetime: Some(lifetime),
402        mutability: None,
403        elem: Box::new(ty),
404    })
405}
406
407/// Construct a [`syn::Type`] referring to
408/// `::core::marker::PhantomData<&#lifetime ()>`.
409pub(crate) fn phantom_lifetime_ty(lifetime: Lifetime) -> Type {
410    let span = lifetime.span();
411    let dummy = Type::Tuple(TypeTuple {
412        paren_token: token::Paren::default(),
413        elems: punctuated::Punctuated::default(),
414    });
415    Type::Path(TypePath {
416        qself: None,
417        path: Path {
418            leading_colon: Some(syn::token::PathSep {
419                spans: [span, span],
420            }),
421            segments: [
422                PathSegment {
423                    ident: Ident::new("core", span),
424                    arguments: PathArguments::None,
425                },
426                PathSegment {
427                    ident: Ident::new("marker", span),
428                    arguments: PathArguments::None,
429                },
430                PathSegment {
431                    ident: Ident::new("PhantomData", span),
432                    arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
433                        colon2_token: None,
434                        lt_token: token::Lt { spans: [span] },
435                        args: [GenericArgument::Type(ref_ty(dummy, lifetime))]
436                            .into_iter()
437                            .collect(),
438                        gt_token: token::Gt { spans: [span] },
439                    }),
440                },
441            ]
442            .into_iter()
443            .collect(),
444        },
445    })
446}
447
448/// Construct a [`syn::TypePath`] referring to
449/// `<#of_ty as ::xso::FromXml>`.
450fn from_xml_of(of_ty: Type) -> (Span, TypePath) {
451    let span = of_ty.span();
452    (
453        span,
454        TypePath {
455            qself: Some(QSelf {
456                lt_token: syn::token::Lt { spans: [span] },
457                ty: Box::new(of_ty),
458                position: 2,
459                as_token: Some(syn::token::As { span }),
460                gt_token: syn::token::Gt { spans: [span] },
461            }),
462            path: Path {
463                leading_colon: Some(syn::token::PathSep {
464                    spans: [span, span],
465                }),
466                segments: [
467                    PathSegment {
468                        ident: Ident::new("xso", span),
469                        arguments: PathArguments::None,
470                    },
471                    PathSegment {
472                        ident: Ident::new("FromXml", span),
473                        arguments: PathArguments::None,
474                    },
475                ]
476                .into_iter()
477                .collect(),
478            },
479        },
480    )
481}
482
483/// Construct a [`syn::Type`] referring to
484/// `<#of_ty as ::xso::FromXml>::Builder`.
485pub(crate) fn from_xml_builder_ty(of_ty: Type) -> Type {
486    let (span, mut ty) = from_xml_of(of_ty);
487    ty.path.segments.push(PathSegment {
488        ident: Ident::new("Builder", span),
489        arguments: PathArguments::None,
490    });
491    Type::Path(ty)
492}
493
494/// Construct a [`syn::Expr`] referring to
495/// `<#of_ty as ::xso::FromXml>::from_events`.
496pub(crate) fn from_events_fn(of_ty: Type) -> Expr {
497    let (span, mut ty) = from_xml_of(of_ty);
498    ty.path.segments.push(PathSegment {
499        ident: Ident::new("from_events", span),
500        arguments: PathArguments::None,
501    });
502    Expr::Path(ExprPath {
503        attrs: Vec::new(),
504        qself: ty.qself,
505        path: ty.path,
506    })
507}
508
509/// Construct a [`syn::Type`] which wraps the given `ty` in
510/// `::core::option::Option<_>`.
511pub(crate) fn option_ty(ty: Type) -> Type {
512    let span = ty.span();
513    Type::Path(TypePath {
514        qself: None,
515        path: Path {
516            leading_colon: Some(syn::token::PathSep {
517                spans: [span, span],
518            }),
519            segments: [
520                PathSegment {
521                    ident: Ident::new("core", span),
522                    arguments: PathArguments::None,
523                },
524                PathSegment {
525                    ident: Ident::new("option", span),
526                    arguments: PathArguments::None,
527                },
528                PathSegment {
529                    ident: Ident::new("Option", span),
530                    arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
531                        colon2_token: None,
532                        lt_token: syn::token::Lt { spans: [span] },
533                        args: [GenericArgument::Type(ty)].into_iter().collect(),
534                        gt_token: syn::token::Gt { spans: [span] },
535                    }),
536                },
537            ]
538            .into_iter()
539            .collect(),
540        },
541    })
542}
543
544/// Construct a [`syn::TypePath`] referring to
545/// `<#of_ty as ::xso::FromEventsBuilder>`.
546fn from_events_builder_of(of_ty: Type) -> (Span, TypePath) {
547    let span = of_ty.span();
548    (
549        span,
550        TypePath {
551            qself: Some(QSelf {
552                lt_token: syn::token::Lt { spans: [span] },
553                ty: Box::new(of_ty),
554                position: 2,
555                as_token: Some(syn::token::As { span }),
556                gt_token: syn::token::Gt { spans: [span] },
557            }),
558            path: Path {
559                leading_colon: Some(syn::token::PathSep {
560                    spans: [span, span],
561                }),
562                segments: [
563                    PathSegment {
564                        ident: Ident::new("xso", span),
565                        arguments: PathArguments::None,
566                    },
567                    PathSegment {
568                        ident: Ident::new("FromEventsBuilder", span),
569                        arguments: PathArguments::None,
570                    },
571                ]
572                .into_iter()
573                .collect(),
574            },
575        },
576    )
577}
578
579/// Construct a [`syn::Expr`] referring to
580/// `<#of_ty as ::xso::FromEventsBuilder>::feed`.
581pub(crate) fn feed_fn(of_ty: Type) -> Expr {
582    let (span, mut ty) = from_events_builder_of(of_ty);
583    ty.path.segments.push(PathSegment {
584        ident: Ident::new("feed", span),
585        arguments: PathArguments::None,
586    });
587    Expr::Path(ExprPath {
588        attrs: Vec::new(),
589        qself: ty.qself,
590        path: ty.path,
591    })
592}
593
594fn as_xml_of(of_ty: Type) -> (Span, TypePath) {
595    let span = of_ty.span();
596    (
597        span,
598        TypePath {
599            qself: Some(QSelf {
600                lt_token: syn::token::Lt { spans: [span] },
601                ty: Box::new(of_ty),
602                position: 2,
603                as_token: Some(syn::token::As { span }),
604                gt_token: syn::token::Gt { spans: [span] },
605            }),
606            path: Path {
607                leading_colon: Some(syn::token::PathSep {
608                    spans: [span, span],
609                }),
610                segments: [
611                    PathSegment {
612                        ident: Ident::new("xso", span),
613                        arguments: PathArguments::None,
614                    },
615                    PathSegment {
616                        ident: Ident::new("AsXml", span),
617                        arguments: PathArguments::None,
618                    },
619                ]
620                .into_iter()
621                .collect(),
622            },
623        },
624    )
625}
626
627/// Construct a [`syn::Expr`] referring to
628/// `<#of_ty as ::xso::AsXml>::as_xml_iter`.
629pub(crate) fn as_xml_iter_fn(of_ty: Type) -> Expr {
630    let (span, mut ty) = as_xml_of(of_ty);
631    ty.path.segments.push(PathSegment {
632        ident: Ident::new("as_xml_iter", span),
633        arguments: PathArguments::None,
634    });
635    Expr::Path(ExprPath {
636        attrs: Vec::new(),
637        qself: ty.qself,
638        path: ty.path,
639    })
640}
641
642/// Construct a [`syn::Type`] referring to
643/// `<#of_ty as ::xso::AsXml>::ItemIter`.
644pub(crate) fn item_iter_ty(of_ty: Type, lifetime: Lifetime) -> Type {
645    let (span, mut ty) = as_xml_of(of_ty);
646    ty.path.segments.push(PathSegment {
647        ident: Ident::new("ItemIter", span),
648        arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
649            colon2_token: None,
650            lt_token: token::Lt { spans: [span] },
651            args: [GenericArgument::Lifetime(lifetime)].into_iter().collect(),
652            gt_token: token::Gt { spans: [span] },
653        }),
654    });
655    Type::Path(ty)
656}
657
658/// Construct a [`syn::TypePath`] referring to `<#of_ty as IntoIterator>`.
659fn into_iterator_of(of_ty: Type) -> (Span, TypePath) {
660    let span = of_ty.span();
661    (
662        span,
663        TypePath {
664            qself: Some(QSelf {
665                lt_token: syn::token::Lt { spans: [span] },
666                ty: Box::new(of_ty),
667                position: 3,
668                as_token: Some(syn::token::As { span }),
669                gt_token: syn::token::Gt { spans: [span] },
670            }),
671            path: Path {
672                leading_colon: Some(syn::token::PathSep {
673                    spans: [span, span],
674                }),
675                segments: [
676                    PathSegment {
677                        ident: Ident::new("core", span),
678                        arguments: PathArguments::None,
679                    },
680                    PathSegment {
681                        ident: Ident::new("iter", span),
682                        arguments: PathArguments::None,
683                    },
684                    PathSegment {
685                        ident: Ident::new("IntoIterator", span),
686                        arguments: PathArguments::None,
687                    },
688                ]
689                .into_iter()
690                .collect(),
691            },
692        },
693    )
694}
695
696/// Construct a [`syn::Type`] referring to
697/// `<#of_ty as IntoIterator>::IntoIter`.
698pub(crate) fn into_iterator_iter_ty(of_ty: Type) -> Type {
699    let (span, mut ty) = into_iterator_of(of_ty);
700    ty.path.segments.push(PathSegment {
701        ident: Ident::new("IntoIter", span),
702        arguments: PathArguments::None,
703    });
704    Type::Path(ty)
705}
706
707/// Construct a [`syn::Type`] referring to
708/// `<#of_ty as IntoIterator>::Item`.
709pub(crate) fn into_iterator_item_ty(of_ty: Type) -> Type {
710    let (span, mut ty) = into_iterator_of(of_ty);
711    ty.path.segments.push(PathSegment {
712        ident: Ident::new("Item", span),
713        arguments: PathArguments::None,
714    });
715    Type::Path(ty)
716}
717
718/// Construct a [`syn::Expr`] referring to
719/// `<#of_ty as IntoIterator>::into_iter`.
720pub(crate) fn into_iterator_into_iter_fn(of_ty: Type) -> Expr {
721    let (span, mut ty) = into_iterator_of(of_ty);
722    ty.path.segments.push(PathSegment {
723        ident: Ident::new("into_iter", span),
724        arguments: PathArguments::None,
725    });
726    Expr::Path(ExprPath {
727        attrs: Vec::new(),
728        qself: ty.qself,
729        path: ty.path,
730    })
731}
732
733/// Construct a [`syn::Expr`] referring to
734/// `<#of_ty as ::core::iter::Extend>::extend`.
735pub(crate) fn extend_fn(of_ty: Type, item_ty: Type) -> Expr {
736    let span = of_ty.span();
737    Expr::Path(ExprPath {
738        attrs: Vec::new(),
739        qself: Some(QSelf {
740            lt_token: syn::token::Lt { spans: [span] },
741            ty: Box::new(of_ty),
742            position: 3,
743            as_token: Some(syn::token::As { span }),
744            gt_token: syn::token::Gt { spans: [span] },
745        }),
746        path: Path {
747            leading_colon: Some(syn::token::PathSep {
748                spans: [span, span],
749            }),
750            segments: [
751                PathSegment {
752                    ident: Ident::new("core", span),
753                    arguments: PathArguments::None,
754                },
755                PathSegment {
756                    ident: Ident::new("iter", span),
757                    arguments: PathArguments::None,
758                },
759                PathSegment {
760                    ident: Ident::new("Extend", span),
761                    arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
762                        colon2_token: Some(syn::token::PathSep {
763                            spans: [span, span],
764                        }),
765                        lt_token: syn::token::Lt { spans: [span] },
766                        args: [GenericArgument::Type(item_ty)].into_iter().collect(),
767                        gt_token: syn::token::Gt { spans: [span] },
768                    }),
769                },
770                PathSegment {
771                    ident: Ident::new("extend", span),
772                    arguments: PathArguments::None,
773                },
774            ]
775            .into_iter()
776            .collect(),
777        },
778    })
779}
780
781/// Construct a [`syn::TypePath`] which references the given type name.
782pub(crate) fn ty_from_ident(ident: Ident) -> TypePath {
783    TypePath {
784        qself: None,
785        path: ident.into(),
786    }
787}
788
789/// Construct a [`syn::Type`] referring to `xso::OptionAsXml<#inner_ty>`.
790pub(crate) fn option_as_xml_ty(inner_ty: Type) -> Type {
791    let span = inner_ty.span();
792    Type::Path(TypePath {
793        qself: None,
794        path: Path {
795            leading_colon: Some(syn::token::PathSep {
796                spans: [span, span],
797            }),
798            segments: [
799                PathSegment {
800                    ident: Ident::new("xso", span),
801                    arguments: PathArguments::None,
802                },
803                PathSegment {
804                    ident: Ident::new("asxml", span),
805                    arguments: PathArguments::None,
806                },
807                PathSegment {
808                    ident: Ident::new("OptionAsXml", span),
809                    arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
810                        colon2_token: None,
811                        lt_token: token::Lt { spans: [span] },
812                        args: [GenericArgument::Type(inner_ty)].into_iter().collect(),
813                        gt_token: token::Gt { spans: [span] },
814                    }),
815                },
816            ]
817            .into_iter()
818            .collect(),
819        },
820    })
821}
822
823/// Construct a [`syn::Type`] referring to `::xso::exports::minidom::Element`.
824#[cfg(feature = "minidom")]
825pub(crate) fn element_ty(span: Span) -> Type {
826    Type::Path(TypePath {
827        qself: None,
828        path: Path {
829            leading_colon: Some(syn::token::PathSep {
830                spans: [span, span],
831            }),
832            segments: [
833                PathSegment {
834                    ident: Ident::new("xso", span),
835                    arguments: PathArguments::None,
836                },
837                PathSegment {
838                    ident: Ident::new("exports", span),
839                    arguments: PathArguments::None,
840                },
841                PathSegment {
842                    ident: Ident::new("minidom", span),
843                    arguments: PathArguments::None,
844                },
845                PathSegment {
846                    ident: Ident::new("Element", span),
847                    arguments: PathArguments::None,
848                },
849            ]
850            .into_iter()
851            .collect(),
852        },
853    })
854}
855
856/// Construct a [`syn::Path`] referring to `::xso::UnknownAttributePolicy`.
857pub(crate) fn unknown_attribute_policy_path(span: Span) -> Path {
858    Path {
859        leading_colon: Some(syn::token::PathSep {
860            spans: [span, span],
861        }),
862        segments: [
863            PathSegment {
864                ident: Ident::new("xso", span),
865                arguments: PathArguments::None,
866            },
867            PathSegment {
868                ident: Ident::new("UnknownAttributePolicy", span),
869                arguments: PathArguments::None,
870            },
871        ]
872        .into_iter()
873        .collect(),
874    }
875}
876
877/// Construct a [`syn::Path`] referring to `::xso::UnknownChildPolicy`.
878pub(crate) fn unknown_child_policy_path(span: Span) -> Path {
879    Path {
880        leading_colon: Some(syn::token::PathSep {
881            spans: [span, span],
882        }),
883        segments: [
884            PathSegment {
885                ident: Ident::new("xso", span),
886                arguments: PathArguments::None,
887            },
888            PathSegment {
889                ident: Ident::new("UnknownChildPolicy", span),
890                arguments: PathArguments::None,
891            },
892        ]
893        .into_iter()
894        .collect(),
895    }
896}
897
898/// Construct a [`syn::Type`] referring to `::xso::fromxml::Discard`.
899pub(crate) fn discard_builder_ty(span: Span) -> Type {
900    Type::Path(TypePath {
901        qself: None,
902        path: Path {
903            leading_colon: Some(syn::token::PathSep {
904                spans: [span, span],
905            }),
906            segments: [
907                PathSegment {
908                    ident: Ident::new("xso", span),
909                    arguments: PathArguments::None,
910                },
911                PathSegment {
912                    ident: Ident::new("fromxml", span),
913                    arguments: PathArguments::None,
914                },
915                PathSegment {
916                    ident: Ident::new("Discard", span),
917                    arguments: PathArguments::None,
918                },
919            ]
920            .into_iter()
921            .collect(),
922        },
923    })
924}
925
926/// Construct a [`syn::Type`] referring to the built-in `bool` type.
927///
928/// Note that we go through `xso::exports::CoreBool` for that, because there seems
929/// to be no way to access built-in types once they have been shadowed in a
930/// scope.
931pub(crate) fn bool_ty(span: Span) -> Type {
932    Type::Path(TypePath {
933        qself: None,
934        path: Path {
935            leading_colon: Some(syn::token::PathSep {
936                spans: [span, span],
937            }),
938            segments: [
939                PathSegment {
940                    ident: Ident::new("xso", span),
941                    arguments: PathArguments::None,
942                },
943                PathSegment {
944                    ident: Ident::new("exports", span),
945                    arguments: PathArguments::None,
946                },
947                PathSegment {
948                    ident: Ident::new("CoreBool", span),
949                    arguments: PathArguments::None,
950                },
951            ]
952            .into_iter()
953            .collect(),
954        },
955    })
956}
957
958/// Construct a [`syn::Type`] referring to the built-in `u8` type.
959///
960/// Note that we go through `xso::exports::CoreU8` for that, because there seems
961/// to be no way to access built-in types once they have been shadowed in a
962/// scope.
963pub(crate) fn u8_ty(span: Span) -> Type {
964    Type::Path(TypePath {
965        qself: None,
966        path: Path {
967            leading_colon: Some(syn::token::PathSep {
968                spans: [span, span],
969            }),
970            segments: [
971                PathSegment {
972                    ident: Ident::new("xso", span),
973                    arguments: PathArguments::None,
974                },
975                PathSegment {
976                    ident: Ident::new("exports", span),
977                    arguments: PathArguments::None,
978                },
979                PathSegment {
980                    ident: Ident::new("CoreU8", span),
981                    arguments: PathArguments::None,
982                },
983            ]
984            .into_iter()
985            .collect(),
986        },
987    })
988}
989
990/// Construct a [`syn::Type`] referring to `::xso::fromxml::EmptyBuilder`.
991pub(crate) fn empty_builder_ty(span: Span) -> Type {
992    Type::Path(TypePath {
993        qself: None,
994        path: Path {
995            leading_colon: Some(syn::token::PathSep {
996                spans: [span, span],
997            }),
998            segments: [
999                PathSegment {
1000                    ident: Ident::new("xso", span),
1001                    arguments: PathArguments::None,
1002                },
1003                PathSegment {
1004                    ident: Ident::new("fromxml", span),
1005                    arguments: PathArguments::None,
1006                },
1007                PathSegment {
1008                    ident: Ident::new("EmptyBuilder", span),
1009                    arguments: PathArguments::None,
1010                },
1011            ]
1012            .into_iter()
1013            .collect(),
1014        },
1015    })
1016}