extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
#[derive(Debug, Clone)]
pub struct PostcardError {
pub code: i32,
pub pos: usize,
pub message: String,
pub source_bytes: Option<Vec<u8>>,
}
impl fmt::Display for PostcardError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} at position {}", self.message, self.pos)?;
if let Some(ref bytes) = self.source_bytes {
let context = self.hex_context(bytes);
if !context.is_empty() {
write!(f, "\n{}", context)?;
}
}
Ok(())
}
}
impl PostcardError {
fn hex_context(&self, bytes: &[u8]) -> String {
use alloc::format;
if bytes.is_empty() {
return String::new();
}
let start = self.pos.saturating_sub(8);
let end = (self.pos + 8).min(bytes.len());
let mut parts = Vec::new();
for (i, byte) in bytes[start..end].iter().enumerate() {
let abs_pos = start + i;
if abs_pos == self.pos {
parts.push(format!("[{:02x}]", byte));
} else {
parts.push(format!("{:02x}", byte));
}
}
format!(
" bytes: {} (position {} marked with [])",
parts.join(" "),
self.pos
)
}
pub fn with_source(mut self, bytes: &[u8]) -> Self {
self.source_bytes = Some(bytes.to_vec());
self
}
}
impl std::error::Error for PostcardError {}
pub mod codes {
pub const UNEXPECTED_EOF: i32 = -100;
pub const INVALID_BOOL: i32 = -101;
pub const VARINT_OVERFLOW: i32 = -102;
pub const SEQ_UNDERFLOW: i32 = -103;
pub const INVALID_UTF8: i32 = -104;
pub const INVALID_OPTION_DISCRIMINANT: i32 = -105;
pub const INVALID_ENUM_DISCRIMINANT: i32 = -106;
pub const UNSUPPORTED_OPAQUE_TYPE: i32 = -107;
pub const UNEXPECTED_END_OF_INPUT: i32 = -108;
pub const COLLECTION_TOO_LARGE: i32 = -109;
pub const UNSUPPORTED: i32 = -1;
}
impl PostcardError {
pub fn from_code(code: i32, pos: usize) -> Self {
let message = match code {
codes::UNEXPECTED_EOF => "unexpected end of input".to_string(),
codes::INVALID_BOOL => "invalid boolean value (expected 0 or 1)".to_string(),
codes::VARINT_OVERFLOW => "varint overflow".to_string(),
codes::SEQ_UNDERFLOW => "sequence underflow (internal error)".to_string(),
codes::INVALID_UTF8 => "invalid UTF-8 in string".to_string(),
codes::INVALID_OPTION_DISCRIMINANT => {
"invalid Option discriminant (expected 0x00 or 0x01)".to_string()
}
codes::INVALID_ENUM_DISCRIMINANT => "invalid enum variant discriminant".to_string(),
codes::COLLECTION_TOO_LARGE => "collection length exceeds maximum".to_string(),
codes::UNSUPPORTED => "unsupported operation".to_string(),
_ => format!("unknown error code {}", code),
};
Self {
code,
pos,
message,
source_bytes: None,
}
}
}
#[derive(Debug)]
pub enum SerializeError {
BufferTooSmall,
Custom(String),
}
impl fmt::Display for SerializeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SerializeError::BufferTooSmall => write!(f, "Buffer too small for serialized data"),
SerializeError::Custom(msg) => write!(f, "{}", msg),
}
}
}
impl std::error::Error for SerializeError {}