meta.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//! # 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::fmt;
  13use core::hash::{Hash, Hasher};
  14
  15use proc_macro2::{Span, TokenStream};
  16use quote::{quote, quote_spanned};
  17use syn::{meta::ParseNestedMeta, spanned::Spanned, *};
  18
  19use rxml_validation::NcName;
  20
  21use crate::error_message::PrettyPath;
  22
  23/// XML core namespace URI (for the `xml:` prefix)
  24pub const XMLNS_XML: &str = "http://www.w3.org/XML/1998/namespace";
  25/// XML namespace URI (for the `xmlns:` prefix)
  26pub const XMLNS_XMLNS: &str = "http://www.w3.org/2000/xmlns/";
  27
  28macro_rules! reject_key {
  29    ($key:ident not on $not_allowed_on:literal $(only on $only_allowed_on:literal)?) => {
  30        if let Some(ref $key) = $key {
  31            #[allow(unused_imports)]
  32            use syn::spanned::Spanned as _;
  33            return Err(Error::new(
  34                $key.span(),
  35                concat!(
  36                    "`",
  37                    stringify!($key),
  38                    "` is not allowed on ",
  39                    $not_allowed_on,
  40                    $(
  41                        " (only on ",
  42                        $only_allowed_on,
  43                        ")",
  44                    )?
  45                ),
  46            ));
  47        }
  48    };
  49
  50    ($key:ident flag not on $not_allowed_on:literal $(only on $only_allowed_on:literal)?) => {
  51        if let Flag::Present(ref $key) = $key {
  52            return Err(Error::new(
  53                *$key,
  54                concat!(
  55                    "`",
  56                    stringify!($key),
  57                    "` is not allowed on ",
  58                    $not_allowed_on,
  59                    $(
  60                        " (only on ",
  61                        $only_allowed_on,
  62                        ")",
  63                    )?
  64                ),
  65            ));
  66        }
  67    };
  68
  69    ($key:ident vec not on $not_allowed_on:literal $(only on $only_allowed_on:literal)?) => {
  70        if let Some(ref $key) = $key.first() {
  71            return Err(Error::new(
  72                $key.span(),
  73                concat!(
  74                    "`",
  75                    stringify!($key),
  76                    "` is not allowed on ",
  77                    $not_allowed_on,
  78                    $(
  79                        " (only on ",
  80                        $only_allowed_on,
  81                        ")",
  82                    )?
  83                ),
  84            ));
  85        }
  86    };
  87}
  88
  89pub(crate) use reject_key;
  90
  91/// Value for the `#[xml(namespace = ..)]` attribute.
  92#[derive(Debug, Clone, PartialEq, Eq, Hash)]
  93pub(crate) enum NamespaceRef {
  94    /// The XML namespace is specified as a string literal.
  95    LitStr(LitStr),
  96
  97    /// The XML namespace is specified as a path.
  98    Path(Path),
  99}
 100
 101impl NamespaceRef {
 102    pub(crate) fn fudge(value: &str, span: Span) -> Self {
 103        Self::LitStr(LitStr::new(value, span))
 104    }
 105}
 106
 107impl fmt::Display for NamespaceRef {
 108    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 109        match self {
 110            Self::LitStr(s) => write!(f, "{}", s.value()),
 111            Self::Path(ref p) => write!(f, "<{}>", PrettyPath(p)),
 112        }
 113    }
 114}
 115
 116impl syn::parse::Parse for NamespaceRef {
 117    fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
 118        if input.peek(syn::LitStr) {
 119            Ok(Self::LitStr(input.parse()?))
 120        } else {
 121            Ok(Self::Path(input.parse()?))
 122        }
 123    }
 124}
 125
 126impl quote::ToTokens for NamespaceRef {
 127    fn to_tokens(&self, tokens: &mut TokenStream) {
 128        match self {
 129            Self::LitStr(ref lit) => lit.to_tokens(tokens),
 130            Self::Path(ref path) => path.to_tokens(tokens),
 131        }
 132    }
 133}
 134
 135/// Value for the `#[xml(name = .. )]` attribute.
 136#[derive(Debug, Clone)]
 137pub(crate) enum NameRef {
 138    /// The XML name is specified as a string literal.
 139    Literal {
 140        /// The validated XML name.
 141        value: NcName,
 142
 143        /// The span of the original [`syn::LitStr`].
 144        span: Span,
 145    },
 146
 147    /// The XML name is specified as a path.
 148    Path(Path),
 149}
 150
 151impl NameRef {
 152    pub(crate) fn fudge(value: NcName, span: Span) -> Self {
 153        Self::Literal { value, span }
 154    }
 155}
 156
 157impl fmt::Display for NameRef {
 158    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 159        match self {
 160            Self::Literal { value, .. } => write!(f, "{}", value.as_str()),
 161            Self::Path(ref p) => write!(f, "<{}>", PrettyPath(p)),
 162        }
 163    }
 164}
 165
 166impl Hash for NameRef {
 167    fn hash<H: Hasher>(&self, h: &mut H) {
 168        match self {
 169            Self::Literal { ref value, .. } => value.hash(h),
 170            Self::Path(ref path) => path.hash(h),
 171        }
 172    }
 173}
 174
 175impl PartialEq for NameRef {
 176    fn eq(&self, other: &NameRef) -> bool {
 177        match self {
 178            Self::Literal {
 179                value: ref my_value,
 180                ..
 181            } => match other {
 182                Self::Literal {
 183                    value: ref other_value,
 184                    ..
 185                } => my_value == other_value,
 186                _ => false,
 187            },
 188            Self::Path(ref my_path) => match other {
 189                Self::Path(ref other_path) => my_path == other_path,
 190                _ => false,
 191            },
 192        }
 193    }
 194}
 195
 196impl Eq for NameRef {}
 197
 198impl syn::parse::Parse for NameRef {
 199    fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
 200        if input.peek(syn::LitStr) {
 201            let s: LitStr = input.parse()?;
 202            let span = s.span();
 203            match NcName::try_from(s.value()) {
 204                Ok(value) => Ok(Self::Literal { value, span }),
 205                Err(e) => Err(Error::new(span, format!("not a valid XML name: {}", e))),
 206            }
 207        } else {
 208            let p: Path = input.parse()?;
 209            Ok(Self::Path(p))
 210        }
 211    }
 212}
 213
 214impl quote::ToTokens for NameRef {
 215    fn to_tokens(&self, tokens: &mut TokenStream) {
 216        match self {
 217            Self::Literal { ref value, span } => {
 218                let span = *span;
 219                let value = value.as_str();
 220                let value = quote_spanned! { span=> #value };
 221                // SAFETY: self.0 is a known-good NcName, so converting it to an
 222                // NcNameStr is known to be safe.
 223                // NOTE: we cannot use `quote_spanned! { self.span=> }` for the unsafe
 224                // block as that would then in fact trip a `#[deny(unsafe_code)]` lint
 225                // at the use site of the macro.
 226                tokens.extend(quote! {
 227                    unsafe { ::xso::exports::rxml::NcNameStr::from_str_unchecked(#value) }
 228                })
 229            }
 230            Self::Path(ref path) => path.to_tokens(tokens),
 231        }
 232    }
 233}
 234
 235/// Represents the amount constraint used with child elements.
 236///
 237/// Currently, this only supports "one" (literal `1`) or "any amount" (`..`).
 238/// In the future, we might want to add support for any range pattern for
 239/// `usize` and any positive integer literal.
 240#[derive(Debug)]
 241pub(crate) enum AmountConstraint {
 242    /// Equivalent to `1`
 243    #[allow(dead_code)]
 244    FixedSingle(Span),
 245
 246    /// Equivalent to `..`.
 247    Any(Span),
 248}
 249
 250impl syn::parse::Parse for AmountConstraint {
 251    fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
 252        if input.peek(LitInt) && !input.peek2(token::DotDot) && !input.peek2(token::DotDotEq) {
 253            let lit: LitInt = input.parse()?;
 254            let value: usize = lit.base10_parse()?;
 255            if value == 1 {
 256                Ok(Self::FixedSingle(lit.span()))
 257            } else {
 258                Err(Error::new(lit.span(), "only `1` and `..` are allowed here"))
 259            }
 260        } else {
 261            let p: PatRange = input.parse()?;
 262            if let Some(attr) = p.attrs.first() {
 263                return Err(Error::new_spanned(attr, "attributes not allowed here"));
 264            }
 265            if let Some(start) = p.start.as_ref() {
 266                return Err(Error::new_spanned(
 267                    start,
 268                    "only full ranges (`..`) are allowed here",
 269                ));
 270            }
 271            if let Some(end) = p.end.as_ref() {
 272                return Err(Error::new_spanned(
 273                    end,
 274                    "only full ranges (`..`) are allowed here",
 275                ));
 276            }
 277            Ok(Self::Any(p.span()))
 278        }
 279    }
 280}
 281
 282/// Represents a boolean flag from a `#[xml(..)]` attribute meta.
 283#[derive(Clone, Copy, Debug)]
 284pub(crate) enum Flag {
 285    /// The flag is not set.
 286    Absent,
 287
 288    /// The flag was set.
 289    Present(
 290        /// The span of the syntax element which enabled the flag.
 291        ///
 292        /// This is used to generate useful error messages by pointing at the
 293        /// specific place the flag was activated.
 294        #[allow(dead_code)]
 295        Span,
 296    ),
 297}
 298
 299impl Flag {
 300    /// Return true if the flag is set, false otherwise.
 301    pub(crate) fn is_set(&self) -> bool {
 302        match self {
 303            Self::Absent => false,
 304            Self::Present(_) => true,
 305        }
 306    }
 307
 308    /// Like `Option::take`, but for flags.
 309    pub(crate) fn take(&mut self) -> Self {
 310        let mut result = Flag::Absent;
 311        core::mem::swap(&mut result, self);
 312        result
 313    }
 314}
 315
 316impl<T: Spanned> From<T> for Flag {
 317    fn from(other: T) -> Flag {
 318        Flag::Present(other.span())
 319    }
 320}
 321
 322/// A pair of `namespace` and `name` keys.
 323#[derive(Debug, Default, PartialEq, Eq, Hash)]
 324pub(crate) struct QNameRef {
 325    /// The XML namespace supplied.
 326    pub(crate) namespace: Option<NamespaceRef>,
 327
 328    /// The XML name supplied.
 329    pub(crate) name: Option<NameRef>,
 330}
 331
 332impl QNameRef {
 333    /// Attempt to incrementally parse this QNameRef.
 334    ///
 335    /// If `meta` contains either `namespace` or `name` keys, they are
 336    /// processed and either `Ok(None)` or an error is returned.
 337    ///
 338    /// If no matching key is found, `Ok(Some(meta))` is returned for further
 339    /// processing.
 340    fn parse_incremental_from_meta<'x>(
 341        &mut self,
 342        meta: ParseNestedMeta<'x>,
 343    ) -> Result<Option<ParseNestedMeta<'x>>> {
 344        if meta.path.is_ident("name") {
 345            if self.name.is_some() {
 346                return Err(Error::new_spanned(meta.path, "duplicate `name` key"));
 347            }
 348            let value = meta.value()?;
 349            let name_span = value.span();
 350            let (new_namespace, new_name) = parse_prefixed_name(value)?;
 351            if let Some(new_namespace) = new_namespace {
 352                if let Some(namespace) = self.namespace.as_ref() {
 353                    let mut error = Error::new(
 354                        name_span,
 355                        "cannot combine `namespace` key with prefixed `name`",
 356                    );
 357                    error.combine(Error::new_spanned(namespace, "`namespace` was set here"));
 358                    return Err(error);
 359                }
 360                self.namespace = Some(new_namespace);
 361            }
 362            self.name = Some(new_name);
 363            Ok(None)
 364        } else if meta.path.is_ident("namespace") {
 365            if self.namespace.is_some() {
 366                return Err(Error::new_spanned(
 367                    meta.path,
 368                    "duplicate `namespace` key or `name` key has prefix",
 369                ));
 370            }
 371            self.namespace = Some(meta.value()?.parse()?);
 372            Ok(None)
 373        } else {
 374            Ok(Some(meta))
 375        }
 376    }
 377}
 378
 379/// Identifies XML content to discard.
 380#[derive(Debug)]
 381pub(crate) enum DiscardSpec {
 382    /// `#[xml(discard(attribute..))]`
 383    Attribute {
 384        /// The span of the nested meta from which this was parsed.
 385        ///
 386        /// This is useful for error messages.
 387        span: Span,
 388
 389        /// The value assigned to `namespace` and `name` fields inside
 390        /// `#[xml(discard(attribute(..)))]`, if any.
 391        qname: QNameRef,
 392    },
 393
 394    /// `#[xml(discard(text))]`
 395    Text {
 396        /// The span of the nested meta from which this was parsed.
 397        ///
 398        /// This is useful for error messages.
 399        span: Span,
 400    },
 401}
 402
 403impl DiscardSpec {
 404    pub(crate) fn span(&self) -> Span {
 405        match self {
 406            Self::Attribute { ref span, .. } => *span,
 407            Self::Text { ref span, .. } => *span,
 408        }
 409    }
 410}
 411
 412impl TryFrom<XmlFieldMeta> for DiscardSpec {
 413    type Error = syn::Error;
 414
 415    fn try_from(other: XmlFieldMeta) -> Result<Self> {
 416        match other {
 417            XmlFieldMeta::Attribute {
 418                span,
 419                kind: AttributeKind::Generic(qname),
 420                default_,
 421                type_,
 422                codec,
 423            } => {
 424                reject_key!(default_ flag not on "discard specifications" only on "fields");
 425                reject_key!(type_ not on "discard specifications" only on "fields");
 426                reject_key!(codec not on "discard specifications" only on "fields");
 427                Ok(Self::Attribute { span, qname })
 428            }
 429            XmlFieldMeta::Text { span, type_, codec } => {
 430                reject_key!(type_ not on "discard specifications" only on "fields");
 431                reject_key!(codec not on "discard specifications" only on "fields");
 432                Ok(Self::Text { span })
 433            }
 434            other => Err(Error::new(
 435                other.span(),
 436                "cannot discard this kind of child",
 437            )),
 438        }
 439    }
 440}
 441
 442/// Wrapper around `QNameRef` which saves additional span information.
 443#[derive(Debug)]
 444pub(crate) struct SpannedQNameRef {
 445    /// The span which created the (potentially empty) ref.
 446    pub span: Span,
 447
 448    /// The ref itself.
 449    pub qname: QNameRef,
 450}
 451
 452impl SpannedQNameRef {
 453    pub(crate) fn span(&self) -> Span {
 454        self.span
 455    }
 456}
 457
 458/// Contents of an `#[xml(..)]` attribute on a struct, enum variant, or enum.
 459#[derive(Debug)]
 460pub(crate) struct XmlCompoundMeta {
 461    /// The span of the `#[xml(..)]` meta from which this was parsed.
 462    ///
 463    /// This is useful for error messages.
 464    pub(crate) span: Span,
 465
 466    /// The value assigned to `namespace` and `name` fields inside
 467    /// `#[xml(..)]`, if any.
 468    pub(crate) qname: QNameRef,
 469
 470    /// The debug flag.
 471    pub(crate) debug: Flag,
 472
 473    /// The value assigned to `builder` inside `#[xml(..)]`, if any.
 474    pub(crate) builder: Option<Ident>,
 475
 476    /// The value assigned to `iterator` inside `#[xml(..)]`, if any.
 477    pub(crate) iterator: Option<Ident>,
 478
 479    /// The value assigned to `on_unknown_attribute` inside `#[xml(..)]`, if
 480    /// any.
 481    pub(crate) on_unknown_attribute: Option<Ident>,
 482
 483    /// The value assigned to `on_unknown_child` inside `#[xml(..)]`, if
 484    /// any.
 485    pub(crate) on_unknown_child: Option<Ident>,
 486
 487    /// The exhaustive flag.
 488    pub(crate) exhaustive: Flag,
 489
 490    /// The transparent flag.
 491    pub(crate) transparent: Flag,
 492
 493    /// Items to discard.
 494    pub(crate) discard: Vec<DiscardSpec>,
 495
 496    /// The value assigned to `deserialize_callback` inside `#[xml(..)]`, if any.
 497    pub(crate) deserialize_callback: Option<Path>,
 498
 499    /// The value assigned to `attribute` inside `#[xml(..)]`, if any.
 500    pub(crate) attribute: Option<SpannedQNameRef>,
 501
 502    /// The value assigned to `value` inside `#[xml(..)]`, if any.
 503    pub(crate) value: Option<LitStr>,
 504}
 505
 506impl XmlCompoundMeta {
 507    /// Parse the meta values from a `#[xml(..)]` attribute.
 508    ///
 509    /// Undefined options or options with incompatible values are rejected
 510    /// with an appropriate compile-time error.
 511    fn parse_from_attribute(attr: &Attribute) -> Result<Self> {
 512        let mut qname = QNameRef::default();
 513        let mut builder = None;
 514        let mut iterator = None;
 515        let mut on_unknown_attribute = None;
 516        let mut on_unknown_child = None;
 517        let mut debug = Flag::Absent;
 518        let mut exhaustive = Flag::Absent;
 519        let mut transparent = Flag::Absent;
 520        let mut discard = Vec::new();
 521        let mut deserialize_callback = None;
 522        let mut attribute = None;
 523        let mut value = None;
 524
 525        attr.parse_nested_meta(|meta| {
 526            if meta.path.is_ident("debug") {
 527                if debug.is_set() {
 528                    return Err(Error::new_spanned(meta.path, "duplicate `debug` key"));
 529                }
 530                debug = (&meta.path).into();
 531                Ok(())
 532            } else if meta.path.is_ident("builder") {
 533                if builder.is_some() {
 534                    return Err(Error::new_spanned(meta.path, "duplicate `builder` key"));
 535                }
 536                builder = Some(meta.value()?.parse()?);
 537                Ok(())
 538            } else if meta.path.is_ident("iterator") {
 539                if iterator.is_some() {
 540                    return Err(Error::new_spanned(meta.path, "duplicate `iterator` key"));
 541                }
 542                iterator = Some(meta.value()?.parse()?);
 543                Ok(())
 544            } else if meta.path.is_ident("on_unknown_attribute") {
 545                if on_unknown_attribute.is_some() {
 546                    return Err(Error::new_spanned(
 547                        meta.path,
 548                        "duplicate `on_unknown_attribute` key",
 549                    ));
 550                }
 551                on_unknown_attribute = Some(meta.value()?.parse()?);
 552                Ok(())
 553            } else if meta.path.is_ident("on_unknown_child") {
 554                if on_unknown_child.is_some() {
 555                    return Err(Error::new_spanned(
 556                        meta.path,
 557                        "duplicate `on_unknown_child` key",
 558                    ));
 559                }
 560                on_unknown_child = Some(meta.value()?.parse()?);
 561                Ok(())
 562            } else if meta.path.is_ident("exhaustive") {
 563                if exhaustive.is_set() {
 564                    return Err(Error::new_spanned(meta.path, "duplicate `exhaustive` key"));
 565                }
 566                exhaustive = (&meta.path).into();
 567                Ok(())
 568            } else if meta.path.is_ident("transparent") {
 569                if transparent.is_set() {
 570                    return Err(Error::new_spanned(meta.path, "duplicate `transparent` key"));
 571                }
 572                transparent = (&meta.path).into();
 573                Ok(())
 574            } else if meta.path.is_ident("discard") {
 575                meta.parse_nested_meta(|meta| {
 576                    discard.push(XmlFieldMeta::parse_from_meta(meta)?.try_into()?);
 577                    Ok(())
 578                })?;
 579                Ok(())
 580            } else if meta.path.is_ident("deserialize_callback") {
 581                if deserialize_callback.is_some() {
 582                    return Err(Error::new_spanned(
 583                        meta.path,
 584                        "duplicate `deserialize_callback` key",
 585                    ));
 586                }
 587                deserialize_callback = Some(meta.value()?.parse()?);
 588                Ok(())
 589            } else if meta.path.is_ident("attribute") {
 590                if attribute.is_some() {
 591                    return Err(Error::new_spanned(meta.path, "duplicate `attribute` key"));
 592                }
 593
 594                let span = meta.path.span();
 595                let qname = if meta.input.peek(Token![=]) {
 596                    let (namespace, name) = parse_prefixed_name(meta.value()?)?;
 597                    QNameRef {
 598                        name: Some(name),
 599                        namespace,
 600                    }
 601                } else {
 602                    let mut qname = QNameRef::default();
 603                    meta.parse_nested_meta(|meta| {
 604                        match qname.parse_incremental_from_meta(meta)? {
 605                            None => Ok(()),
 606                            Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
 607                        }
 608                    })?;
 609                    qname
 610                };
 611
 612                attribute = Some(SpannedQNameRef { qname, span });
 613                Ok(())
 614            } else if meta.path.is_ident("value") {
 615                if value.is_some() {
 616                    return Err(Error::new_spanned(meta.path, "duplicate `value` key"));
 617                }
 618                value = Some(meta.value()?.parse()?);
 619                Ok(())
 620            } else {
 621                match qname.parse_incremental_from_meta(meta)? {
 622                    None => Ok(()),
 623                    Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
 624                }
 625            }
 626        })?;
 627
 628        Ok(Self {
 629            span: attr.span(),
 630            qname,
 631            debug,
 632            builder,
 633            iterator,
 634            on_unknown_attribute,
 635            on_unknown_child,
 636            exhaustive,
 637            transparent,
 638            discard,
 639            deserialize_callback,
 640            attribute,
 641            value,
 642        })
 643    }
 644
 645    /// Search through `attrs` for a single `#[xml(..)]` attribute and parse
 646    /// it.
 647    ///
 648    /// Undefined options or options with incompatible values are rejected
 649    /// with an appropriate compile-time error.
 650    ///
 651    /// If more than one `#[xml(..)]` attribute is found, an error is
 652    /// emitted.
 653    ///
 654    /// If no `#[xml(..)]` attribute is found, `None` is returned.
 655    pub(crate) fn try_parse_from_attributes(attrs: &[Attribute]) -> Result<Option<Self>> {
 656        let mut result = None;
 657        for attr in attrs {
 658            if !attr.path().is_ident("xml") {
 659                continue;
 660            }
 661            if result.is_some() {
 662                return Err(syn::Error::new_spanned(
 663                    attr.path(),
 664                    "only one #[xml(..)] per struct or enum variant allowed",
 665                ));
 666            }
 667            result = Some(Self::parse_from_attribute(attr)?);
 668        }
 669        Ok(result)
 670    }
 671
 672    /// Search through `attrs` for a single `#[xml(..)]` attribute and parse
 673    /// it.
 674    ///
 675    /// Undefined options or options with incompatible values are rejected
 676    /// with an appropriate compile-time error.
 677    ///
 678    /// If more than one or no `#[xml(..)]` attribute is found, an error is
 679    /// emitted.
 680    pub(crate) fn parse_from_attributes(attrs: &[Attribute]) -> Result<Self> {
 681        match Self::try_parse_from_attributes(attrs)? {
 682            Some(v) => Ok(v),
 683            None => Err(syn::Error::new(
 684                Span::call_site(),
 685                "#[xml(..)] attribute required on struct or enum variant",
 686            )),
 687        }
 688    }
 689}
 690
 691/// Return true if the tokens the cursor points at are a valid type path
 692/// prefix.
 693///
 694/// This does not advance the parse stream.
 695///
 696/// If the tokens *do* look like a type path, a Span which points at the first
 697/// `<` encountered is returned. This can be used for a helpful error message
 698/// in case parsing the type path does then fail.
 699fn maybe_type_path(p: parse::ParseStream<'_>) -> (bool, Option<Span>) {
 700    // ParseStream cursors do not advance the stream, but they are also rather
 701    // unwieldy to use. Prepare for a lot of `let .. = ..`.
 702
 703    let cursor = if p.peek(token::PathSep) {
 704        // If we have a path separator, we need to skip that initially. We
 705        // do this by skipping two punctuations. We use unwrap() here because
 706        // we already know for sure that we see two punctuation items (because
 707        // of the peek).
 708        p.cursor().punct().unwrap().1.punct().unwrap().1
 709    } else {
 710        // No `::` initially, so we just take what we have.
 711        p.cursor()
 712    };
 713
 714    // Now we loop over `$ident::` segments. If we find anything but a `:`
 715    // after the ident, we exit. Depending on *what* we find, we either exit
 716    // true or false, but see for yourself.
 717    let mut cursor = cursor;
 718    loop {
 719        // Here we look for the identifier, but we do not care for its
 720        // contents.
 721        let Some((_, new_cursor)) = cursor.ident() else {
 722            return (false, None);
 723        };
 724        cursor = new_cursor;
 725
 726        // Now we see what actually follows the ident (it must be punctuation
 727        // for it to be a type path...)
 728        let Some((punct, new_cursor)) = cursor.punct() else {
 729            return (false, None);
 730        };
 731        cursor = new_cursor;
 732
 733        match punct.as_char() {
 734            // Looks like a `foo<..`, we treat that as a type path for the
 735            // reasons stated in [`parse_codec_expr`]'s doc.
 736            '<' => return (true, Some(punct.span())),
 737
 738            // Continue looking ahead: looks like a path separator.
 739            ':' => (),
 740
 741            // Anything else (such as `,` (separating another argument most
 742            // likely), or `.` (a method call?)) we treat as "not a type
 743            // path".
 744            _ => return (false, None),
 745        }
 746
 747        // If we are here, we saw a `:`. Look for the second one.
 748        let Some((punct, new_cursor)) = cursor.punct() else {
 749            return (false, None);
 750        };
 751        cursor = new_cursor;
 752
 753        if punct.as_char() != ':' {
 754            // If it is not another `:`, it cannot be a type path.
 755            return (false, None);
 756        }
 757
 758        // And round and round and round it goes.
 759        // We will terminate eventually because the cursor will return None
 760        // on any of the lookups because parse streams are (hopefully!)
 761        // finite. Most likely, we'll however encounter a `<` or other non-`:`
 762        // punctuation first.
 763    }
 764}
 765
 766/// Parse expressions passed to `codec`.
 767///
 768/// Those will generally be paths to unit type constructors (such as `Foo`)
 769/// or references to static values or chains of function calls.
 770///
 771/// In the case of unit type constructors for generic types, users may type
 772/// for example `FixedHex<20>`, thinking they are writing a type path. However,
 773/// while `FixedHex<20>` is indeed a valid type path, it is not a valid
 774/// expression for a unit type constructor. Instead it is parsed as
 775/// `FixedHex < 20` and then a syntax error.
 776///
 777/// We however know that `Foo < Bar` is never a valid expression for a type.
 778/// Thus, we can be smart about this and inject the `::` at the right place
 779/// automatically.
 780fn parse_codec_expr(p: parse::ParseStream<'_>) -> Result<(Expr, Option<Error>)> {
 781    let (maybe_type_path, punct_span) = maybe_type_path(p);
 782    if maybe_type_path {
 783        let helpful_error =
 784            punct_span.map(|span| Error::new(span, "help: try inserting a `::` before this `<`"));
 785        let mut type_path: TypePath = match p.parse() {
 786            Ok(v) => v,
 787            Err(mut e) => match helpful_error {
 788                Some(help) => {
 789                    e.combine(help);
 790                    return Err(e);
 791                }
 792                None => return Err(e),
 793            },
 794        };
 795        // We got a type path -- so we now inject the `::` before any `<` as
 796        // needed.
 797        for segment in type_path.path.segments.iter_mut() {
 798            if let PathArguments::AngleBracketed(ref mut arguments) = segment.arguments {
 799                let span = arguments.span();
 800                arguments.colon2_token.get_or_insert(token::PathSep {
 801                    spans: [span, span],
 802                });
 803            }
 804        }
 805        Ok((
 806            Expr::Path(ExprPath {
 807                attrs: Vec::new(),
 808                qself: type_path.qself,
 809                path: type_path.path,
 810            }),
 811            helpful_error,
 812        ))
 813    } else {
 814        p.parse().map(|x| (x, None))
 815    }
 816}
 817
 818/// Parse an XML name while resolving built-in namespace prefixes.
 819fn parse_prefixed_name(
 820    value: syn::parse::ParseStream<'_>,
 821) -> Result<(Option<NamespaceRef>, NameRef)> {
 822    if !value.peek(LitStr) {
 823        // if we don't have a string literal next, we delegate to the default
 824        // `NameRef` parser.
 825        return Ok((None, value.parse()?));
 826    }
 827
 828    let name: LitStr = value.parse()?;
 829    let name_span = name.span();
 830    let (prefix, name) = match name
 831        .value()
 832        .try_into()
 833        .and_then(|name: rxml_validation::Name| name.split_name())
 834    {
 835        Ok(v) => v,
 836        Err(e) => {
 837            return Err(Error::new(
 838                name_span,
 839                format!("not a valid XML name: {}", e),
 840            ))
 841        }
 842    };
 843    let name = NameRef::Literal {
 844        value: name,
 845        span: name_span,
 846    };
 847    if let Some(prefix) = prefix {
 848        let namespace_uri = match prefix.as_str() {
 849            "xml" => XMLNS_XML,
 850            "xmlns" => XMLNS_XMLNS,
 851            other => return Err(Error::new(
 852                name_span,
 853                format!("prefix `{}` is not a built-in prefix and cannot be used. specify the desired namespace using the `namespace` key instead.", other)
 854            )),
 855        };
 856        Ok((Some(NamespaceRef::fudge(namespace_uri, name_span)), name))
 857    } else {
 858        Ok((None, name))
 859    }
 860}
 861
 862/// XML attribute subtypes for `#[xml(attribute)]` and `#[xml(lang)]`.
 863#[derive(Debug)]
 864pub(crate) enum AttributeKind {
 865    /// Any generic attribute (`#[xml(attribute)]`).
 866    Generic(QNameRef),
 867
 868    /// The special `xml:lang` attribute (`#[xml(lang)]`).
 869    XmlLang,
 870}
 871
 872/// Contents of an `#[xml(..)]` attribute on a struct or enum variant member.
 873#[derive(Debug)]
 874pub(crate) enum XmlFieldMeta {
 875    /// `#[xml(attribute)]`, `#[xml(attribute = ..)]` or `#[xml(attribute(..))]`, `#[xml(lang)]`
 876    Attribute {
 877        /// The span of the `#[xml(attribute)]` meta from which this was parsed.
 878        ///
 879        /// This is useful for error messages.
 880        span: Span,
 881
 882        /// Attribute subtype (normal vs. `xml:lang`).
 883        kind: AttributeKind,
 884
 885        /// The `default` flag.
 886        default_: Flag,
 887
 888        /// An explicit type override, only usable within extracts.
 889        type_: Option<Type>,
 890
 891        /// The path to the optional codec type.
 892        codec: Option<Expr>,
 893    },
 894
 895    /// `#[xml(text)]`
 896    Text {
 897        /// The span of the `#[xml(text)]` meta from which this was parsed.
 898        ///
 899        /// This is useful for error messages.
 900        span: Span,
 901
 902        /// The path to the optional codec type.
 903        codec: Option<Expr>,
 904
 905        /// An explicit type override, only usable within extracts.
 906        type_: Option<Type>,
 907    },
 908
 909    /// `#[xml(child)`
 910    Child {
 911        /// The span of the `#[xml(child)]` meta from which this was parsed.
 912        ///
 913        /// This is useful for error messages.
 914        span: Span,
 915
 916        /// The `default` flag.
 917        default_: Flag,
 918
 919        /// The `n` flag.
 920        amount: Option<AmountConstraint>,
 921    },
 922
 923    /// `#[xml(extract)]
 924    Extract {
 925        /// The span of the `#[xml(extract)]` meta from which this was parsed.
 926        ///
 927        /// This is useful for error messages.
 928        span: Span,
 929
 930        /// The namespace/name keys.
 931        qname: QNameRef,
 932
 933        /// The `n` flag.
 934        amount: Option<AmountConstraint>,
 935
 936        /// The `default` flag.
 937        default_: Flag,
 938
 939        /// The `fields` nested meta.
 940        fields: Vec<XmlFieldMeta>,
 941
 942        /// The `on_unknown_attribute` value.
 943        on_unknown_attribute: Option<Ident>,
 944
 945        /// The `on_unknown_child` value.
 946        on_unknown_child: Option<Ident>,
 947    },
 948
 949    /// `#[xml(element)]`
 950    Element {
 951        /// The span of the `#[xml(element)]` meta from which this was parsed.
 952        ///
 953        /// This is useful for error messages.
 954        span: Span,
 955
 956        /// The `default` flag.
 957        default_: Flag,
 958
 959        /// The `n` flag.
 960        amount: Option<AmountConstraint>,
 961    },
 962
 963    /// `#[xml(flag)]
 964    Flag {
 965        /// The span of the `#[xml(flag)]` meta from which this was parsed.
 966        ///
 967        /// This is useful for error messages.
 968        span: Span,
 969
 970        /// The namespace/name keys.
 971        qname: QNameRef,
 972    },
 973}
 974
 975impl XmlFieldMeta {
 976    /// Parse a `#[xml(attribute(..))]` meta.
 977    ///
 978    /// That meta can have three distinct syntax styles:
 979    /// - argument-less: `#[xml(attribute)]`
 980    /// - shorthand: `#[xml(attribute = ..)]`
 981    /// - full: `#[xml(attribute(..))]`
 982    fn attribute_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
 983        if meta.input.peek(Token![=]) {
 984            // shorthand syntax
 985            let (namespace, name) = parse_prefixed_name(meta.value()?)?;
 986            Ok(Self::Attribute {
 987                span: meta.path.span(),
 988                kind: AttributeKind::Generic(QNameRef {
 989                    name: Some(name),
 990                    namespace,
 991                }),
 992                default_: Flag::Absent,
 993                type_: None,
 994                codec: None,
 995            })
 996        } else if meta.input.peek(syn::token::Paren) {
 997            // full syntax
 998            let mut qname = QNameRef::default();
 999            let mut default_ = Flag::Absent;
1000            let mut type_ = None;
1001            let mut codec = None;
1002            meta.parse_nested_meta(|meta| {
1003                if meta.path.is_ident("default") {
1004                    if default_.is_set() {
1005                        return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
1006                    }
1007                    default_ = (&meta.path).into();
1008                    Ok(())
1009                } else if meta.path.is_ident("type_") {
1010                    if type_.is_some() {
1011                        return Err(Error::new_spanned(meta.path, "duplicate `type_` key"));
1012                    }
1013                    type_ = Some(meta.value()?.parse()?);
1014                    Ok(())
1015                } else if meta.path.is_ident("codec") {
1016                    if codec.is_some() {
1017                        return Err(Error::new_spanned(meta.path, "duplicate `codec` key"));
1018                    }
1019                    let (new_codec, helpful_error) = parse_codec_expr(meta.value()?)?;
1020                    // See the comment at the top of text_from_meta() below for why we
1021                    // do this.
1022                    let lookahead = meta.input.lookahead1();
1023                    if !lookahead.peek(Token![,]) && !meta.input.is_empty() {
1024                        if let Some(helpful_error) = helpful_error {
1025                            let mut e = lookahead.error();
1026                            e.combine(helpful_error);
1027                            return Err(e);
1028                        }
1029                    }
1030                    codec = Some(new_codec);
1031                    Ok(())
1032                } else {
1033                    match qname.parse_incremental_from_meta(meta)? {
1034                        None => Ok(()),
1035                        Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
1036                    }
1037                }
1038            })?;
1039            Ok(Self::Attribute {
1040                span: meta.path.span(),
1041                kind: AttributeKind::Generic(qname),
1042                default_,
1043                type_,
1044                codec,
1045            })
1046        } else {
1047            // argument-less syntax
1048            Ok(Self::Attribute {
1049                span: meta.path.span(),
1050                kind: AttributeKind::Generic(QNameRef::default()),
1051                default_: Flag::Absent,
1052                type_: None,
1053                codec: None,
1054            })
1055        }
1056    }
1057
1058    /// Parse a `#[xml(text)]` meta.
1059    fn text_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
1060        if meta.input.peek(Token![=]) {
1061            let (codec, helpful_error) = parse_codec_expr(meta.value()?)?;
1062            // A meta value can only be followed by either a `,`, or the end
1063            // of the parse stream (because of the delimited group ending).
1064            // Hence we check we are there. And if we are *not* there, we emit
1065            // an error straight away, with the helpful addition from the
1066            // `parse_codec_expr` if we have it.
1067            //
1068            // If we do not do this, the user gets a rather confusing
1069            // "expected `,`" message if the `maybe_type_path` guess was
1070            // wrong.
1071            let lookahead = meta.input.lookahead1();
1072            if !lookahead.peek(Token![,]) && !meta.input.is_empty() {
1073                if let Some(helpful_error) = helpful_error {
1074                    let mut e = lookahead.error();
1075                    e.combine(helpful_error);
1076                    return Err(e);
1077                }
1078            }
1079            Ok(Self::Text {
1080                span: meta.path.span(),
1081                type_: None,
1082                codec: Some(codec),
1083            })
1084        } else if meta.input.peek(syn::token::Paren) {
1085            let mut codec: Option<Expr> = None;
1086            let mut type_: Option<Type> = None;
1087            meta.parse_nested_meta(|meta| {
1088                if meta.path.is_ident("codec") {
1089                    if codec.is_some() {
1090                        return Err(Error::new_spanned(meta.path, "duplicate `codec` key"));
1091                    }
1092                    let (new_codec, helpful_error) = parse_codec_expr(meta.value()?)?;
1093                    // See above (at the top-ish of this function) for why we
1094                    // do this.
1095                    let lookahead = meta.input.lookahead1();
1096                    if !lookahead.peek(Token![,]) && !meta.input.is_empty() {
1097                        if let Some(helpful_error) = helpful_error {
1098                            let mut e = lookahead.error();
1099                            e.combine(helpful_error);
1100                            return Err(e);
1101                        }
1102                    }
1103                    codec = Some(new_codec);
1104                    Ok(())
1105                } else if meta.path.is_ident("type_") {
1106                    if type_.is_some() {
1107                        return Err(Error::new_spanned(meta.path, "duplicate `type_` key"));
1108                    }
1109                    type_ = Some(meta.value()?.parse()?);
1110                    Ok(())
1111                } else {
1112                    Err(Error::new_spanned(meta.path, "unsupported key"))
1113                }
1114            })?;
1115            Ok(Self::Text {
1116                span: meta.path.span(),
1117                type_,
1118                codec,
1119            })
1120        } else {
1121            Ok(Self::Text {
1122                span: meta.path.span(),
1123                type_: None,
1124                codec: None,
1125            })
1126        }
1127    }
1128
1129    /// Parse a `#[xml(child)]` meta.
1130    fn child_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
1131        if meta.input.peek(syn::token::Paren) {
1132            let mut default_ = Flag::Absent;
1133            let mut amount = None;
1134            meta.parse_nested_meta(|meta| {
1135                if meta.path.is_ident("default") {
1136                    if default_.is_set() {
1137                        return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
1138                    }
1139                    default_ = (&meta.path).into();
1140                    Ok(())
1141                } else if meta.path.is_ident("n") {
1142                    if amount.is_some() {
1143                        return Err(Error::new_spanned(meta.path, "duplicate `n` key"));
1144                    }
1145                    amount = Some(meta.value()?.parse()?);
1146                    Ok(())
1147                } else {
1148                    Err(Error::new_spanned(meta.path, "unsupported key"))
1149                }
1150            })?;
1151            Ok(Self::Child {
1152                span: meta.path.span(),
1153                default_,
1154                amount,
1155            })
1156        } else {
1157            Ok(Self::Child {
1158                span: meta.path.span(),
1159                default_: Flag::Absent,
1160                amount: None,
1161            })
1162        }
1163    }
1164
1165    /// Parse a `#[xml(extract)]` meta.
1166    fn extract_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
1167        let mut qname = QNameRef::default();
1168        let mut fields = None;
1169        let mut amount = None;
1170        let mut on_unknown_attribute = None;
1171        let mut on_unknown_child = None;
1172        let mut default_ = Flag::Absent;
1173        meta.parse_nested_meta(|meta| {
1174            if meta.path.is_ident("default") {
1175                if default_.is_set() {
1176                    return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
1177                }
1178                default_ = (&meta.path).into();
1179                Ok(())
1180            } else if meta.path.is_ident("fields") {
1181                if let Some((fields_span, _)) = fields.as_ref() {
1182                    let mut error = Error::new_spanned(meta.path, "duplicate `fields` meta");
1183                    error.combine(Error::new(*fields_span, "previous `fields` meta was here"));
1184                    return Err(error);
1185                }
1186                let mut new_fields = Vec::new();
1187                meta.parse_nested_meta(|meta| {
1188                    new_fields.push(XmlFieldMeta::parse_from_meta(meta)?);
1189                    Ok(())
1190                })?;
1191                fields = Some((meta.path.span(), new_fields));
1192                Ok(())
1193            } else if meta.path.is_ident("n") {
1194                if amount.is_some() {
1195                    return Err(Error::new_spanned(meta.path, "duplicate `n` key"));
1196                }
1197                amount = Some(meta.value()?.parse()?);
1198                Ok(())
1199            } else if meta.path.is_ident("on_unknown_attribute") {
1200                if on_unknown_attribute.is_some() {
1201                    return Err(Error::new_spanned(
1202                        meta.path,
1203                        "duplicate `on_unknown_attribute` key",
1204                    ));
1205                }
1206                on_unknown_attribute = Some(meta.value()?.parse()?);
1207                Ok(())
1208            } else if meta.path.is_ident("on_unknown_child") {
1209                if on_unknown_child.is_some() {
1210                    return Err(Error::new_spanned(
1211                        meta.path,
1212                        "duplicate `on_unknown_child` key",
1213                    ));
1214                }
1215                on_unknown_child = Some(meta.value()?.parse()?);
1216                Ok(())
1217            } else {
1218                match qname.parse_incremental_from_meta(meta)? {
1219                    None => Ok(()),
1220                    Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
1221                }
1222            }
1223        })?;
1224        let fields = fields.map(|(_, x)| x).unwrap_or_else(Vec::new);
1225        Ok(Self::Extract {
1226            span: meta.path.span(),
1227            default_,
1228            qname,
1229            fields,
1230            amount,
1231            on_unknown_attribute,
1232            on_unknown_child,
1233        })
1234    }
1235
1236    /// Parse a `#[xml(element)]` meta.
1237    fn element_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
1238        let mut amount = None;
1239        let mut default_ = Flag::Absent;
1240        if meta.input.peek(syn::token::Paren) {
1241            meta.parse_nested_meta(|meta| {
1242                if meta.path.is_ident("default") {
1243                    if default_.is_set() {
1244                        return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
1245                    }
1246                    default_ = (&meta.path).into();
1247                    Ok(())
1248                } else if meta.path.is_ident("n") {
1249                    if amount.is_some() {
1250                        return Err(Error::new_spanned(meta.path, "duplicate `n` key"));
1251                    }
1252                    amount = Some(meta.value()?.parse()?);
1253                    Ok(())
1254                } else {
1255                    Err(Error::new_spanned(meta.path, "unsupported key"))
1256                }
1257            })?;
1258        }
1259        Ok(Self::Element {
1260            span: meta.path.span(),
1261            default_,
1262            amount,
1263        })
1264    }
1265
1266    /// Parse a `#[xml(flag)]` meta.
1267    fn flag_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
1268        let mut qname = QNameRef::default();
1269        if meta.input.peek(syn::token::Paren) {
1270            meta.parse_nested_meta(|meta| match qname.parse_incremental_from_meta(meta)? {
1271                None => Ok(()),
1272                Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
1273            })?;
1274        }
1275        Ok(Self::Flag {
1276            span: meta.path.span(),
1277            qname,
1278        })
1279    }
1280
1281    /// Parse a `#[xml(lang)]` meta.
1282    fn lang_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
1283        let mut default_ = Flag::Absent;
1284        let mut type_ = None;
1285        let mut codec = None;
1286
1287        if meta.input.peek(syn::token::Paren) {
1288            meta.parse_nested_meta(|meta| {
1289                if meta.path.is_ident("default") {
1290                    if default_.is_set() {
1291                        return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
1292                    }
1293                    default_ = (&meta.path).into();
1294                    Ok(())
1295                } else if meta.path.is_ident("type_") {
1296                    if type_.is_some() {
1297                        return Err(Error::new_spanned(meta.path, "duplicate `type_` key"));
1298                    }
1299                    type_ = Some(meta.value()?.parse()?);
1300                    Ok(())
1301                } else if meta.path.is_ident("codec") {
1302                    if codec.is_some() {
1303                        return Err(Error::new_spanned(meta.path, "duplicate `codec` key"));
1304                    }
1305                    let (new_codec, helpful_error) = parse_codec_expr(meta.value()?)?;
1306                    // See the comment at the top of text_from_meta() below for why we
1307                    // do this.
1308                    let lookahead = meta.input.lookahead1();
1309                    if !lookahead.peek(Token![,]) && !meta.input.is_empty() {
1310                        if let Some(helpful_error) = helpful_error {
1311                            let mut e = lookahead.error();
1312                            e.combine(helpful_error);
1313                            return Err(e);
1314                        }
1315                    }
1316                    codec = Some(new_codec);
1317                    Ok(())
1318                } else {
1319                    Err(Error::new_spanned(meta.path, "unsupported key"))
1320                }
1321            })?;
1322        }
1323
1324        Ok(Self::Attribute {
1325            span: meta.path.span(),
1326            kind: AttributeKind::XmlLang,
1327            default_,
1328            type_,
1329            codec,
1330        })
1331    }
1332
1333    /// Parse [`Self`] from a nestd meta, switching on the identifier
1334    /// of that nested meta.
1335    fn parse_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
1336        if meta.path.is_ident("attribute") {
1337            Self::attribute_from_meta(meta)
1338        } else if meta.path.is_ident("text") {
1339            Self::text_from_meta(meta)
1340        } else if meta.path.is_ident("child") {
1341            Self::child_from_meta(meta)
1342        } else if meta.path.is_ident("extract") {
1343            Self::extract_from_meta(meta)
1344        } else if meta.path.is_ident("element") {
1345            Self::element_from_meta(meta)
1346        } else if meta.path.is_ident("flag") {
1347            Self::flag_from_meta(meta)
1348        } else if meta.path.is_ident("lang") {
1349            Self::lang_from_meta(meta)
1350        } else {
1351            Err(Error::new_spanned(meta.path, "unsupported field meta"))
1352        }
1353    }
1354
1355    /// Parse an `#[xml(..)]` meta on a field.
1356    ///
1357    /// This switches based on the first identifier within the `#[xml(..)]`
1358    /// meta and generates an enum variant accordingly.
1359    ///
1360    /// Only a single nested meta is allowed; more than one will be
1361    /// rejected with an appropriate compile-time error.
1362    ///
1363    /// If no meta is contained at all, a compile-time error is generated.
1364    ///
1365    /// Undefined options or options with incompatible values are rejected
1366    /// with an appropriate compile-time error.
1367    pub(crate) fn parse_from_attribute(attr: &Attribute) -> Result<Self> {
1368        let mut result: Option<Self> = None;
1369
1370        attr.parse_nested_meta(|meta| {
1371            if result.is_some() {
1372                return Err(Error::new_spanned(
1373                    meta.path,
1374                    "multiple field type specifiers are not supported",
1375                ));
1376            }
1377
1378            result = Some(Self::parse_from_meta(meta)?);
1379            Ok(())
1380        })?;
1381
1382        if let Some(result) = result {
1383            Ok(result)
1384        } else {
1385            Err(Error::new_spanned(
1386                attr,
1387                "missing field type specifier within `#[xml(..)]`",
1388            ))
1389        }
1390    }
1391
1392    /// Find and parse a `#[xml(..)]` meta on a field.
1393    ///
1394    /// This invokes [`Self::parse_from_attribute`] internally on the first
1395    /// encountered `#[xml(..)]` meta.
1396    ///
1397    /// If not exactly one `#[xml(..)]` meta is encountered, an error is
1398    /// returned. The error is spanned to `err_span`.
1399    pub(crate) fn parse_from_attributes(attrs: &[Attribute], err_span: &Span) -> Result<Self> {
1400        let mut result: Option<Self> = None;
1401        for attr in attrs {
1402            if !attr.path().is_ident("xml") {
1403                continue;
1404            }
1405
1406            if result.is_some() {
1407                return Err(Error::new_spanned(
1408                    attr,
1409                    "only one #[xml(..)] attribute per field allowed.",
1410                ));
1411            }
1412
1413            result = Some(Self::parse_from_attribute(attr)?);
1414        }
1415
1416        if let Some(result) = result {
1417            Ok(result)
1418        } else {
1419            Err(Error::new(*err_span, "missing #[xml(..)] meta on field"))
1420        }
1421    }
1422
1423    /// Return a span which points at the meta which constructed this
1424    /// XmlFieldMeta.
1425    pub(crate) fn span(&self) -> Span {
1426        match self {
1427            Self::Attribute { ref span, .. } => *span,
1428            Self::Child { ref span, .. } => *span,
1429            Self::Text { ref span, .. } => *span,
1430            Self::Extract { ref span, .. } => *span,
1431            Self::Element { ref span, .. } => *span,
1432            Self::Flag { ref span, .. } => *span,
1433        }
1434    }
1435
1436    /// Extract an explicit type specification if it exists.
1437    pub(crate) fn take_type(&mut self) -> Option<Type> {
1438        match self {
1439            Self::Attribute { ref mut type_, .. } => type_.take(),
1440            Self::Text { ref mut type_, .. } => type_.take(),
1441            _ => None,
1442        }
1443    }
1444}