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}