Skip to main content

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}