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//! # Parse Rust attributes
8//!
9//! This module is concerned with parsing attributes from the Rust "meta"
10//! annotations on structs, enums, enum variants and fields.
11
12use core::hash::{Hash, Hasher};
13
14use proc_macro2::{Span, TokenStream};
15use quote::{quote, quote_spanned};
16use syn::{meta::ParseNestedMeta, spanned::Spanned, *};
17
18use rxml_validation::NcName;
19
20/// XML core namespace URI (for the `xml:` prefix)
21pub const XMLNS_XML: &str = "http://www.w3.org/XML/1998/namespace";
22/// XML namespace URI (for the `xmlns:` prefix)
23pub const XMLNS_XMLNS: &str = "http://www.w3.org/2000/xmlns/";
24
25macro_rules! reject_key {
26 ($key:ident not on $not_allowed_on:literal $(only on $only_allowed_on:literal)?) => {
27 if let Some(ref $key) = $key {
28 return Err(Error::new_spanned(
29 $key,
30 concat!(
31 "`",
32 stringify!($key),
33 "` is not allowed on ",
34 $not_allowed_on,
35 $(
36 " (only on ",
37 $only_allowed_on,
38 ")",
39 )?
40 ),
41 ));
42 }
43 };
44
45 ($key:ident flag not on $not_allowed_on:literal $(only on $only_allowed_on:literal)?) => {
46 if let Flag::Present(ref $key) = $key {
47 return Err(Error::new(
48 *$key,
49 concat!(
50 "`",
51 stringify!($key),
52 "` is not allowed on ",
53 $not_allowed_on,
54 $(
55 " (only on ",
56 $only_allowed_on,
57 ")",
58 )?
59 ),
60 ));
61 }
62 };
63}
64
65pub(crate) use reject_key;
66
67/// Value for the `#[xml(namespace = ..)]` attribute.
68#[derive(Debug, Clone)]
69pub(crate) enum NamespaceRef {
70 /// The XML namespace is specified as a string literal.
71 LitStr(LitStr),
72
73 /// The XML namespace is specified as a path.
74 Path(Path),
75}
76
77impl NamespaceRef {
78 fn fudge(value: &str, span: Span) -> Self {
79 Self::LitStr(LitStr::new(value, span))
80 }
81}
82
83impl syn::parse::Parse for NamespaceRef {
84 fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
85 if input.peek(syn::LitStr) {
86 Ok(Self::LitStr(input.parse()?))
87 } else {
88 Ok(Self::Path(input.parse()?))
89 }
90 }
91}
92
93impl quote::ToTokens for NamespaceRef {
94 fn to_tokens(&self, tokens: &mut TokenStream) {
95 match self {
96 Self::LitStr(ref lit) => lit.to_tokens(tokens),
97 Self::Path(ref path) => path.to_tokens(tokens),
98 }
99 }
100}
101
102/// Value for the `#[xml(name = .. )]` attribute.
103#[derive(Debug, Clone)]
104pub(crate) enum NameRef {
105 /// The XML name is specified as a string literal.
106 Literal {
107 /// The validated XML name.
108 value: NcName,
109
110 /// The span of the original [`syn::LitStr`].
111 span: Span,
112 },
113
114 /// The XML name is specified as a path.
115 Path(Path),
116}
117
118impl Hash for NameRef {
119 fn hash<H: Hasher>(&self, h: &mut H) {
120 match self {
121 Self::Literal { ref value, .. } => value.hash(h),
122 Self::Path(ref path) => path.hash(h),
123 }
124 }
125}
126
127impl PartialEq for NameRef {
128 fn eq(&self, other: &NameRef) -> bool {
129 match self {
130 Self::Literal {
131 value: ref my_value,
132 ..
133 } => match other {
134 Self::Literal {
135 value: ref other_value,
136 ..
137 } => my_value == other_value,
138 _ => false,
139 },
140 Self::Path(ref my_path) => match other {
141 Self::Path(ref other_path) => my_path == other_path,
142 _ => false,
143 },
144 }
145 }
146}
147
148impl Eq for NameRef {}
149
150impl syn::parse::Parse for NameRef {
151 fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
152 if input.peek(syn::LitStr) {
153 let s: LitStr = input.parse()?;
154 let span = s.span();
155 match NcName::try_from(s.value()) {
156 Ok(value) => Ok(Self::Literal { value, span }),
157 Err(e) => Err(Error::new(span, format!("not a valid XML name: {}", e))),
158 }
159 } else {
160 let p: Path = input.parse()?;
161 Ok(Self::Path(p))
162 }
163 }
164}
165
166impl quote::ToTokens for NameRef {
167 fn to_tokens(&self, tokens: &mut TokenStream) {
168 match self {
169 Self::Literal { ref value, span } => {
170 let span = *span;
171 let value = value.as_str();
172 let value = quote_spanned! { span=> #value };
173 // SAFETY: self.0 is a known-good NcName, so converting it to an
174 // NcNameStr is known to be safe.
175 // NOTE: we cannot use `quote_spanned! { self.span=> }` for the unsafe
176 // block as that would then in fact trip a `#[deny(unsafe_code)]` lint
177 // at the use site of the macro.
178 tokens.extend(quote! {
179 unsafe { ::xso::exports::rxml::NcNameStr::from_str_unchecked(#value) }
180 })
181 }
182 Self::Path(ref path) => path.to_tokens(tokens),
183 }
184 }
185}
186
187/// Represents the amount constraint used with child elements.
188///
189/// Currently, this only supports "one" (literal `1`) or "any amount" (`..`).
190/// In the future, we might want to add support for any range pattern for
191/// `usize` and any positive integer literal.
192#[derive(Debug)]
193pub(crate) enum AmountConstraint {
194 /// Equivalent to `1`
195 #[allow(dead_code)]
196 FixedSingle(Span),
197
198 /// Equivalent to `..`.
199 Any(Span),
200}
201
202impl syn::parse::Parse for AmountConstraint {
203 fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
204 if input.peek(LitInt) && !input.peek2(token::DotDot) && !input.peek2(token::DotDotEq) {
205 let lit: LitInt = input.parse()?;
206 let value: usize = lit.base10_parse()?;
207 if value == 1 {
208 Ok(Self::FixedSingle(lit.span()))
209 } else {
210 Err(Error::new(lit.span(), "only `1` and `..` are allowed here"))
211 }
212 } else {
213 let p: PatRange = input.parse()?;
214 if let Some(attr) = p.attrs.first() {
215 return Err(Error::new_spanned(attr, "attributes not allowed here"));
216 }
217 if let Some(start) = p.start.as_ref() {
218 return Err(Error::new_spanned(
219 start,
220 "only full ranges (`..`) are allowed here",
221 ));
222 }
223 if let Some(end) = p.end.as_ref() {
224 return Err(Error::new_spanned(
225 end,
226 "only full ranges (`..`) are allowed here",
227 ));
228 }
229 Ok(Self::Any(p.span()))
230 }
231 }
232}
233
234/// Represents a boolean flag from a `#[xml(..)]` attribute meta.
235#[derive(Clone, Copy, Debug)]
236pub(crate) enum Flag {
237 /// The flag is not set.
238 Absent,
239
240 /// The flag was set.
241 Present(
242 /// The span of the syntax element which enabled the flag.
243 ///
244 /// This is used to generate useful error messages by pointing at the
245 /// specific place the flag was activated.
246 #[allow(dead_code)]
247 Span,
248 ),
249}
250
251impl Flag {
252 /// Return true if the flag is set, false otherwise.
253 pub(crate) fn is_set(&self) -> bool {
254 match self {
255 Self::Absent => false,
256 Self::Present(_) => true,
257 }
258 }
259
260 /// Like `Option::take`, but for flags.
261 pub(crate) fn take(&mut self) -> Self {
262 let mut result = Flag::Absent;
263 core::mem::swap(&mut result, self);
264 result
265 }
266}
267
268impl<T: Spanned> From<T> for Flag {
269 fn from(other: T) -> Flag {
270 Flag::Present(other.span())
271 }
272}
273
274/// A pair of `namespace` and `name` keys.
275#[derive(Debug, Default)]
276pub(crate) struct QNameRef {
277 /// The XML namespace supplied.
278 pub(crate) namespace: Option<NamespaceRef>,
279
280 /// The XML name supplied.
281 pub(crate) name: Option<NameRef>,
282}
283
284impl QNameRef {
285 /// Attempt to incrementally parse this QNameRef.
286 ///
287 /// If `meta` contains either `namespace` or `name` keys, they are
288 /// processed and either `Ok(None)` or an error is returned.
289 ///
290 /// If no matching key is found, `Ok(Some(meta))` is returned for further
291 /// processing.
292 fn parse_incremental_from_meta<'x>(
293 &mut self,
294 meta: ParseNestedMeta<'x>,
295 ) -> Result<Option<ParseNestedMeta<'x>>> {
296 if meta.path.is_ident("name") {
297 if self.name.is_some() {
298 return Err(Error::new_spanned(meta.path, "duplicate `name` key"));
299 }
300 let value = meta.value()?;
301 let name_span = value.span();
302 let (new_namespace, new_name) = parse_prefixed_name(value)?;
303 if let Some(new_namespace) = new_namespace {
304 if let Some(namespace) = self.namespace.as_ref() {
305 let mut error = Error::new(
306 name_span,
307 "cannot combine `namespace` key with prefixed `name`",
308 );
309 error.combine(Error::new_spanned(namespace, "`namespace` was set here"));
310 return Err(error);
311 }
312 self.namespace = Some(new_namespace);
313 }
314 self.name = Some(new_name);
315 Ok(None)
316 } else if meta.path.is_ident("namespace") {
317 if self.namespace.is_some() {
318 return Err(Error::new_spanned(
319 meta.path,
320 "duplicate `namespace` key or `name` key has prefix",
321 ));
322 }
323 self.namespace = Some(meta.value()?.parse()?);
324 Ok(None)
325 } else {
326 Ok(Some(meta))
327 }
328 }
329}
330
331/// Contents of an `#[xml(..)]` attribute on a struct, enum variant, or enum.
332#[derive(Debug)]
333pub(crate) struct XmlCompoundMeta {
334 /// The span of the `#[xml(..)]` meta from which this was parsed.
335 ///
336 /// This is useful for error messages.
337 pub(crate) span: Span,
338
339 /// The value assigned to `namespace` and `name` fields inside
340 /// `#[xml(..)]`, if any.
341 pub(crate) qname: QNameRef,
342
343 /// The debug flag.
344 pub(crate) debug: Flag,
345
346 /// The value assigned to `builder` inside `#[xml(..)]`, if any.
347 pub(crate) builder: Option<Ident>,
348
349 /// The value assigned to `iterator` inside `#[xml(..)]`, if any.
350 pub(crate) iterator: Option<Ident>,
351
352 /// The exhaustive flag.
353 pub(crate) exhaustive: Flag,
354
355 /// The transparent flag.
356 pub(crate) transparent: Flag,
357}
358
359impl XmlCompoundMeta {
360 /// Parse the meta values from a `#[xml(..)]` attribute.
361 ///
362 /// Undefined options or options with incompatible values are rejected
363 /// with an appropriate compile-time error.
364 fn parse_from_attribute(attr: &Attribute) -> Result<Self> {
365 let mut qname = QNameRef::default();
366 let mut builder = None;
367 let mut iterator = None;
368 let mut debug = Flag::Absent;
369 let mut exhaustive = Flag::Absent;
370 let mut transparent = Flag::Absent;
371
372 attr.parse_nested_meta(|meta| {
373 if meta.path.is_ident("debug") {
374 if debug.is_set() {
375 return Err(Error::new_spanned(meta.path, "duplicate `debug` key"));
376 }
377 debug = (&meta.path).into();
378 Ok(())
379 } else if meta.path.is_ident("builder") {
380 if builder.is_some() {
381 return Err(Error::new_spanned(meta.path, "duplicate `builder` key"));
382 }
383 builder = Some(meta.value()?.parse()?);
384 Ok(())
385 } else if meta.path.is_ident("iterator") {
386 if iterator.is_some() {
387 return Err(Error::new_spanned(meta.path, "duplicate `iterator` key"));
388 }
389 iterator = Some(meta.value()?.parse()?);
390 Ok(())
391 } else if meta.path.is_ident("exhaustive") {
392 if exhaustive.is_set() {
393 return Err(Error::new_spanned(meta.path, "duplicate `exhaustive` key"));
394 }
395 exhaustive = (&meta.path).into();
396 Ok(())
397 } else if meta.path.is_ident("transparent") {
398 if transparent.is_set() {
399 return Err(Error::new_spanned(meta.path, "duplicate `transparent` key"));
400 }
401 transparent = (&meta.path).into();
402 Ok(())
403 } else {
404 match qname.parse_incremental_from_meta(meta)? {
405 None => Ok(()),
406 Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
407 }
408 }
409 })?;
410
411 Ok(Self {
412 span: attr.span(),
413 qname,
414 debug,
415 builder,
416 iterator,
417 exhaustive,
418 transparent,
419 })
420 }
421
422 /// Search through `attrs` for a single `#[xml(..)]` attribute and parse
423 /// it.
424 ///
425 /// Undefined options or options with incompatible values are rejected
426 /// with an appropriate compile-time error.
427 ///
428 /// If more than one `#[xml(..)]` attribute is found, an error is
429 /// emitted.
430 ///
431 /// If no `#[xml(..)]` attribute is found, `None` is returned.
432 pub(crate) fn try_parse_from_attributes(attrs: &[Attribute]) -> Result<Option<Self>> {
433 let mut result = None;
434 for attr in attrs {
435 if !attr.path().is_ident("xml") {
436 continue;
437 }
438 if result.is_some() {
439 return Err(syn::Error::new_spanned(
440 attr.path(),
441 "only one #[xml(..)] per struct or enum variant allowed",
442 ));
443 }
444 result = Some(Self::parse_from_attribute(attr)?);
445 }
446 Ok(result)
447 }
448
449 /// Search through `attrs` for a single `#[xml(..)]` attribute and parse
450 /// it.
451 ///
452 /// Undefined options or options with incompatible values are rejected
453 /// with an appropriate compile-time error.
454 ///
455 /// If more than one or no `#[xml(..)]` attribute is found, an error is
456 /// emitted.
457 pub(crate) fn parse_from_attributes(attrs: &[Attribute]) -> Result<Self> {
458 match Self::try_parse_from_attributes(attrs)? {
459 Some(v) => Ok(v),
460 None => Err(syn::Error::new(
461 Span::call_site(),
462 "#[xml(..)] attribute required on struct or enum variant",
463 )),
464 }
465 }
466}
467
468/// Return true if the tokens the cursor points at are a valid type path
469/// prefix.
470///
471/// This does not advance the parse stream.
472///
473/// If the tokens *do* look like a type path, a Span which points at the first
474/// `<` encountered is returned. This can be used for a helpful error message
475/// in case parsing the type path does then fail.
476fn maybe_type_path(p: parse::ParseStream<'_>) -> (bool, Option<Span>) {
477 // ParseStream cursors do not advance the stream, but they are also rather
478 // unwieldly to use. Prepare for a lot of `let .. = ..`.
479
480 let cursor = if p.peek(token::PathSep) {
481 // If we have a path separator, we need to skip that initially. We
482 // do this by skipping two punctuations. We use unwrap() here because
483 // we already know for sure that we see two punctuation items (because
484 // of the peek).
485 p.cursor().punct().unwrap().1.punct().unwrap().1
486 } else {
487 // No `::` initially, so we just take what we have.
488 p.cursor()
489 };
490
491 // Now we loop over `$ident::` segments. If we find anything but a `:`
492 // after the ident, we exit. Depending on *what* we find, we either exit
493 // true or false, but see for yourself.
494 let mut cursor = cursor;
495 loop {
496 // Here we look for the identifier, but we do not care for its
497 // contents.
498 let Some((_, new_cursor)) = cursor.ident() else {
499 return (false, None);
500 };
501 cursor = new_cursor;
502
503 // Now we see what actually follows the ident (it must be punctuation
504 // for it to be a type path...)
505 let Some((punct, new_cursor)) = cursor.punct() else {
506 return (false, None);
507 };
508 cursor = new_cursor;
509
510 match punct.as_char() {
511 // Looks like a `foo<..`, we treat that as a type path for the
512 // reasons stated in [`parse_codec_expr`]'s doc.
513 '<' => return (true, Some(punct.span())),
514
515 // Continue looking ahead: looks like a path separator.
516 ':' => (),
517
518 // Anything else (such as `,` (separating another argument most
519 // likely), or `.` (a method call?)) we treat as "not a type
520 // path".
521 _ => return (false, None),
522 }
523
524 // If we are here, we saw a `:`. Look for the second one.
525 let Some((punct, new_cursor)) = cursor.punct() else {
526 return (false, None);
527 };
528 cursor = new_cursor;
529
530 if punct.as_char() != ':' {
531 // If it is not another `:`, it cannot be a type path.
532 return (false, None);
533 }
534
535 // And round and round and round it goes.
536 // We will terminate eventually because the cursor will return None
537 // on any of the lookups because parse streams are (hopefully!)
538 // finite. Most likely, we'll however encounter a `<` or other non-`:`
539 // punctuation first.
540 }
541}
542
543/// Parse expressions passed to `codec`.
544///
545/// Those will generally be paths to unit type constructors (such as `Foo`)
546/// or references to static values or chains of function calls.
547///
548/// In the case of unit type constructors for generic types, users may type
549/// for example `FixedHex<20>`, thinking they are writing a type path. However,
550/// while `FixedHex<20>` is indeed a valid type path, it is not a valid
551/// expression for a unit type constructor. Instead it is parsed as
552/// `FixedHex < 20` and then a syntax error.
553///
554/// We however know that `Foo < Bar` is never a valid expression for a type.
555/// Thus, we can be smart about this and inject the `::` at the right place
556/// automatically.
557fn parse_codec_expr(p: parse::ParseStream<'_>) -> Result<(Expr, Option<Error>)> {
558 let (maybe_type_path, punct_span) = maybe_type_path(p);
559 if maybe_type_path {
560 let helpful_error =
561 punct_span.map(|span| Error::new(span, "help: try inserting a `::` before this `<`"));
562 let mut type_path: TypePath = match p.parse() {
563 Ok(v) => v,
564 Err(mut e) => match helpful_error {
565 Some(help) => {
566 e.combine(help);
567 return Err(e);
568 }
569 None => return Err(e),
570 },
571 };
572 // We got a type path -- so we now inject the `::` before any `<` as
573 // needed.
574 for segment in type_path.path.segments.iter_mut() {
575 match segment.arguments {
576 PathArguments::AngleBracketed(ref mut arguments) => {
577 let span = arguments.span();
578 arguments
579 .colon2_token
580 .get_or_insert_with(|| token::PathSep {
581 spans: [span, span],
582 });
583 }
584 _ => (),
585 }
586 }
587 Ok((
588 Expr::Path(ExprPath {
589 attrs: Vec::new(),
590 qself: type_path.qself,
591 path: type_path.path,
592 }),
593 helpful_error,
594 ))
595 } else {
596 p.parse().map(|x| (x, None))
597 }
598}
599
600/// Parse an XML name while resolving built-in namespace prefixes.
601fn parse_prefixed_name(
602 value: syn::parse::ParseStream<'_>,
603) -> Result<(Option<NamespaceRef>, NameRef)> {
604 if !value.peek(LitStr) {
605 // if we don't have a string literal next, we delegate to the default
606 // `NameRef` parser.
607 return Ok((None, value.parse()?));
608 }
609
610 let name: LitStr = value.parse()?;
611 let name_span = name.span();
612 let (prefix, name) = match name
613 .value()
614 .try_into()
615 .and_then(|name: rxml_validation::Name| name.split_name())
616 {
617 Ok(v) => v,
618 Err(e) => {
619 return Err(Error::new(
620 name_span,
621 format!("not a valid XML name: {}", e),
622 ))
623 }
624 };
625 let name = NameRef::Literal {
626 value: name,
627 span: name_span,
628 };
629 if let Some(prefix) = prefix {
630 let namespace_uri = match prefix.as_str() {
631 "xml" => XMLNS_XML,
632 "xmlns" => XMLNS_XMLNS,
633 other => return Err(Error::new(
634 name_span,
635 format!("prefix `{}` is not a built-in prefix and cannot be used. specify the desired namespace using the `namespace` key instead.", other)
636 )),
637 };
638 Ok((Some(NamespaceRef::fudge(namespace_uri, name_span)), name))
639 } else {
640 Ok((None, name))
641 }
642}
643
644/// Contents of an `#[xml(..)]` attribute on a struct or enum variant member.
645#[derive(Debug)]
646pub(crate) enum XmlFieldMeta {
647 /// `#[xml(attribute)]`, `#[xml(attribute = ..)]` or `#[xml(attribute(..))]`
648 Attribute {
649 /// The span of the `#[xml(attribute)]` meta from which this was parsed.
650 ///
651 /// This is useful for error messages.
652 span: Span,
653
654 /// The namespace/name keys.
655 qname: QNameRef,
656
657 /// The `default` flag.
658 default_: Flag,
659
660 /// An explicit type override, only usable within extracts.
661 type_: Option<Type>,
662 },
663
664 /// `#[xml(text)]`
665 Text {
666 /// The span of the `#[xml(text)]` meta from which this was parsed.
667 ///
668 /// This is useful for error messages.
669 span: Span,
670
671 /// The path to the optional codec type.
672 codec: Option<Expr>,
673
674 /// An explicit type override, only usable within extracts.
675 type_: Option<Type>,
676 },
677
678 /// `#[xml(child)`
679 Child {
680 /// The span of the `#[xml(child)]` meta from which this was parsed.
681 ///
682 /// This is useful for error messages.
683 span: Span,
684
685 /// The `default` flag.
686 default_: Flag,
687
688 /// The `n` flag.
689 amount: Option<AmountConstraint>,
690 },
691
692 /// `#[xml(extract)]
693 Extract {
694 /// The span of the `#[xml(extract)]` meta from which this was parsed.
695 ///
696 /// This is useful for error messages.
697 span: Span,
698
699 /// The namespace/name keys.
700 qname: QNameRef,
701
702 /// The `n` flag.
703 amount: Option<AmountConstraint>,
704
705 /// The `default` flag.
706 default_: Flag,
707
708 /// The `fields` nested meta.
709 fields: Vec<XmlFieldMeta>,
710 },
711
712 /// `#[xml(element)]`
713 Element {
714 /// The span of the `#[xml(element)]` meta from which this was parsed.
715 ///
716 /// This is useful for error messages.
717 span: Span,
718
719 /// The `n` flag.
720 amount: Option<AmountConstraint>,
721 },
722}
723
724impl XmlFieldMeta {
725 /// Parse a `#[xml(attribute(..))]` meta.
726 ///
727 /// That meta can have three distinct syntax styles:
728 /// - argument-less: `#[xml(attribute)]`
729 /// - shorthand: `#[xml(attribute = ..)]`
730 /// - full: `#[xml(attribute(..))]`
731 fn attribute_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
732 if meta.input.peek(Token![=]) {
733 // shorthand syntax
734 let (namespace, name) = parse_prefixed_name(meta.value()?)?;
735 Ok(Self::Attribute {
736 span: meta.path.span(),
737 qname: QNameRef {
738 name: Some(name),
739 namespace,
740 },
741 default_: Flag::Absent,
742 type_: None,
743 })
744 } else if meta.input.peek(syn::token::Paren) {
745 // full syntax
746 let mut qname = QNameRef::default();
747 let mut default_ = Flag::Absent;
748 let mut type_ = None;
749 meta.parse_nested_meta(|meta| {
750 if meta.path.is_ident("default") {
751 if default_.is_set() {
752 return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
753 }
754 default_ = (&meta.path).into();
755 Ok(())
756 } else if meta.path.is_ident("type_") {
757 if type_.is_some() {
758 return Err(Error::new_spanned(meta.path, "duplicate `type_` key"));
759 }
760 type_ = Some(meta.value()?.parse()?);
761 Ok(())
762 } else {
763 match qname.parse_incremental_from_meta(meta)? {
764 None => Ok(()),
765 Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
766 }
767 }
768 })?;
769 Ok(Self::Attribute {
770 span: meta.path.span(),
771 qname,
772 default_,
773 type_,
774 })
775 } else {
776 // argument-less syntax
777 Ok(Self::Attribute {
778 span: meta.path.span(),
779 qname: QNameRef::default(),
780 default_: Flag::Absent,
781 type_: None,
782 })
783 }
784 }
785
786 /// Parse a `#[xml(text)]` meta.
787 fn text_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
788 if meta.input.peek(Token![=]) {
789 let (codec, helpful_error) = parse_codec_expr(meta.value()?)?;
790 // A meta value can only be followed by either a `,`, or the end
791 // of the parse stream (because of the delimited group ending).
792 // Hence we check we are there. And if we are *not* there, we emit
793 // an error straight away, with the helpful addition from the
794 // `parse_codec_expr` if we have it.
795 //
796 // If we do not do this, the user gets a rather confusing
797 // "expected `,`" message if the `maybe_type_path` guess was
798 // wrong.
799 let lookahead = meta.input.lookahead1();
800 if !lookahead.peek(Token![,]) && !meta.input.is_empty() {
801 if let Some(helpful_error) = helpful_error {
802 let mut e = lookahead.error();
803 e.combine(helpful_error);
804 return Err(e);
805 }
806 }
807 Ok(Self::Text {
808 span: meta.path.span(),
809 type_: None,
810 codec: Some(codec),
811 })
812 } else if meta.input.peek(syn::token::Paren) {
813 let mut codec: Option<Expr> = None;
814 let mut type_: Option<Type> = None;
815 meta.parse_nested_meta(|meta| {
816 if meta.path.is_ident("codec") {
817 if codec.is_some() {
818 return Err(Error::new_spanned(meta.path, "duplicate `codec` key"));
819 }
820 let (new_codec, helpful_error) = parse_codec_expr(meta.value()?)?;
821 // See above (at the top-ish of this function) for why we
822 // do this.
823 let lookahead = meta.input.lookahead1();
824 if !lookahead.peek(Token![,]) && !meta.input.is_empty() {
825 if let Some(helpful_error) = helpful_error {
826 let mut e = lookahead.error();
827 e.combine(helpful_error);
828 return Err(e);
829 }
830 }
831 codec = Some(new_codec);
832 Ok(())
833 } else if meta.path.is_ident("type_") {
834 if type_.is_some() {
835 return Err(Error::new_spanned(meta.path, "duplicate `type_` key"));
836 }
837 type_ = Some(meta.value()?.parse()?);
838 Ok(())
839 } else {
840 Err(Error::new_spanned(meta.path, "unsupported key"))
841 }
842 })?;
843 Ok(Self::Text {
844 span: meta.path.span(),
845 type_,
846 codec,
847 })
848 } else {
849 Ok(Self::Text {
850 span: meta.path.span(),
851 type_: None,
852 codec: None,
853 })
854 }
855 }
856
857 /// Parse a `#[xml(child)]` meta.
858 fn child_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
859 if meta.input.peek(syn::token::Paren) {
860 let mut default_ = Flag::Absent;
861 let mut amount = None;
862 meta.parse_nested_meta(|meta| {
863 if meta.path.is_ident("default") {
864 if default_.is_set() {
865 return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
866 }
867 default_ = (&meta.path).into();
868 Ok(())
869 } else if meta.path.is_ident("n") {
870 if amount.is_some() {
871 return Err(Error::new_spanned(meta.path, "duplicate `n` key"));
872 }
873 amount = Some(meta.value()?.parse()?);
874 Ok(())
875 } else {
876 Err(Error::new_spanned(meta.path, "unsupported key"))
877 }
878 })?;
879 Ok(Self::Child {
880 span: meta.path.span(),
881 default_,
882 amount,
883 })
884 } else {
885 Ok(Self::Child {
886 span: meta.path.span(),
887 default_: Flag::Absent,
888 amount: None,
889 })
890 }
891 }
892
893 /// Parse a `#[xml(extract)]` meta.
894 fn extract_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
895 let mut qname = QNameRef::default();
896 let mut fields = None;
897 let mut amount = None;
898 let mut default_ = Flag::Absent;
899 meta.parse_nested_meta(|meta| {
900 if meta.path.is_ident("default") {
901 if default_.is_set() {
902 return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
903 }
904 default_ = (&meta.path).into();
905 Ok(())
906 } else if meta.path.is_ident("fields") {
907 if let Some((fields_span, _)) = fields.as_ref() {
908 let mut error = Error::new_spanned(meta.path, "duplicate `fields` meta");
909 error.combine(Error::new(*fields_span, "previous `fields` meta was here"));
910 return Err(error);
911 }
912 let mut new_fields = Vec::new();
913 meta.parse_nested_meta(|meta| {
914 new_fields.push(XmlFieldMeta::parse_from_meta(meta)?);
915 Ok(())
916 })?;
917 fields = Some((meta.path.span(), new_fields));
918 Ok(())
919 } else if meta.path.is_ident("n") {
920 if amount.is_some() {
921 return Err(Error::new_spanned(meta.path, "duplicate `n` key"));
922 }
923 amount = Some(meta.value()?.parse()?);
924 Ok(())
925 } else {
926 match qname.parse_incremental_from_meta(meta)? {
927 None => Ok(()),
928 Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
929 }
930 }
931 })?;
932 let fields = fields.map(|(_, x)| x).unwrap_or_else(Vec::new);
933 Ok(Self::Extract {
934 span: meta.path.span(),
935 default_,
936 qname,
937 fields,
938 amount,
939 })
940 }
941
942 /// Parse a `#[xml(element)]` meta.
943 fn element_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
944 let mut amount = None;
945 meta.parse_nested_meta(|meta| {
946 if meta.path.is_ident("n") {
947 if amount.is_some() {
948 return Err(Error::new_spanned(meta.path, "duplicate `n` key"));
949 }
950 amount = Some(meta.value()?.parse()?);
951 Ok(())
952 } else {
953 Err(Error::new_spanned(meta.path, "unsupported key"))
954 }
955 })?;
956 Ok(Self::Element {
957 span: meta.path.span(),
958 amount,
959 })
960 }
961
962 /// Parse [`Self`] from a nestd meta, switching on the identifier
963 /// of that nested meta.
964 fn parse_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
965 if meta.path.is_ident("attribute") {
966 Self::attribute_from_meta(meta)
967 } else if meta.path.is_ident("text") {
968 Self::text_from_meta(meta)
969 } else if meta.path.is_ident("child") {
970 Self::child_from_meta(meta)
971 } else if meta.path.is_ident("extract") {
972 Self::extract_from_meta(meta)
973 } else if meta.path.is_ident("element") {
974 Self::element_from_meta(meta)
975 } else {
976 Err(Error::new_spanned(meta.path, "unsupported field meta"))
977 }
978 }
979
980 /// Parse an `#[xml(..)]` meta on a field.
981 ///
982 /// This switches based on the first identifier within the `#[xml(..)]`
983 /// meta and generates an enum variant accordingly.
984 ///
985 /// Only a single nested meta is allowed; more than one will be
986 /// rejected with an appropriate compile-time error.
987 ///
988 /// If no meta is contained at all, a compile-time error is generated.
989 ///
990 /// Undefined options or options with incompatible values are rejected
991 /// with an appropriate compile-time error.
992 pub(crate) fn parse_from_attribute(attr: &Attribute) -> Result<Self> {
993 let mut result: Option<Self> = None;
994
995 attr.parse_nested_meta(|meta| {
996 if result.is_some() {
997 return Err(Error::new_spanned(
998 meta.path,
999 "multiple field type specifiers are not supported",
1000 ));
1001 }
1002
1003 result = Some(Self::parse_from_meta(meta)?);
1004 Ok(())
1005 })?;
1006
1007 if let Some(result) = result {
1008 Ok(result)
1009 } else {
1010 Err(Error::new_spanned(
1011 attr,
1012 "missing field type specifier within `#[xml(..)]`",
1013 ))
1014 }
1015 }
1016
1017 /// Find and parse a `#[xml(..)]` meta on a field.
1018 ///
1019 /// This invokes [`Self::parse_from_attribute`] internally on the first
1020 /// encountered `#[xml(..)]` meta.
1021 ///
1022 /// If not exactly one `#[xml(..)]` meta is encountered, an error is
1023 /// returned. The error is spanned to `err_span`.
1024 pub(crate) fn parse_from_attributes(attrs: &[Attribute], err_span: &Span) -> Result<Self> {
1025 let mut result: Option<Self> = None;
1026 for attr in attrs {
1027 if !attr.path().is_ident("xml") {
1028 continue;
1029 }
1030
1031 if result.is_some() {
1032 return Err(Error::new_spanned(
1033 attr,
1034 "only one #[xml(..)] attribute per field allowed.",
1035 ));
1036 }
1037
1038 result = Some(Self::parse_from_attribute(attr)?);
1039 }
1040
1041 if let Some(result) = result {
1042 Ok(result)
1043 } else {
1044 Err(Error::new(*err_span, "missing #[xml(..)] meta on field"))
1045 }
1046 }
1047
1048 /// Return a span which points at the meta which constructed this
1049 /// XmlFieldMeta.
1050 pub(crate) fn span(&self) -> Span {
1051 match self {
1052 Self::Attribute { ref span, .. } => *span,
1053 Self::Child { ref span, .. } => *span,
1054 Self::Text { ref span, .. } => *span,
1055 Self::Extract { ref span, .. } => *span,
1056 Self::Element { ref span, .. } => *span,
1057 }
1058 }
1059
1060 /// Extract an explicit type specification if it exists.
1061 pub(crate) fn take_type(&mut self) -> Option<Type> {
1062 match self {
1063 Self::Attribute { ref mut type_, .. } => type_.take(),
1064 Self::Text { ref mut type_, .. } => type_.take(),
1065 _ => None,
1066 }
1067 }
1068}