use crate::decode::{ErrorContext, ResourceLimit, SourceLocation};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum CodecError {
#[error("not the expected format: {0}")]
WrongFormat(String),
#[error("malformed container: {0}")]
Malformed(String),
#[error("invalid encoder input: {0}")]
InvalidInput(String),
#[error(
"truncated input during {} at space {} offset {}",
.context.operation, .location.space.index(), .location.offset
)]
Truncated {
location: SourceLocation,
context: ErrorContext,
},
#[error(
"resource limit on {:?}: {:?} (limit {}, used {}, requested {})",
.0.dimension, .0.reason, .0.limit, .0.used, .0.additional
)]
ResourceLimit(ResourceLimit),
#[error("strict mode rejects {loss_code}: {message}")]
StrictRefusal {
loss_code: String,
message: String,
},
#[error("not implemented yet: {0}")]
NotImplemented(String),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
}
impl CodecError {
pub fn malformed(message: impl std::fmt::Display) -> Self {
Self::Malformed(message.to_string())
}
pub const fn truncated(location: SourceLocation, operation: &'static str) -> Self {
Self::Truncated {
location,
context: ErrorContext {
operation,
location: Some(location),
},
}
}
}
#[cfg(test)]
mod tests {
use super::CodecError;
#[test]
fn malformed_constructor_formats_the_message_once() {
let error = CodecError::malformed(format_args!("field {} is invalid", 7));
assert_eq!(error.to_string(), "malformed container: field 7 is invalid");
}
#[test]
fn a_strict_refusal_names_the_loss_and_claims_no_container_defect() {
let error = CodecError::StrictRefusal {
loss_code: "step/parse.noncanonical-syntax".into(),
message: "complex partial records are not alphabetical".into(),
};
assert_eq!(
error.to_string(),
"strict mode rejects step/parse.noncanonical-syntax: complex partial \
records are not alphabetical"
);
}
}