Skip to main content

dvb_si/
error.rs

1//! Error type returned by every parser in this crate.
2
3use thiserror::Error;
4
5/// Crate-wide result alias.
6pub type Result<T> = core::result::Result<T, Error>;
7
8/// Error variants that parsers + builders can return.
9///
10/// Spec references inside `#[error(...)]` strings quote clauses from
11/// ETSI EN 300 468 v1.19.1 where applicable.
12#[derive(Debug, Error, PartialEq, Eq)]
13#[non_exhaustive]
14pub enum Error {
15    /// Input buffer was shorter than the smallest valid encoding for the type.
16    #[error("buffer too short: need {need} bytes, have {have} (while parsing {what})")]
17    BufferTooShort {
18        /// Bytes required to proceed.
19        need: usize,
20        /// Bytes actually available.
21        have: usize,
22        /// Human-readable name of the type or field being parsed.
23        what: &'static str,
24    },
25
26    /// CRC-32 validation failed for a table section.
27    #[error("CRC-32 mismatch: computed {computed:#010x}, expected {expected:#010x}")]
28    CrcMismatch {
29        /// CRC we calculated over the section bytes.
30        computed: u32,
31        /// CRC carried at the end of the section.
32        expected: u32,
33    },
34
35    /// `table_id` byte doesn't match any expected value for the parser invoked.
36    #[error("unexpected table_id {table_id:#04x} for {what} (expected one of {expected:?})")]
37    UnexpectedTableId {
38        /// Byte value actually read.
39        table_id: u8,
40        /// Table names or parser expecting it.
41        what: &'static str,
42        /// The permitted set.
43        expected: &'static [u8],
44    },
45
46    /// Descriptor payload failed semantic validation.
47    #[error("invalid descriptor (tag {tag:#04x}): {reason}")]
48    InvalidDescriptor {
49        /// Descriptor tag being parsed.
50        tag: u8,
51        /// Specific failure reason.
52        reason: &'static str,
53    },
54
55    /// A decoded value passed to a `set_*` accessor could not be encoded to the
56    /// field's fixed wire representation (e.g. a duration ≥ 100 hours, or a date
57    /// outside the 16-bit MJD range).
58    #[error("value out of range for {field}: {reason}")]
59    ValueOutOfRange {
60        /// Field being set.
61        field: &'static str,
62        /// Why the value is not representable.
63        reason: &'static str,
64    },
65
66    /// A `section_length` declared more bytes than the containing buffer could hold.
67    #[error("section_length {declared} exceeds remaining buffer ({available} bytes)")]
68    SectionLengthOverflow {
69        /// Length bytes declared inside the section header.
70        declared: usize,
71        /// Bytes actually available after the header.
72        available: usize,
73    },
74
75    /// A reserved bit was not in the expected state. Most parsers are permissive
76    /// about reserved bits; this variant is only emitted when a spec clause
77    /// specifically requires a value.
78    #[error("reserved bits violation in {field}: {reason}")]
79    ReservedBitsViolation {
80        /// Where.
81        field: &'static str,
82        /// Why.
83        reason: &'static str,
84    },
85
86    /// Write buffer passed to `serialize_into` was smaller than `serialized_len()`.
87    #[error("serialize: output buffer too small — need {need}, have {have}")]
88    OutputBufferTooSmall {
89        /// Required size.
90        need: usize,
91        /// Actual size.
92        have: usize,
93    },
94
95    /// TS sync byte was not the expected `0x47`.
96    #[error("invalid TS sync byte: expected 0x47, got {found:#04x}")]
97    InvalidSyncByte {
98        /// The byte actually read at position 0.
99        found: u8,
100    },
101
102    /// A serializer's length or count value did not fit its wire field.
103    /// Returned instead of silently narrowing (`as u8`/`as u16`/masking),
104    /// which would emit a misframed section (see #1129).
105    #[error(transparent)]
106    FieldOverflow(#[from] broadcast_common::len::FieldOverflow),
107}
108
109impl From<mpeg_ts::Error> for Error {
110    fn from(e: mpeg_ts::Error) -> Self {
111        match e {
112            mpeg_ts::Error::BufferTooShort { need, have, what } => {
113                Error::BufferTooShort { need, have, what }
114            }
115            mpeg_ts::Error::CrcMismatch { computed, expected } => {
116                Error::CrcMismatch { computed, expected }
117            }
118            mpeg_ts::Error::InvalidSyncByte { found } => Error::InvalidSyncByte { found },
119            mpeg_ts::Error::OutputBufferTooSmall { need, have } => {
120                Error::OutputBufferTooSmall { need, have }
121            }
122            mpeg_ts::Error::SectionLengthOverflow {
123                declared,
124                available,
125            } => Error::SectionLengthOverflow {
126                declared,
127                available,
128            },
129            // mpeg_ts::Error is #[non_exhaustive]; catch future variants generically.
130            _ => Error::BufferTooShort {
131                need: 0,
132                have: 0,
133                what: "mpeg_ts (unknown error)",
134            },
135        }
136    }
137}