Skip to main content

dash_runtime/
error.rs

1//! Typed errors for MPD parsing.
2
3use broadcast_common::impl_spec_display;
4use thiserror::Error;
5
6/// Which bound of [`crate::limits::Limits`] was exceeded.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum Limit {
10    /// Document size in bytes.
11    InputBytes,
12    /// Element nesting depth.
13    Depth,
14    /// Total element count.
15    Elements,
16    /// Length of one attribute value.
17    AttributeBytes,
18    /// Attributes on one element.
19    Attributes,
20    /// `Period` count.
21    Periods,
22    /// `AdaptationSet` count in one Period.
23    AdaptationSets,
24    /// `Representation` count in one AdaptationSet.
25    Representations,
26    /// `S` entries in one `SegmentTimeline`.
27    TimelineEntries,
28    /// `BaseURL` alternates on one level.
29    BaseUrls,
30    /// `SegmentURL` entries in one `SegmentList`.
31    SegmentUrls,
32}
33
34impl Limit {
35    /// Stable snake_case label.
36    #[must_use]
37    pub fn name(&self) -> &'static str {
38        match self {
39            Self::InputBytes => "input_bytes",
40            Self::Depth => "depth",
41            Self::Elements => "elements",
42            Self::AttributeBytes => "attribute_bytes",
43            Self::Attributes => "attributes",
44            Self::Periods => "periods",
45            Self::AdaptationSets => "adaptation_sets",
46            Self::Representations => "representations",
47            Self::TimelineEntries => "timeline_entries",
48            Self::BaseUrls => "base_urls",
49            Self::SegmentUrls => "segment_urls",
50        }
51    }
52}
53impl_spec_display!(Limit);
54
55/// A feature the 0.1 core recognises but deliberately does not implement.
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57#[non_exhaustive]
58pub enum Unsupported {
59    /// `MPD@type="list"` (ISO/IEC 23009-1 Ed.6).
60    PresentationTypeList,
61    /// Segment sequences: `S@k` above 1 or a `$SubNumber$` template.
62    SegmentSequence,
63    /// A `data:` URL used as a Segment address (5.3.9.1 b).
64    DataUrl,
65    /// A byte range with no last byte (`a-`).
66    OpenEndedRange,
67    /// A `sidx` reference that points at another `sidx`.
68    HierarchicalSidx,
69}
70
71impl Unsupported {
72    /// Stable snake_case label.
73    #[must_use]
74    pub fn name(&self) -> &'static str {
75        match self {
76            Self::PresentationTypeList => "presentation_type_list",
77            Self::SegmentSequence => "segment_sequence",
78            Self::DataUrl => "data_url",
79            Self::OpenEndedRange => "open_ended_range",
80            Self::HierarchicalSidx => "hierarchical_sidx",
81        }
82    }
83}
84impl_spec_display!(Unsupported);
85
86/// Why an MPD document was rejected.
87#[derive(Debug, Clone, PartialEq, Eq, Error)]
88#[non_exhaustive]
89pub enum MpdError {
90    /// The bytes are not UTF-8.
91    #[error("MPD is not valid UTF-8 (valid up to byte {valid_up_to})")]
92    InvalidUtf8 {
93        /// Length of the valid prefix.
94        valid_up_to: usize,
95    },
96    /// The document is not well-formed XML (or uses a construct this parser
97    /// refuses, such as a DOCTYPE).
98    #[error("XML error at byte {pos}: {message}")]
99    Xml {
100        /// Byte offset where the reader stopped.
101        pos: usize,
102        /// What was wrong.
103        message: String,
104    },
105    /// The root element is not `MPD` in the MPD namespace.
106    #[error("document root is not an MPD in the MPD namespace (found `{found}`)")]
107    NotMpd {
108        /// Local name of the root element.
109        found: String,
110    },
111    /// An attribute or element violates the schema rules the core relies on.
112    #[error("invalid MPD: {what}: {detail}")]
113    Invalid {
114        /// The attribute or rule.
115        what: &'static str,
116        /// The offending value or an explanation.
117        detail: String,
118    },
119    /// A hostile-input bound was exceeded.
120    #[error("MPD exceeds the {limit} limit of {max}")]
121    TooLarge {
122        /// Which bound.
123        limit: Limit,
124        /// Its value.
125        max: usize,
126    },
127    /// A feature outside the 0.1 scope.
128    #[error("unsupported: {0}")]
129    Unsupported(Unsupported),
130}