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::None,
 36                },
 37            ]
 38            .into_iter()
 39            .collect(),
 40        },
 41    })
 42}
 43
 44/// Construct a [`syn::Type`] referring to `::xso::exports::rxml::NcNameStr`.
 45pub(crate) fn ncnamestr_ty(span: Span) -> Type {
 46    Type::Path(TypePath {
 47        qself: None,
 48        path: Path {
 49            leading_colon: Some(syn::token::PathSep {
 50                spans: [span, span],
 51            }),
 52            segments: [
 53                PathSegment {
 54                    ident: Ident::new("xso", span),
 55                    arguments: PathArguments::None,
 56                },
 57                PathSegment {
 58                    ident: Ident::new("exports", span),
 59                    arguments: PathArguments::None,
 60                },
 61                PathSegment {
 62                    ident: Ident::new("rxml", span),
 63                    arguments: PathArguments::None,
 64                },
 65                PathSegment {
 66                    ident: Ident::new("NcNameStr", span),
 67                    arguments: PathArguments::None,
 68                },
 69            ]
 70            .into_iter()
 71            .collect(),
 72        },
 73    })
 74}
 75
 76/// Construct a [`syn::Type`] referring to `Cow<#lifetime, #ty>`.
 77pub(crate) fn cow_ty(ty: Type, lifetime: Lifetime) -> Type {
 78    let span = ty.span();
 79    Type::Path(TypePath {
 80        qself: None,
 81        path: Path {
 82            leading_colon: Some(syn::token::PathSep {
 83                spans: [span, span],
 84            }),
 85            segments: [
 86                PathSegment {
 87                    ident: Ident::new("std", span),
 88                    arguments: PathArguments::None,
 89                },
 90                PathSegment {
 91                    ident: Ident::new("borrow", span),
 92                    arguments: PathArguments::None,
 93                },
 94                PathSegment {
 95                    ident: Ident::new("Cow", span),
 96                    arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
 97                        colon2_token: None,
 98                        lt_token: token::Lt { spans: [span] },
 99                        args: [
100                            GenericArgument::Lifetime(lifetime),
101                            GenericArgument::Type(ty),
102                        ]
103                        .into_iter()
104                        .collect(),
105                        gt_token: token::Gt { spans: [span] },
106                    }),
107                },
108            ]
109            .into_iter()
110            .collect(),
111        },
112    })
113}
114
115/// Construct a [`syn::Type`] referring to
116/// `Cow<#lifetime, ::rxml::NcNameStr>`.
117pub(crate) fn ncnamestr_cow_ty(ty_span: Span, lifetime: Lifetime) -> Type {
118    cow_ty(ncnamestr_ty(ty_span), lifetime)
119}
120
121/// Construct a [`syn::Expr`] referring to
122/// `<#ty as ::xso::FromXmlText>::from_xml_text`.
123pub(crate) fn from_xml_text_fn(ty: Type) -> Expr {
124    let span = ty.span();
125    Expr::Path(ExprPath {
126        attrs: Vec::new(),
127        qself: Some(QSelf {
128            lt_token: syn::token::Lt { spans: [span] },
129            ty: Box::new(ty),
130            position: 2,
131            as_token: Some(syn::token::As { span }),
132            gt_token: syn::token::Gt { spans: [span] },
133        }),
134        path: Path {
135            leading_colon: Some(syn::token::PathSep {
136                spans: [span, span],
137            }),
138            segments: [
139                PathSegment {
140                    ident: Ident::new("xso", span),
141                    arguments: PathArguments::None,
142                },
143                PathSegment {
144                    ident: Ident::new("FromXmlText", span),
145                    arguments: PathArguments::None,
146                },
147                PathSegment {
148                    ident: Ident::new("from_xml_text", span),
149                    arguments: PathArguments::None,
150                },
151            ]
152            .into_iter()
153            .collect(),
154        },
155    })
156}
157
158/// Construct a [`syn::Expr`] referring to
159/// `<#ty as ::xso::AsOptionalXmlText>::as_optional_xml_text`.
160pub(crate) fn as_optional_xml_text_fn(ty: Type) -> Expr {
161    let span = ty.span();
162    Expr::Path(ExprPath {
163        attrs: Vec::new(),
164        qself: Some(QSelf {
165            lt_token: syn::token::Lt { spans: [span] },
166            ty: Box::new(ty),
167            position: 2,
168            as_token: Some(syn::token::As { span }),
169            gt_token: syn::token::Gt { spans: [span] },
170        }),
171        path: Path {
172            leading_colon: Some(syn::token::PathSep {
173                spans: [span, span],
174            }),
175            segments: [
176                PathSegment {
177                    ident: Ident::new("xso", span),
178                    arguments: PathArguments::None,
179                },
180                PathSegment {
181                    ident: Ident::new("AsOptionalXmlText", span),
182                    arguments: PathArguments::None,
183                },
184                PathSegment {
185                    ident: Ident::new("as_optional_xml_text", span),
186                    arguments: PathArguments::None,
187                },
188            ]
189            .into_iter()
190            .collect(),
191        },
192    })
193}
194
195/// Construct a [`syn::Expr`] referring to
196/// `<#of_ty as ::std::default::Default>::default`.
197pub(crate) fn default_fn(of_ty: Type) -> Expr {
198    let span = of_ty.span();
199    Expr::Path(ExprPath {
200        attrs: Vec::new(),
201        qself: Some(QSelf {
202            lt_token: syn::token::Lt { spans: [span] },
203            ty: Box::new(of_ty),
204            position: 3,
205            as_token: Some(syn::token::As { span }),
206            gt_token: syn::token::Gt { spans: [span] },
207        }),
208        path: Path {
209            leading_colon: Some(syn::token::PathSep {
210                spans: [span, span],
211            }),
212            segments: [
213                PathSegment {
214                    ident: Ident::new("std", span),
215                    arguments: PathArguments::None,
216                },
217                PathSegment {
218                    ident: Ident::new("default", span),
219                    arguments: PathArguments::None,
220                },
221                PathSegment {
222                    ident: Ident::new("Default", span),
223                    arguments: PathArguments::None,
224                },
225                PathSegment {
226                    ident: Ident::new("default", span),
227                    arguments: PathArguments::None,
228                },
229            ]
230            .into_iter()
231            .collect(),
232        },
233    })
234}
235
236/// Construct a [`syn::Type`] referring to `::std::string::String`.
237pub(crate) fn string_ty(span: Span) -> Type {
238    Type::Path(TypePath {
239        qself: None,
240        path: Path {
241            leading_colon: Some(syn::token::PathSep {
242                spans: [span, span],
243            }),
244            segments: [
245                PathSegment {
246                    ident: Ident::new("std", span),
247                    arguments: PathArguments::None,
248                },
249                PathSegment {
250                    ident: Ident::new("string", span),
251                    arguments: PathArguments::None,
252                },
253                PathSegment {
254                    ident: Ident::new("String", span),
255                    arguments: PathArguments::None,
256                },
257            ]
258            .into_iter()
259            .collect(),
260        },
261    })
262}
263
264/// Construct a [`syn::Expr`] referring to
265/// `<#ty as ::xso::AsXmlText>::as_xml_text`.
266pub(crate) fn as_xml_text_fn(ty: Type) -> Expr {
267    let span = ty.span();
268    Expr::Path(ExprPath {
269        attrs: Vec::new(),
270        qself: Some(QSelf {
271            lt_token: syn::token::Lt { spans: [span] },
272            ty: Box::new(ty),
273            position: 2,
274            as_token: Some(syn::token::As { span }),
275            gt_token: syn::token::Gt { spans: [span] },
276        }),
277        path: Path {
278            leading_colon: Some(syn::token::PathSep {
279                spans: [span, span],
280            }),
281            segments: [
282                PathSegment {
283                    ident: Ident::new("xso", span),
284                    arguments: PathArguments::None,
285                },
286                PathSegment {
287                    ident: Ident::new("AsXmlText", span),
288                    arguments: PathArguments::None,
289                },
290                PathSegment {
291                    ident: Ident::new("as_xml_text", span),
292                    arguments: PathArguments::None,
293                },
294            ]
295            .into_iter()
296            .collect(),
297        },
298    })
299}
300
301/// Construct a [`syn::TypePath`] referring to
302/// `<#codec_ty as ::xso::TextCodec::<#for_ty>>` and return the
303/// [`syn::Span`] of the `codec_ty` alongside it.
304fn text_codec_of(codec_ty: Type, for_ty: Type) -> (Span, TypePath) {
305    let span = codec_ty.span();
306    (
307        span,
308        TypePath {
309            qself: Some(QSelf {
310                lt_token: syn::token::Lt { spans: [span] },
311                ty: Box::new(codec_ty),
312                position: 2,
313                as_token: Some(syn::token::As { span }),
314                gt_token: syn::token::Gt { spans: [span] },
315            }),
316            path: Path {
317                leading_colon: Some(syn::token::PathSep {
318                    spans: [span, span],
319                }),
320                segments: [
321                    PathSegment {
322                        ident: Ident::new("xso", span),
323                        arguments: PathArguments::None,
324                    },
325                    PathSegment {
326                        ident: Ident::new("TextCodec", span),
327                        arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
328                            colon2_token: Some(syn::token::PathSep {
329                                spans: [span, span],
330                            }),
331                            lt_token: syn::token::Lt { spans: [span] },
332                            args: [GenericArgument::Type(for_ty)].into_iter().collect(),
333                            gt_token: syn::token::Gt { spans: [span] },
334                        }),
335                    },
336                ]
337                .into_iter()
338                .collect(),
339            },
340        },
341    )
342}
343
344/// Construct a [`syn::Expr`] referring to
345/// `<#codec_ty as ::xso::TextCodec::<#for_ty>>::encode`.
346pub(crate) fn text_codec_encode_fn(codec_ty: Type, for_ty: Type) -> Expr {
347    let (span, mut ty) = text_codec_of(codec_ty, for_ty);
348    ty.path.segments.push(PathSegment {
349        ident: Ident::new("encode", span),
350        arguments: PathArguments::None,
351    });
352    Expr::Path(ExprPath {
353        attrs: Vec::new(),
354        qself: ty.qself,
355        path: ty.path,
356    })
357}
358
359/// Construct a [`syn::Expr`] referring to
360/// `<#codec_ty as ::xso::TextCodec::<#for_ty>>::decode`.
361pub(crate) fn text_codec_decode_fn(codec_ty: Type, for_ty: Type) -> Expr {
362    let (span, mut ty) = text_codec_of(codec_ty, for_ty);
363    ty.path.segments.push(PathSegment {
364        ident: Ident::new("decode", span),
365        arguments: PathArguments::None,
366    });
367    Expr::Path(ExprPath {
368        attrs: Vec::new(),
369        qself: ty.qself,
370        path: ty.path,
371    })
372}
373
374/// Construct a [`syn::Type`] for `&#lifetime #ty`.
375pub(crate) fn ref_ty(ty: Type, lifetime: Lifetime) -> Type {
376    let span = ty.span();
377    Type::Reference(TypeReference {
378        and_token: token::And { spans: [span] },
379        lifetime: Some(lifetime),
380        mutability: None,
381        elem: Box::new(ty),
382    })
383}
384
385/// Construct a [`syn::Type`] referring to
386/// `::std::marker::PhantomData<&#lifetime ()>`.
387pub(crate) fn phantom_lifetime_ty(lifetime: Lifetime) -> Type {
388    let span = lifetime.span();
389    let dummy = Type::Tuple(TypeTuple {
390        paren_token: token::Paren::default(),
391        elems: punctuated::Punctuated::default(),
392    });
393    Type::Path(TypePath {
394        qself: None,
395        path: Path {
396            leading_colon: Some(syn::token::PathSep {
397                spans: [span, span],
398            }),
399            segments: [
400                PathSegment {
401                    ident: Ident::new("std", span),
402                    arguments: PathArguments::None,
403                },
404                PathSegment {
405                    ident: Ident::new("marker", span),
406                    arguments: PathArguments::None,
407                },
408                PathSegment {
409                    ident: Ident::new("PhantomData", span),
410                    arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
411                        colon2_token: None,
412                        lt_token: token::Lt { spans: [span] },
413                        args: [GenericArgument::Type(ref_ty(dummy, lifetime))]
414                            .into_iter()
415                            .collect(),
416                        gt_token: token::Gt { spans: [span] },
417                    }),
418                },
419            ]
420            .into_iter()
421            .collect(),
422        },
423    })
424}
425
426/// Construct a [`syn::TypePath`] referring to
427/// `<#of_ty as ::xso::FromXml>`.
428fn from_xml_of(of_ty: Type) -> (Span, TypePath) {
429    let span = of_ty.span();
430    (
431        span,
432        TypePath {
433            qself: Some(QSelf {
434                lt_token: syn::token::Lt { spans: [span] },
435                ty: Box::new(of_ty),
436                position: 2,
437                as_token: Some(syn::token::As { span }),
438                gt_token: syn::token::Gt { spans: [span] },
439            }),
440            path: Path {
441                leading_colon: Some(syn::token::PathSep {
442                    spans: [span, span],
443                }),
444                segments: [
445                    PathSegment {
446                        ident: Ident::new("xso", span),
447                        arguments: PathArguments::None,
448                    },
449                    PathSegment {
450                        ident: Ident::new("FromXml", span),
451                        arguments: PathArguments::None,
452                    },
453                ]
454                .into_iter()
455                .collect(),
456            },
457        },
458    )
459}
460
461/// Construct a [`syn::Type`] referring to
462/// `<#of_ty as ::xso::FromXml>::Builder`.
463pub(crate) fn from_xml_builder_ty(of_ty: Type) -> Type {
464    let (span, mut ty) = from_xml_of(of_ty);
465    ty.path.segments.push(PathSegment {
466        ident: Ident::new("Builder", span),
467        arguments: PathArguments::None,
468    });
469    Type::Path(ty)
470}
471
472/// Construct a [`syn::Expr`] referring to
473/// `<#of_ty as ::xso::FromXml>::from_events`.
474pub(crate) fn from_events_fn(of_ty: Type) -> Expr {
475    let (span, mut ty) = from_xml_of(of_ty);
476    ty.path.segments.push(PathSegment {
477        ident: Ident::new("from_events", span),
478        arguments: PathArguments::None,
479    });
480    Expr::Path(ExprPath {
481        attrs: Vec::new(),
482        qself: ty.qself,
483        path: ty.path,
484    })
485}
486
487/// Construct a [`syn::Type`] which wraps the given `ty` in
488/// `::std::option::Option<_>`.
489pub(crate) fn option_ty(ty: Type) -> Type {
490    let span = ty.span();
491    Type::Path(TypePath {
492        qself: None,
493        path: Path {
494            leading_colon: Some(syn::token::PathSep {
495                spans: [span, span],
496            }),
497            segments: [
498                PathSegment {
499                    ident: Ident::new("std", span),
500                    arguments: PathArguments::None,
501                },
502                PathSegment {
503                    ident: Ident::new("option", span),
504                    arguments: PathArguments::None,
505                },
506                PathSegment {
507                    ident: Ident::new("Option", span),
508                    arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
509                        colon2_token: None,
510                        lt_token: syn::token::Lt { spans: [span] },
511                        args: [GenericArgument::Type(ty)].into_iter().collect(),
512                        gt_token: syn::token::Gt { spans: [span] },
513                    }),
514                },
515            ]
516            .into_iter()
517            .collect(),
518        },
519    })
520}
521
522/// Construct a [`syn::TypePath`] referring to
523/// `<#of_ty as ::xso::FromEventsBuilder>`.
524fn from_events_builder_of(of_ty: Type) -> (Span, TypePath) {
525    let span = of_ty.span();
526    (
527        span,
528        TypePath {
529            qself: Some(QSelf {
530                lt_token: syn::token::Lt { spans: [span] },
531                ty: Box::new(of_ty),
532                position: 2,
533                as_token: Some(syn::token::As { span }),
534                gt_token: syn::token::Gt { spans: [span] },
535            }),
536            path: Path {
537                leading_colon: Some(syn::token::PathSep {
538                    spans: [span, span],
539                }),
540                segments: [
541                    PathSegment {
542                        ident: Ident::new("xso", span),
543                        arguments: PathArguments::None,
544                    },
545                    PathSegment {
546                        ident: Ident::new("FromEventsBuilder", span),
547                        arguments: PathArguments::None,
548                    },
549                ]
550                .into_iter()
551                .collect(),
552            },
553        },
554    )
555}
556
557/// Construct a [`syn::Expr`] referring to
558/// `<#of_ty as ::xso::FromEventsBuilder>::feed`.
559pub(crate) fn feed_fn(of_ty: Type) -> Expr {
560    let (span, mut ty) = from_events_builder_of(of_ty);
561    ty.path.segments.push(PathSegment {
562        ident: Ident::new("feed", span),
563        arguments: PathArguments::None,
564    });
565    Expr::Path(ExprPath {
566        attrs: Vec::new(),
567        qself: ty.qself,
568        path: ty.path,
569    })
570}
571
572fn as_xml_of(of_ty: Type) -> (Span, TypePath) {
573    let span = of_ty.span();
574    (
575        span,
576        TypePath {
577            qself: Some(QSelf {
578                lt_token: syn::token::Lt { spans: [span] },
579                ty: Box::new(of_ty),
580                position: 2,
581                as_token: Some(syn::token::As { span }),
582                gt_token: syn::token::Gt { spans: [span] },
583            }),
584            path: Path {
585                leading_colon: Some(syn::token::PathSep {
586                    spans: [span, span],
587                }),
588                segments: [
589                    PathSegment {
590                        ident: Ident::new("xso", span),
591                        arguments: PathArguments::None,
592                    },
593                    PathSegment {
594                        ident: Ident::new("AsXml", span),
595                        arguments: PathArguments::None,
596                    },
597                ]
598                .into_iter()
599                .collect(),
600            },
601        },
602    )
603}
604
605/// Construct a [`syn::Expr`] referring to
606/// `<#of_ty as ::xso::AsXml>::as_xml_iter`.
607pub(crate) fn as_xml_iter_fn(of_ty: Type) -> Expr {
608    let (span, mut ty) = as_xml_of(of_ty);
609    ty.path.segments.push(PathSegment {
610        ident: Ident::new("as_xml_iter", span),
611        arguments: PathArguments::None,
612    });
613    Expr::Path(ExprPath {
614        attrs: Vec::new(),
615        qself: ty.qself,
616        path: ty.path,
617    })
618}
619
620/// Construct a [`syn::Type`] referring to
621/// `<#of_ty as ::xso::AsXml>::ItemIter`.
622pub(crate) fn item_iter_ty(of_ty: Type, lifetime: Lifetime) -> Type {
623    let (span, mut ty) = as_xml_of(of_ty);
624    ty.path.segments.push(PathSegment {
625        ident: Ident::new("ItemIter", span),
626        arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
627            colon2_token: None,
628            lt_token: token::Lt { spans: [span] },
629            args: [GenericArgument::Lifetime(lifetime)].into_iter().collect(),
630            gt_token: token::Gt { spans: [span] },
631        }),
632    });
633    Type::Path(ty)
634}