preserves/
error.rs

1//! Serde and plain-Preserves codec errors.
2
3use num::bigint::BigInt;
4use std::convert::From;
5use std::io;
6
7/// Representation of parse, deserialization, and other conversion errors.
8#[derive(Debug)]
9pub enum Error {
10    /// Generic IO error.
11    Io(io::Error),
12    /// Generic message for the user.
13    Message(String),
14    /// Invalid unicode scalar `n` found during interpretation of a `<UnicodeScalar n>` record
15    /// as a Rust `char`.
16    InvalidUnicodeScalar(u32),
17    /// Preserves supports arbitrary integers; when these are converted to specific Rust
18    /// machine word types, sometimes they exceed the available range.
19    NumberOutOfRange(BigInt),
20    /// Serde has limited support for deserializing free-form data; this error is signalled
21    /// when one of the limits is hit.
22    CannotDeserializeAny,
23    /// Syntax error: missing closing delimiter (`)`, `]`, `}`, `>` in text syntax; `0x84` in binary syntax; etc.)
24    MissingCloseDelimiter,
25    /// Signalled when an expected term is not present.
26    MissingItem,
27    /// Signalled when what was received did not match expectations.
28    Expected(ExpectedKind, Received),
29    #[doc(hidden)] // TODO remove this enum variant? It isn't used
30    StreamingSerializationUnsupported,
31}
32
33/// Used in [Error::Expected] to indicate what was received.
34#[derive(Debug)]
35pub enum Received {
36    #[doc(hidden)] // TODO remove this enum variant? It isn't used
37    ReceivedSomethingElse,
38    /// Received a record with the given label symbol text.
39    ReceivedRecordWithLabel(String),
40    /// Received some other value, described in the `String`
41    ReceivedOtherValue(String),
42}
43
44/// Used in [Error::Expected] to indicate what was expected.
45#[derive(Debug, PartialEq)]
46pub enum ExpectedKind {
47    Boolean,
48    Float,
49    Double,
50
51    SignedIntegerI128,
52    SignedIntegerU128,
53    SignedInteger,
54    String,
55    ByteString,
56    Symbol,
57
58    /// Expected a record, either of a specific arity (length) or of no specific arity
59    Record(Option<usize>),
60    /// Expected a record with a symbol label with text `String`, perhaps of some specific arity
61    SimpleRecord(String, Option<usize>),
62    Sequence,
63    Set,
64    Dictionary,
65
66    Embedded,
67
68    SequenceOrSet, // Because of hacking up serde's data model: see open_sequence_or_set etc.
69
70    Option,
71    UnicodeScalar,
72}
73
74impl From<io::Error> for Error {
75    fn from(e: io::Error) -> Self {
76        Error::Io(e)
77    }
78}
79
80impl From<Error> for io::Error {
81    fn from(e: Error) -> Self {
82        match e {
83            Error::Io(ioe) => ioe,
84            Error::Message(str) => io::Error::new(io::ErrorKind::Other, str),
85            _ => io::Error::new(io::ErrorKind::Other, e.to_string()),
86        }
87    }
88}
89
90impl serde::ser::Error for Error {
91    fn custom<T: std::fmt::Display>(msg: T) -> Self {
92        Self::Message(msg.to_string())
93    }
94}
95
96impl serde::de::Error for Error {
97    fn custom<T: std::fmt::Display>(msg: T) -> Self {
98        Self::Message(msg.to_string())
99    }
100}
101
102impl std::error::Error for Error {}
103
104impl std::fmt::Display for Error {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        write!(f, "{:?}", self)
107    }
108}
109
110//---------------------------------------------------------------------------
111
112/// True iff `e` is `Error::Io`
113pub fn is_io_error(e: &Error) -> bool {
114    matches!(e, Error::Io(_))
115}
116
117/// Produce the generic "end of file" error, `Error::Io(`[io_eof]`())`
118pub fn eof() -> Error {
119    Error::Io(io_eof())
120}
121
122/// True iff `e` is an "end of file" error; see [is_eof_io_error]
123pub fn is_eof_error(e: &Error) -> bool {
124    if let Error::Io(ioe) = e {
125        is_eof_io_error(ioe)
126    } else {
127        false
128    }
129}
130
131/// Produce a syntax error bearing the message `s`
132pub fn syntax_error(s: &str) -> Error {
133    Error::Io(io_syntax_error(s))
134}
135
136/// True iff `e` is a syntax error; see [is_syntax_io_error]
137pub fn is_syntax_error(e: &Error) -> bool {
138    if let Error::Io(ioe) = e {
139        is_syntax_io_error(ioe)
140    } else {
141        false
142    }
143}
144
145//---------------------------------------------------------------------------
146
147/// Produce an [io::Error] of [io::ErrorKind::UnexpectedEof].
148pub fn io_eof() -> io::Error {
149    io::Error::new(io::ErrorKind::UnexpectedEof, "EOF")
150}
151
152/// True iff `e` is [io::ErrorKind::UnexpectedEof]
153pub fn is_eof_io_error(e: &io::Error) -> bool {
154    matches!(e.kind(), io::ErrorKind::UnexpectedEof)
155}
156
157/// Produce a syntax error ([io::ErrorKind::InvalidData]) bearing the message `s`
158pub fn io_syntax_error(s: &str) -> io::Error {
159    io::Error::new(io::ErrorKind::InvalidData, s)
160}
161
162/// True iff `e` is an [io::ErrorKind::InvalidData] (a syntax error)
163pub fn is_syntax_io_error(e: &io::Error) -> bool {
164    matches!(e.kind(), io::ErrorKind::InvalidData)
165}