use thiserror::Error;
fn fmt_object_location(idx: Option<usize>) -> String {
match idx {
Some(i) => format!("object {i}"),
None => "frame".to_string(),
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum TensogramError {
#[error("framing error: {0}")]
Framing(String),
#[error("metadata error: {0}")]
Metadata(String),
#[error("encoding error: {0}")]
Encoding(String),
#[error("compression error: {0}")]
Compression(String),
#[error("object error: {0}")]
Object(String),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("hash mismatch on {}: expected {expected}, got {actual}",
fmt_object_location(*object_index))]
HashMismatch {
object_index: Option<usize>,
expected: String,
actual: String,
},
#[error(
"hash verification requested but object {object_index} has no inline hash recorded \
(HASH_PRESENT flag clear); re-encode with hashing=true or call decode without verify_hash=true"
)]
MissingHash { object_index: usize },
#[error("remote error: {0}")]
Remote(String),
}
pub type Result<T> = std::result::Result<T, TensogramError>;
pub(crate) fn with_object_index(e: TensogramError, idx: usize) -> TensogramError {
match e {
TensogramError::HashMismatch {
object_index: _,
expected,
actual,
} => TensogramError::HashMismatch {
object_index: Some(idx),
expected,
actual,
},
TensogramError::MissingHash { object_index: _ } => {
TensogramError::MissingHash { object_index: idx }
}
other => other,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fmt_object_location_some_and_none() {
assert_eq!(fmt_object_location(Some(7)), "object 7");
assert_eq!(fmt_object_location(None), "frame");
}
#[test]
fn hash_mismatch_display_uses_object_location() {
let with_obj = TensogramError::HashMismatch {
object_index: Some(3),
expected: "aaaa".to_string(),
actual: "bbbb".to_string(),
};
assert_eq!(
with_obj.to_string(),
"hash mismatch on object 3: expected aaaa, got bbbb"
);
let no_obj = TensogramError::HashMismatch {
object_index: None,
expected: "aaaa".to_string(),
actual: "bbbb".to_string(),
};
assert_eq!(
no_obj.to_string(),
"hash mismatch on frame: expected aaaa, got bbbb"
);
}
#[test]
fn with_object_index_stamps_hash_mismatch() {
let e = TensogramError::HashMismatch {
object_index: None,
expected: "x".to_string(),
actual: "y".to_string(),
};
match with_object_index(e, 5) {
TensogramError::HashMismatch { object_index, .. } => {
assert_eq!(object_index, Some(5));
}
other => panic!("expected HashMismatch, got {other:?}"),
}
}
#[test]
fn with_object_index_stamps_missing_hash() {
let e = TensogramError::MissingHash { object_index: 0 };
match with_object_index(e, 9) {
TensogramError::MissingHash { object_index } => assert_eq!(object_index, 9),
other => panic!("expected MissingHash, got {other:?}"),
}
}
#[test]
fn with_object_index_passes_other_errors_through() {
let e = TensogramError::Framing("boom".to_string());
match with_object_index(e, 42) {
TensogramError::Framing(msg) => assert_eq!(msg, "boom"),
other => panic!("expected Framing passthrough, got {other:?}"),
}
}
}