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}