facet_postcard/
error.rs

1use alloc::string::String;
2use core::fmt;
3
4use facet_core::{ScalarType, Shape};
5use facet_path::Path;
6use facet_reflect::ReflectError;
7
8#[cfg(feature = "pretty-errors")]
9use facet_path::pretty::PathDiagnostic;
10
11/// Errors that can occur during postcard serialization
12#[derive(Debug)]
13pub enum SerializeError {
14    /// The output buffer is too small to hold the serialized data
15    BufferTooSmall,
16    /// Encountered a type that cannot be serialized to postcard format
17    UnsupportedType(&'static str),
18    /// Encountered a scalar type that postcard doesn't support
19    UnsupportedScalar {
20        /// The scalar type that was encountered
21        scalar_type: ScalarType,
22        /// The path in the data structure where this occurred
23        path: Path,
24        /// The root shape for formatting the path
25        root_shape: &'static Shape,
26    },
27    /// Encountered an unknown scalar (scalar_type() returned None)
28    UnknownScalar {
29        /// The type name from the shape
30        type_name: &'static str,
31        /// The path in the data structure where this occurred
32        path: Path,
33        /// The root shape for formatting the path
34        root_shape: &'static Shape,
35    },
36}
37
38// Re-export for convenience
39pub use facet_path::{Path as ErrorPath, PathStep as ErrorPathStep};
40
41impl SerializeError {
42    /// Format error as a simple one-line message (without pretty rendering)
43    pub fn format_simple(&self) -> String {
44        match self {
45            SerializeError::BufferTooSmall => String::from("Buffer too small for serialized data"),
46            SerializeError::UnsupportedType(ty) => {
47                alloc::format!("Unsupported type for postcard serialization: {ty}")
48            }
49            SerializeError::UnsupportedScalar {
50                scalar_type,
51                path,
52                root_shape,
53            } => {
54                let path_str = path.format_with_shape(root_shape);
55                alloc::format!(
56                    "Unsupported scalar type {:?} at path: {}",
57                    scalar_type,
58                    path_str
59                )
60            }
61            SerializeError::UnknownScalar {
62                type_name,
63                path,
64                root_shape,
65            } => {
66                let path_str = path.format_with_shape(root_shape);
67                alloc::format!("Unknown scalar type '{}' at path: {}", type_name, path_str)
68            }
69        }
70    }
71
72    /// Format error with pretty rendering (requires `pretty-errors` feature)
73    #[cfg(feature = "pretty-errors")]
74    pub fn format_pretty(&self) -> String {
75        match self {
76            SerializeError::BufferTooSmall => String::from("Buffer too small for serialized data"),
77            SerializeError::UnsupportedType(ty) => {
78                alloc::format!("Unsupported type for postcard serialization: {ty}")
79            }
80            SerializeError::UnsupportedScalar {
81                scalar_type,
82                path,
83                root_shape,
84            } => {
85                let message = alloc::format!("Unsupported scalar type: {:?}", scalar_type);
86                path.format_pretty(root_shape, message, None)
87            }
88            SerializeError::UnknownScalar {
89                type_name,
90                path,
91                root_shape,
92            } => {
93                let message = alloc::format!("Unknown scalar type: {}", type_name);
94                path.format_pretty(root_shape, message, None)
95            }
96        }
97    }
98}
99
100impl fmt::Display for SerializeError {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        #[cfg(feature = "pretty-errors")]
103        {
104            write!(f, "{}", self.format_pretty())
105        }
106        #[cfg(not(feature = "pretty-errors"))]
107        {
108            write!(f, "{}", self.format_simple())
109        }
110    }
111}
112
113#[cfg(feature = "std")]
114impl std::error::Error for SerializeError {}
115
116#[cfg(feature = "pretty-errors")]
117impl miette::Diagnostic for SerializeError {
118    fn source_code(&self) -> Option<&dyn miette::SourceCode> {
119        // We delegate to PathDiagnostic for the actual rendering via to_diagnostic()
120        None
121    }
122
123    fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn miette::Diagnostic> + 'a>> {
124        // PathDiagnostic handles related diagnostics internally
125        None
126    }
127
128    fn diagnostic_source(&self) -> Option<&dyn miette::Diagnostic> {
129        None
130    }
131}
132
133impl SerializeError {
134    /// Convert to a PathDiagnostic for rich error display
135    #[cfg(feature = "pretty-errors")]
136    pub fn to_diagnostic(&self) -> Option<PathDiagnostic> {
137        match self {
138            SerializeError::UnsupportedScalar {
139                scalar_type,
140                path,
141                root_shape,
142            } => {
143                let message = alloc::format!("Unsupported scalar type: {:?}", scalar_type);
144                Some(path.to_diagnostic(root_shape, message, None))
145            }
146            SerializeError::UnknownScalar {
147                type_name,
148                path,
149                root_shape,
150            } => {
151                let message = alloc::format!("Unsupported scalar type: {}", type_name);
152                Some(path.to_diagnostic(root_shape, message, None))
153            }
154            _ => None,
155        }
156    }
157}
158
159/// Errors that can occur during postcard deserialization
160#[derive(Debug)]
161pub enum DeserializeError {
162    /// Not enough data available to decode a complete value
163    UnexpectedEnd,
164    /// The data is malformed or corrupted
165    InvalidData,
166    /// Integer value is too large for the target type
167    IntegerOverflow,
168    /// Encountered a field name that isn't recognized
169    UnknownField,
170    /// Required field is missing from the input
171    MissingField(&'static str),
172    /// Shape is not supported for deserialization
173    UnsupportedShape,
174    /// Type is not supported for deserialization
175    UnsupportedType(&'static str),
176    /// Invalid enum variant index
177    InvalidVariant,
178    /// Invalid boolean value (not 0 or 1)
179    InvalidBool,
180    /// Invalid UTF-8 in string
181    InvalidUtf8,
182    /// Reflection error from facet-reflect
183    ReflectError(ReflectError),
184    /// Sequence length mismatch
185    LengthMismatch,
186}
187
188impl From<ReflectError> for DeserializeError {
189    fn from(err: ReflectError) -> Self {
190        Self::ReflectError(err)
191    }
192}
193
194impl fmt::Display for DeserializeError {
195    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196        match self {
197            DeserializeError::UnexpectedEnd => write!(f, "Unexpected end of input"),
198            DeserializeError::InvalidData => write!(f, "Invalid postcard data"),
199            DeserializeError::IntegerOverflow => {
200                write!(f, "Integer value too large for target type")
201            }
202            DeserializeError::UnknownField => write!(f, "Unknown field encountered"),
203            DeserializeError::MissingField(field) => {
204                write!(f, "Missing required field: {field}")
205            }
206            DeserializeError::UnsupportedShape => {
207                write!(f, "Unsupported shape for deserialization")
208            }
209            DeserializeError::UnsupportedType(ty) => {
210                write!(f, "Unsupported type for deserialization: {ty}")
211            }
212            DeserializeError::InvalidVariant => write!(f, "Invalid enum variant index"),
213            DeserializeError::InvalidBool => write!(f, "Invalid boolean value (expected 0 or 1)"),
214            DeserializeError::InvalidUtf8 => write!(f, "Invalid UTF-8 in string data"),
215            DeserializeError::ReflectError(err) => write!(f, "Reflection error: {err}"),
216            DeserializeError::LengthMismatch => write!(f, "Sequence length mismatch"),
217        }
218    }
219}
220
221#[cfg(feature = "std")]
222impl std::error::Error for DeserializeError {}