1extern crate alloc;
4
5use alloc::string::String;
6use alloc::vec::Vec;
7use core::fmt;
8
9#[derive(Debug, Clone)]
11pub struct PostcardError {
12 pub code: i32,
14 pub pos: usize,
16 pub message: String,
18 pub source_bytes: Option<Vec<u8>>,
20}
21
22impl fmt::Display for PostcardError {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 write!(f, "{} at position {}", self.message, self.pos)?;
25 if let Some(ref bytes) = self.source_bytes {
26 let context = self.hex_context(bytes);
28 if !context.is_empty() {
29 write!(f, "\n{}", context)?;
30 }
31 }
32 Ok(())
33 }
34}
35
36impl PostcardError {
37 fn hex_context(&self, bytes: &[u8]) -> String {
39 use alloc::format;
40
41 if bytes.is_empty() {
42 return String::new();
43 }
44
45 let start = self.pos.saturating_sub(8);
47 let end = (self.pos + 8).min(bytes.len());
48
49 let mut parts = Vec::new();
50 for (i, byte) in bytes[start..end].iter().enumerate() {
51 let abs_pos = start + i;
52 if abs_pos == self.pos {
53 parts.push(format!("[{:02x}]", byte));
54 } else {
55 parts.push(format!("{:02x}", byte));
56 }
57 }
58
59 format!(
60 " bytes: {} (position {} marked with [])",
61 parts.join(" "),
62 self.pos
63 )
64 }
65
66 pub fn with_source(mut self, bytes: &[u8]) -> Self {
68 self.source_bytes = Some(bytes.to_vec());
69 self
70 }
71}
72
73impl std::error::Error for PostcardError {}
74
75pub mod codes {
77 pub const UNEXPECTED_EOF: i32 = -100;
79 pub const INVALID_BOOL: i32 = -101;
81 pub const VARINT_OVERFLOW: i32 = -102;
83 pub const SEQ_UNDERFLOW: i32 = -103;
85 pub const INVALID_UTF8: i32 = -104;
87 pub const INVALID_OPTION_DISCRIMINANT: i32 = -105;
89 pub const INVALID_ENUM_DISCRIMINANT: i32 = -106;
91 pub const UNSUPPORTED_OPAQUE_TYPE: i32 = -107;
93 pub const UNEXPECTED_END_OF_INPUT: i32 = -108;
95 pub const UNSUPPORTED: i32 = -1;
97}
98
99impl PostcardError {
100 pub fn from_code(code: i32, pos: usize) -> Self {
102 let message = match code {
103 codes::UNEXPECTED_EOF => "unexpected end of input".to_string(),
104 codes::INVALID_BOOL => "invalid boolean value (expected 0 or 1)".to_string(),
105 codes::VARINT_OVERFLOW => "varint overflow".to_string(),
106 codes::SEQ_UNDERFLOW => "sequence underflow (internal error)".to_string(),
107 codes::INVALID_UTF8 => "invalid UTF-8 in string".to_string(),
108 codes::INVALID_OPTION_DISCRIMINANT => {
109 "invalid Option discriminant (expected 0x00 or 0x01)".to_string()
110 }
111 codes::INVALID_ENUM_DISCRIMINANT => "invalid enum variant discriminant".to_string(),
112 codes::UNSUPPORTED => "unsupported operation".to_string(),
113 _ => format!("unknown error code {}", code),
114 };
115 Self {
116 code,
117 pos,
118 message,
119 source_bytes: None,
120 }
121 }
122}
123
124#[derive(Debug)]
126pub enum SerializeError {
127 BufferTooSmall,
129 Custom(String),
131}
132
133impl fmt::Display for SerializeError {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 SerializeError::BufferTooSmall => write!(f, "Buffer too small for serialized data"),
137 SerializeError::Custom(msg) => write!(f, "{}", msg),
138 }
139 }
140}
141
142impl std::error::Error for SerializeError {}