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}