Skip to main content

ssai_runtime/
error.rs

1//! Crate error type.
2
3use alloc::string::String;
4
5/// Errors produced by session, decision, splice-conditioning, and playlist
6/// rendering operations.
7#[derive(Debug, thiserror::Error, Clone, PartialEq)]
8#[non_exhaustive]
9pub enum Error {
10    /// [`crate::splice::condition_splice_point`] found no candidate boundary
11    /// within the caller's tolerance.
12    #[error(
13        "no candidate splice boundary within {tolerance_ticks} ticks of requested pts \
14         {requested_pts} (nearest delta {nearest_delta_ticks} ticks)"
15    )]
16    NoAlignedBoundary {
17        /// The cue's nominal target.
18        requested_pts: u64,
19        /// The caller's maximum acceptable drift.
20        tolerance_ticks: u64,
21        /// The delta of the nearest candidate actually found.
22        nearest_delta_ticks: u64,
23    },
24    /// [`crate::splice::condition_splice_point`] was called with an empty
25    /// candidate slice.
26    #[error("no candidate splice boundaries supplied")]
27    NoCandidates,
28    /// A PTS value (or the modulus itself) passed to
29    /// [`crate::splice::condition_splice_point_wrapping`] was not below a
30    /// non-zero modulus (issue #1125 / audit r14-SSAI-W2).
31    #[error("pts {pts} is not below the clock modulus {modulus} (or the modulus is zero)")]
32    PtsOutOfRange {
33        /// The offending value.
34        pts: u64,
35        /// The wrap modulus supplied.
36        modulus: u64,
37    },
38    /// The base playlist carries no `#EXT-X-PROGRAM-DATE-TIME` tag, which
39    /// RFC 8216bis §4.4.5.1 requires of any playlist containing an
40    /// `EXT-X-DATERANGE` (issue #1125 / audit r14-SSAI-W3).
41    #[error("base playlist has no EXT-X-PROGRAM-DATE-TIME; an EXT-X-DATERANGE requires one")]
42    MissingProgramDateTime,
43    /// An interstitial asset source was neither `X-ASSET-URI` nor
44    /// `X-ASSET-LIST` — Appendix D §D.2 requires exactly one.
45    #[error("interstitial asset source must be exactly one of X-ASSET-URI or X-ASSET-LIST")]
46    InvalidAssetSource,
47    /// [`crate::session::SessionStore`] has no record for the session.
48    #[error("session {0:?} has no active ad break")]
49    NoActiveBreak(String),
50    /// [`crate::session::SessionStore::begin_break`] was called for a
51    /// session that already has an unresumed break.
52    #[error("session {0:?} already has an active ad break")]
53    BreakAlreadyActive(String),
54    /// [`crate::session::SessionStore::resume`] was called for a session whose
55    /// break was already resumed.
56    #[error("session {0:?} has already resumed its ad break")]
57    BreakAlreadyResumed(String),
58    /// [`crate::session::SessionStore::begin_break`] was called for a new
59    /// session while the store was already tracking its maximum.
60    #[error("session store is full ({max} sessions)")]
61    SessionStoreFull {
62        /// The store's bound.
63        max: usize,
64    },
65    /// An Interstitial `EXT-X-DATERANGE` tag line failed to parse.
66    #[error("interstitial DATERANGE parse: {0}")]
67    TagParse(String),
68    /// An attribute value supplied by the [`crate::decision::AdDecisionProvider`]
69    /// (a `URI`, an `ID`, or any other ad-server-controlled string) could not
70    /// be represented as an RFC 8216 §4.2 quoted-string — contains `"`, CR or
71    /// LF (issue #1140 / audit r14-SSAI-W1): rendering an ad-decision
72    /// response straight into the playlist without validation let a `"` or
73    /// a newline in, e.g., an ad URI terminate the attribute list and inject
74    /// arbitrary tag lines into every viewer's session playlist.
75    #[error(transparent)]
76    HlsAttrValue(#[from] broadcast_hls::Error),
77    /// A `DURATION`/`X-RESUME-OFFSET`/`X-PLAYOUT-LIMIT` value was NaN,
78    /// infinite, or negative (issue #1140 / audit r14-SSAI-W4). RFC 8216
79    /// decimal-floating-point is non-negative and finite; `NaN as i64 == 0`
80    /// let a NaN duration render as the bare token `NaN`.
81    #[error("{what} must be a finite, non-negative number of seconds, got {value}")]
82    InvalidDuration {
83        /// Which attribute failed (`"DURATION"`, `"X-RESUME-OFFSET"`, …).
84        what: &'static str,
85        /// The offending value.
86        value: f64,
87    },
88}
89
90/// Crate result alias.
91pub type Result<T> = core::result::Result<T, Error>;