use core::fmt;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SnapshotError {
TruncatedHeader {
needed: usize,
actual: usize,
},
MalformedHeader,
BadMagic {
actual: [u8; 8],
},
FormatMajorMismatch {
actual: u32,
supported: u32,
},
FormatMinorTooNew {
actual: u32,
max_supported: u32,
},
HeaderSizeMismatch {
actual: u32,
expected: u32,
},
NonZeroHeaderReserved,
SectionCountTooLarge {
count: u32,
max: u32,
},
TruncatedSectionTable {
needed: usize,
actual: usize,
},
MalformedSectionTable,
NonZeroEntryReserved {
kind: u32,
},
UnsupportedFlags {
kind: u32,
flags: u8,
},
AlignmentLog2TooLarge {
kind: u32,
alignment_log2: u8,
},
SectionRangeOverflow {
kind: u32,
},
SectionOutOfBounds {
kind: u32,
offset: u64,
length: u64,
snapshot_len: u64,
},
UnsortedSectionTable {
index: usize,
},
NonAscendingKind {
kind: u32,
prev: u32,
},
TableChecksumMismatch {
expected: u32,
actual: u32,
},
SectionChecksumMismatch {
kind: u32,
expected: u32,
actual: u32,
},
SectionMissing {
kind: u32,
},
UsizeOverflow {
value: u64,
},
}
impl SnapshotError {
fn fmt_header_issue(&self, formatter: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
match self {
Self::TruncatedHeader { needed, actual } => Some(write!(
formatter,
"snapshot header is truncated: needed {needed} bytes, got {actual}"
)),
Self::MalformedHeader => Some(formatter.write_str("snapshot header is malformed")),
Self::BadMagic { actual } => Some(write!(formatter, "bad snapshot magic: {actual:?}")),
Self::FormatMajorMismatch { actual, supported } => Some(write!(
formatter,
"unsupported snapshot format major: snapshot is {actual}, this reader supports {supported}"
)),
Self::FormatMinorTooNew {
actual,
max_supported,
} => Some(write!(
formatter,
"snapshot format minor {actual} is newer than this reader's maximum {max_supported}"
)),
Self::HeaderSizeMismatch { actual, expected } => Some(write!(
formatter,
"header_size mismatch: snapshot reports {actual}, this reader expects {expected}"
)),
Self::NonZeroHeaderReserved => {
Some(formatter.write_str("snapshot header reserved bytes are not all zero"))
}
Self::SectionCountTooLarge { count, max } => Some(write!(
formatter,
"section count {count} exceeds maximum {max}"
)),
Self::TruncatedSectionTable { needed, actual } => Some(write!(
formatter,
"section table is truncated: needed {needed} bytes, got {actual}"
)),
Self::MalformedSectionTable => {
Some(formatter.write_str("section table bytes are malformed"))
}
_ => None,
}
}
}
impl fmt::Display for SnapshotError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(result) = self.fmt_header_issue(formatter) {
return result;
}
match self {
Self::NonZeroEntryReserved { kind } => write!(
formatter,
"section {kind} entry trailing reserved bytes are not all zero"
),
Self::UnsupportedFlags { kind, flags } => write!(
formatter,
"section {kind} entry has unsupported flags byte {flags:#04x}"
),
Self::AlignmentLog2TooLarge {
kind,
alignment_log2,
} => write!(
formatter,
"section {kind} alignment_log2 {alignment_log2} exceeds maximum"
),
Self::SectionRangeOverflow { kind } => {
write!(formatter, "section {kind} offset + length overflows u64")
}
Self::SectionOutOfBounds {
kind,
offset,
length,
snapshot_len,
} => write!(
formatter,
"section {kind} is out of bounds: offset {offset}, length {length}, snapshot length {snapshot_len}"
),
Self::UnsortedSectionTable { index } => write!(
formatter,
"section table entry at index {index} is unsorted or overlaps its predecessor"
),
Self::NonAscendingKind { kind, prev } => write!(
formatter,
"section kind {kind} is not strictly greater than its predecessor {prev}"
),
Self::TableChecksumMismatch { expected, actual } => write!(
formatter,
"section table checksum mismatch: header records {expected:#010x}, table bytes hash to {actual:#010x}"
),
Self::SectionChecksumMismatch {
kind,
expected,
actual,
} => write!(
formatter,
"section {kind} payload checksum mismatch: entry records {expected:#010x}, payload hashes to {actual:#010x}"
),
Self::SectionMissing { kind } => {
write!(formatter, "snapshot section {kind} is missing")
}
Self::UsizeOverflow { value } => {
write!(formatter, "u64 value {value} does not fit usize")
}
Self::TruncatedHeader { .. }
| Self::MalformedHeader
| Self::BadMagic { .. }
| Self::FormatMajorMismatch { .. }
| Self::FormatMinorTooNew { .. }
| Self::HeaderSizeMismatch { .. }
| Self::NonZeroHeaderReserved
| Self::SectionCountTooLarge { .. }
| Self::TruncatedSectionTable { .. }
| Self::MalformedSectionTable => Ok(()),
}
}
}
impl core::error::Error for SnapshotError {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SectionViewError {
ZeroSizedType,
LengthNotMultipleOfSize {
length: usize,
elem_size: usize,
},
AlignmentMismatch {
ptr_addr: usize,
required: usize,
},
ChecksumMismatch {
kind: u32,
expected: u32,
actual: u32,
},
}
impl fmt::Display for SectionViewError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ZeroSizedType => {
formatter.write_str("cannot borrow a section payload as a zero-sized type")
}
Self::LengthNotMultipleOfSize { length, elem_size } => write!(
formatter,
"section length {length} is not a multiple of element size {elem_size}"
),
Self::AlignmentMismatch { ptr_addr, required } => write!(
formatter,
"section payload at address {ptr_addr:#x} is not aligned to {required}"
),
Self::ChecksumMismatch {
kind,
expected,
actual,
} => write!(
formatter,
"section {kind} payload checksum mismatch: entry records {expected:#010x}, payload hashes to {actual:#010x}"
),
}
}
}
impl core::error::Error for SectionViewError {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SectionBindError {
Missing {
kind: u32,
},
VersionMismatch {
kind: u32,
expected: u32,
actual: u32,
},
View {
kind: u32,
error: SectionViewError,
},
}
impl fmt::Display for SectionBindError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Missing { kind } => write!(formatter, "snapshot section {kind} is missing"),
Self::VersionMismatch {
kind,
expected,
actual,
} => write!(
formatter,
"snapshot section {kind} version {actual} does not match expected {expected}"
),
Self::View { kind, error } => {
write!(
formatter,
"snapshot section {kind} typed view failed: {error}"
)
}
}
}
}
impl core::error::Error for SectionBindError {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PlanError {
BufferTooSmall {
needed: usize,
actual: usize,
},
AlignmentTooLarge {
alignment_log2: u8,
},
PayloadOverflow,
TooManySections {
count: usize,
},
NonAscendingKind {
kind: u32,
prev: u32,
},
}
impl fmt::Display for PlanError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BufferTooSmall { needed, actual } => write!(
formatter,
"output buffer too small: needed {needed} bytes, got {actual}"
),
Self::AlignmentTooLarge { alignment_log2 } => write!(
formatter,
"alignment_log2 {alignment_log2} exceeds the format maximum"
),
Self::PayloadOverflow => {
formatter.write_str("snapshot payload arithmetic overflowed u64 or usize")
}
Self::TooManySections { count } => {
write!(
formatter,
"section count {count} exceeds the format maximum"
)
}
Self::NonAscendingKind { kind, prev } => write!(
formatter,
"section kind {kind} is not strictly greater than its predecessor {prev}"
),
}
}
}
impl core::error::Error for PlanError {}