1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! The crate's error type — dependency-free, hand-rolled `Display`.
//!
//! `Again` / `Eof` mirror FFmpeg's `EAGAIN` / `AVERROR_EOF` control-flow
//! convention (the same contract as `rusty_vp9`): they drive the push/pull
//! loop and are not failures.
/// Crate-wide result alias.
pub type Result<T> = std::result::Result<T, Error>;
/// Errors (and control-flow signals) produced by the decoder.
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
/// A code path that is scaffolded but not yet implemented.
Unimplemented(&'static str),
/// End of stream: all output has been drained.
Eof,
/// More input is required before output can be produced.
Again,
/// The bitstream is malformed or internally inconsistent.
InvalidData(String),
/// The input is valid but uses a feature outside this decoder's scope
/// (RExt / SCC / multi-layer profiles are parsed and refused by name).
Unsupported(String),
}
impl Error {
/// `#[cold]` and out of line: `InvalidData` owns a `String`, so every
/// `Error::invalid("...")` inlines an allocation and a copy of the literal
/// at the call site. Those sites are bitstream-conformance checks that
/// never fire on a valid stream, and four of them sit inside
/// `residual_block`, the hottest function in the decoder. Every `&str`
/// literal shares one monomorphisation, so this is a single out-of-line
/// body for all of them -- and the enum's public shape is unchanged.
#[cold]
#[inline(never)]
pub fn invalid(msg: impl Into<String>) -> Self {
Error::InvalidData(msg.into())
}
#[cold]
#[inline(never)]
pub fn unsupported(msg: impl Into<String>) -> Self {
Error::Unsupported(msg.into())
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Unimplemented(what) => write!(f, "not yet implemented: {what}"),
Error::Eof => write!(f, "end of stream"),
Error::Again => write!(f, "more input required"),
Error::InvalidData(msg) => write!(f, "invalid data: {msg}"),
Error::Unsupported(msg) => write!(f, "unsupported: {msg}"),
}
}
}
impl std::error::Error for Error {}
impl From<crate::bits::OutOfData> for Error {
fn from(_: crate::bits::OutOfData) -> Self {
Error::InvalidData("bit reader ran out of data".into())
}
}