use std::fmt;
pub type Result<T> = std::result::Result<T, Error>;
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
Magic,
VersionMajor(u16),
VersionMinor(u16),
HeaderTruncated,
HeaderSize(u8),
UnknownFlags(u16),
ReservedNonZero { section: &'static str, offset: u64 },
Offset { section: &'static str, offset: u64 },
Truncated { needed: u64, found: u64 },
TrailingBytes { at: u64 },
Count { field: &'static str, value: u64 },
Padding { offset: u64 },
HashMismatch,
DialectMismatch(u64),
NotCanonical,
StringRef(u32),
NodeRef(u32),
Node { id: u32, reason: &'static str },
Utf8 { offset: u64 },
UnknownUnit(u32),
UnitRef(u32),
Type { id: u32, reason: &'static str },
Edge { from: u32, to: u32 },
Annotation { id: u32, reason: &'static str },
Provenance(&'static str),
Extension { tag: u64, reason: &'static str },
Blob { id: u32, reason: &'static str },
SecretEntry(u32),
DuplicateField { node: u32 },
DuplicateBinding,
Cycle { node: u32 },
Depth { limit: u32 },
Limit { kind: &'static str, limit: u64 },
InvalidArgument(&'static str),
Evaluation(&'static str),
Encode(&'static str),
EncodeDangling(u32),
TooLarge,
StreamMagic,
StreamVersion(u8),
StreamFrameLen { declared: u32, available: u64 },
StreamFrameKind(u8),
StreamSequence { expected: u64, found: u64 },
StreamState(&'static str),
StreamHashMismatch,
StreamDelta(&'static str),
StreamUnterminated,
}
impl Error {
pub const fn code(&self) -> &'static str {
match self {
Error::Magic => "infinity/magic",
Error::VersionMajor(_) => "infinity/version-major",
Error::VersionMinor(_) => "infinity/version-minor",
Error::HeaderTruncated => "infinity/header-truncated",
Error::HeaderSize(_) => "infinity/header-size",
Error::UnknownFlags(_) => "infinity/flags",
Error::ReservedNonZero { .. } => "infinity/reserved",
Error::Offset { .. } => "infinity/offset",
Error::Truncated { .. } => "infinity/truncated",
Error::TrailingBytes { .. } => "infinity/trailing-bytes",
Error::Count { .. } => "infinity/count",
Error::Padding { .. } => "infinity/padding",
Error::HashMismatch => "infinity/hash-mismatch",
Error::DialectMismatch(_) => "infinity/dialect",
Error::NotCanonical => "infinity/not-canonical",
Error::StringRef(_) => "infinity/string-ref",
Error::NodeRef(_) => "infinity/node-ref",
Error::Node { .. } => "infinity/node",
Error::Utf8 { .. } => "infinity/utf8",
Error::UnknownUnit(_) => "infinity/unknown-unit",
Error::UnitRef(_) => "infinity/unit-ref",
Error::Type { .. } => "infinity/type",
Error::Edge { .. } => "infinity/edge",
Error::Annotation { .. } => "infinity/annotation",
Error::Provenance(_) => "infinity/provenance",
Error::Extension { .. } => "infinity/extension",
Error::Blob { .. } => "infinity/blob",
Error::SecretEntry(_) => "infinity/secret-entry",
Error::DuplicateField { .. } => "infinity/duplicate-field",
Error::DuplicateBinding => "infinity/duplicate-binding",
Error::Cycle { .. } => "infinity/cycle",
Error::Depth { .. } => "infinity/depth",
Error::Limit { .. } => "infinity/limit",
Error::InvalidArgument(_) => "infinity/invalid-argument",
Error::Evaluation(_) => "infinity/evaluation",
Error::Encode(_) => "infinity/encode",
Error::EncodeDangling(_) => "infinity/encode-dangling",
Error::TooLarge => "infinity/too-large",
Error::StreamMagic => "infinity/stream-magic",
Error::StreamVersion(_) => "infinity/stream-version",
Error::StreamFrameLen { .. } => "infinity/stream-frame-len",
Error::StreamFrameKind(_) => "infinity/stream-frame-kind",
Error::StreamSequence { .. } => "infinity/stream-sequence",
Error::StreamState(_) => "infinity/stream-state",
Error::StreamHashMismatch => "infinity/stream-hash",
Error::StreamDelta(_) => "infinity/stream-delta",
Error::StreamUnterminated => "infinity/stream-unterminated",
}
}
pub const fn is_fatal(&self) -> bool {
!matches!(self, Error::InvalidArgument(_))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Magic => write!(f, "not an Active Infinity buffer (bad magic)"),
Error::VersionMajor(v) => write!(f, "unsupported major version {v}"),
Error::VersionMinor(v) => write!(f, "unsupported minor version {v}"),
Error::HeaderTruncated => write!(f, "buffer shorter than the fixed header"),
Error::HeaderSize(n) => write!(f, "unsupported header size {n}"),
Error::UnknownFlags(bits) => write!(f, "unknown header flag bits {bits:#06x}"),
Error::ReservedNonZero { section, offset } => {
write!(f, "reserved field in {section} is non-zero at {offset}")
}
Error::Offset { section, offset } => {
write!(f, "invalid {section} offset/range at {offset}")
}
Error::Truncated { needed, found } => {
write!(f, "truncated buffer: need {needed} bytes, found {found}")
}
Error::TrailingBytes { at } => write!(f, "trailing bytes after {at}"),
Error::Count { field, value } => write!(f, "invalid {field} count {value}"),
Error::Padding { offset } => write!(f, "non-zero padding at {offset}"),
Error::HashMismatch => write!(f, "content hash mismatch"),
Error::DialectMismatch(h) => write!(f, "dialect hash {h:#018x} not supported"),
Error::NotCanonical => write!(f, "buffer is not in canonical form"),
Error::StringRef(id) => write!(f, "dangling string reference {id}"),
Error::NodeRef(id) => write!(f, "dangling node reference {id}"),
Error::Node { id, reason } => write!(f, "node {id} is invalid: {reason}"),
Error::Utf8 { offset } => write!(f, "invalid UTF-8 in string heap at {offset}"),
Error::UnknownUnit(d) => write!(f, "unknown unit discriminant {d}"),
Error::UnitRef(id) => write!(f, "dangling unit reference {id}"),
Error::Type { id, reason } => write!(f, "type {id} is invalid: {reason}"),
Error::Edge { from, to } => write!(f, "invalid edge {from} -> {to}"),
Error::Annotation { id, reason } => write!(f, "annotation {id} is invalid: {reason}"),
Error::Provenance(reason) => write!(f, "provenance block is invalid: {reason}"),
Error::Extension { tag, reason } => {
write!(f, "extension {tag} is invalid: {reason}")
}
Error::Blob { id, reason } => write!(f, "blob {id} is invalid: {reason}"),
Error::SecretEntry(id) => write!(f, "secret entry {id} is invalid"),
Error::DuplicateField { node } => write!(f, "table node {node} repeats a field name"),
Error::DuplicateBinding => write!(f, "duplicate binding name"),
Error::Cycle { node } => write!(
f,
"dependency cycle: node {node} is on a cycle or depends on one"
),
Error::Depth { limit } => write!(f, "nesting deeper than {limit}"),
Error::Limit { kind, limit } => write!(f, "{kind} limit {limit} exceeded"),
Error::InvalidArgument(what) => write!(f, "invalid argument: {what}"),
Error::Evaluation(code) => write!(f, "Active evaluation failed: {code}"),
Error::Encode(what) => write!(f, "cannot encode module: {what}"),
Error::EncodeDangling(id) => write!(f, "cannot encode: dangling node {id}"),
Error::TooLarge => write!(f, "module exceeds the 4 GiB addressable image"),
Error::StreamMagic => write!(f, "not an Active Infinity stream frame"),
Error::StreamVersion(v) => write!(f, "unsupported stream frame version {v}"),
Error::StreamFrameLen {
declared,
available,
} => {
write!(
f,
"stream frame declares {declared} bytes, {available} available"
)
}
Error::StreamFrameKind(k) => write!(f, "unknown stream frame kind {k}"),
Error::StreamSequence { expected, found } => {
write!(
f,
"stream frame out of order: expected {expected}, got {found}"
)
}
Error::StreamState(what) => write!(f, "stream state error: {what}"),
Error::StreamHashMismatch => write!(f, "streamed module hash mismatch"),
Error::StreamDelta(what) => write!(f, "delta cannot be applied: {what}"),
Error::StreamUnterminated => write!(f, "stream ended without an end frame"),
}
}
}
impl std::error::Error for Error {}
impl From<std::str::Utf8Error> for Error {
fn from(_: std::str::Utf8Error) -> Self {
Error::Utf8 { offset: 0 }
}
}