//! Serde and plain-Preserves codec errors. use num::bigint::BigInt; use std::convert::From; use std::io; /// Representation of parse, deserialization, and other conversion errors. #[derive(Debug)] pub enum Error { /// Generic IO error. Io(io::Error), /// Generic message for the user. Message(String), /// Invalid unicode scalar `n` found during interpretation of a `` record /// as a Rust `char`. InvalidUnicodeScalar(u32), /// Preserves supports arbitrary integers; when these are converted to specific Rust /// machine word types, sometimes they exceed the available range. NumberOutOfRange(BigInt), /// Serde has limited support for deserializing free-form data; this error is signalled /// when one of the limits is hit. CannotDeserializeAny, /// Syntax error: missing closing delimiter (`)`, `]`, `}`, `>` in text syntax; `0x84` in binary syntax; etc.) MissingCloseDelimiter, /// Signalled when an expected term is not present. MissingItem, /// Signalled when what was received did not match expectations. Expected(ExpectedKind, Received), #[doc(hidden)] // TODO remove this enum variant? It isn't used StreamingSerializationUnsupported, } /// Used in [Error::Expected] to indicate what was received. #[derive(Debug)] pub enum Received { #[doc(hidden)] // TODO remove this enum variant? It isn't used ReceivedSomethingElse, /// Received a record with the given label symbol text. ReceivedRecordWithLabel(String), /// Received some other value, described in the `String` ReceivedOtherValue(String), } /// Used in [Error::Expected] to indicate what was expected. #[derive(Debug, PartialEq)] pub enum ExpectedKind { Boolean, Float, Double, SignedIntegerI128, SignedIntegerU128, SignedInteger, String, ByteString, Symbol, /// Expected a record, either of a specific arity (length) or of no specific arity Record(Option), /// Expected a record with a symbol label with text `String`, perhaps of some specific arity SimpleRecord(String, Option), Sequence, Set, Dictionary, Embedded, SequenceOrSet, // Because of hacking up serde's data model: see open_sequence_or_set etc. Option, UnicodeScalar, } impl From for Error { fn from(e: io::Error) -> Self { Error::Io(e) } } impl From for io::Error { fn from(e: Error) -> Self { match e { Error::Io(ioe) => ioe, Error::Message(str) => io::Error::new(io::ErrorKind::Other, str), _ => io::Error::new(io::ErrorKind::Other, e.to_string()), } } } impl serde::ser::Error for Error { fn custom(msg: T) -> Self { Self::Message(msg.to_string()) } } impl serde::de::Error for Error { fn custom(msg: T) -> Self { Self::Message(msg.to_string()) } } impl std::error::Error for Error {} impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) } } //--------------------------------------------------------------------------- /// True iff `e` is `Error::Io` pub fn is_io_error(e: &Error) -> bool { matches!(e, Error::Io(_)) } /// Produce the generic "end of file" error, `Error::Io(`[io_eof]`())` pub fn eof() -> Error { Error::Io(io_eof()) } /// True iff `e` is an "end of file" error; see [is_eof_io_error] pub fn is_eof_error(e: &Error) -> bool { if let Error::Io(ioe) = e { is_eof_io_error(ioe) } else { false } } /// Produce a syntax error bearing the message `s` pub fn syntax_error(s: &str) -> Error { Error::Io(io_syntax_error(s)) } /// True iff `e` is a syntax error; see [is_syntax_io_error] pub fn is_syntax_error(e: &Error) -> bool { if let Error::Io(ioe) = e { is_syntax_io_error(ioe) } else { false } } //--------------------------------------------------------------------------- /// Produce an [io::Error] of [io::ErrorKind::UnexpectedEof]. pub fn io_eof() -> io::Error { io::Error::new(io::ErrorKind::UnexpectedEof, "EOF") } /// True iff `e` is [io::ErrorKind::UnexpectedEof] pub fn is_eof_io_error(e: &io::Error) -> bool { matches!(e.kind(), io::ErrorKind::UnexpectedEof) } /// Produce a syntax error ([io::ErrorKind::InvalidData]) bearing the message `s` pub fn io_syntax_error(s: &str) -> io::Error { io::Error::new(io::ErrorKind::InvalidData, s) } /// True iff `e` is an [io::ErrorKind::InvalidData] (a syntax error) pub fn is_syntax_io_error(e: &io::Error) -> bool { matches!(e.kind(), io::ErrorKind::InvalidData) }