serde_stream_formats/error.rs
1//! Typed failures for streaming encode and incremental decode.
2
3use std::{
4 fmt,
5 io,
6};
7
8/// A failure while decoding or encoding a Serde document.
9#[derive(Debug)]
10pub enum FormatError {
11 /// The input is not a valid document in the named format.
12 MalformedDocument {
13 /// The format's display name.
14 format: &'static str,
15 /// Decoder detail (position information where the decoder
16 /// provides it).
17 detail: String,
18 },
19 /// The input stream ended the transfer because a configured size
20 /// limit was exceeded (see [`crate::PayloadLimitExceeded`]).
21 PayloadTooLarge,
22 /// The underlying reader failed before the document ended.
23 Read {
24 /// Human-readable I/O detail.
25 detail: String,
26 },
27 /// The value failed to encode in the named format.
28 Encoding {
29 /// The format's display name.
30 format: &'static str,
31 /// Encoder detail.
32 detail: String,
33 },
34}
35
36impl fmt::Display for FormatError {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 match self {
39 Self::MalformedDocument { format, detail } => {
40 write!(f, "malformed {format} document: {detail}")
41 }
42 Self::PayloadTooLarge => f.write_str("payload exceeded the configured size limit"),
43 Self::Read { detail } => write!(f, "body read failed: {detail}"),
44 Self::Encoding { format, detail } => {
45 write!(f, "{format} encoding failed: {detail}")
46 }
47 }
48 }
49}
50
51impl std::error::Error for FormatError {}
52
53/// The sentinel a size-limiting reader wraps into [`io::Error`] so the
54/// decoder can distinguish "too large" from an ordinary read failure.
55///
56/// A transport adapter that enforces a body limit should surface the
57/// limit hit as `io::Error::other(PayloadLimitExceeded)`; every
58/// [`crate::DecodeFormat`] decoder then reports it as
59/// [`FormatError::PayloadTooLarge`] instead of a generic read error.
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct PayloadLimitExceeded;
62
63impl fmt::Display for PayloadLimitExceeded {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 f.write_str("payload exceeded the configured size limit")
66 }
67}
68
69impl std::error::Error for PayloadLimitExceeded {}
70
71impl FormatError {
72 /// Classify a decoder-side I/O failure: the payload-limit sentinel
73 /// becomes [`FormatError::PayloadTooLarge`]; everything else is a
74 /// read failure.
75 #[must_use]
76 pub fn from_read_error(error: &io::Error) -> Self {
77 if matches!(error.get_ref(), Some(source) if source.is::<PayloadLimitExceeded>()) {
78 Self::PayloadTooLarge
79 } else {
80 Self::Read {
81 detail: error.to_string(),
82 }
83 }
84 }
85}