Skip to main content

ion_rs/result/
mod.rs

1//! Types for reporting various modes of success or failure.
2
3use std::borrow::Cow;
4use std::convert::From;
5use std::fmt::{Debug, Error};
6use std::{fmt, io};
7
8use thiserror::Error;
9
10#[cfg(feature = "experimental-serde")]
11use serde::{de, ser};
12
13mod conversion;
14mod decoding_error;
15mod encoding_error;
16mod illegal_operation;
17mod incomplete;
18mod io_error;
19
20pub use conversion::ConversionOperationError;
21pub use conversion::ConversionOperationResult;
22pub use conversion::IonTypeExpectation;
23pub use conversion::TypeExpectation;
24pub use decoding_error::DecodingError;
25pub use encoding_error::EncodingError;
26pub use illegal_operation::IllegalOperation;
27pub use incomplete::IncompleteError;
28pub use io_error::IoError;
29
30use crate::position::Position;
31use crate::result::conversion::{ConversionError, ValueTypeExpectation};
32
33/// A unified Result type representing the outcome of method calls that may fail.
34pub type IonResult<T> = Result<T, IonError>;
35
36/// Represents the different types of high-level failures that might occur when reading Ion data.
37#[non_exhaustive]
38#[derive(Clone, Debug, Error, PartialEq)]
39pub enum IonError {
40    /// Indicates that an IO error was encountered while reading or writing.
41    #[error("{0}")]
42    Io(#[from] IoError),
43
44    /// Indicates that the input buffer did not contain enough data to perform the requested read
45    /// operation. If the input source contains more data, the reader can append it to the buffer
46    /// and try again.
47    #[error("{0}")]
48    Incomplete(#[from] IncompleteError),
49
50    /// Indicates that the writer encountered a problem while serializing a given piece of data.
51    #[error("{0}")]
52    Encoding(#[from] EncodingError),
53
54    /// Indicates that the data stream being read contained illegal or otherwise unreadable data.
55    #[error("{0}")]
56    Decoding(#[from] DecodingError),
57
58    /// Returned when the user has performed an illegal operation (for example: calling stepOut()
59    /// on the cursor at the top level.)
60    #[error("{0}")]
61    IllegalOperation(#[from] IllegalOperation),
62
63    /// Returned when the user has attempted to convert a value to a type for which that value is
64    /// not trivially convertable.
65    #[error("{0}")]
66    Conversion(#[from] ConversionError),
67}
68
69impl From<io::Error> for IonError {
70    fn from(io_error: io::Error) -> Self {
71        IoError::from(io_error).into()
72    }
73}
74
75impl From<io::ErrorKind> for IonError {
76    fn from(error_kind: io::ErrorKind) -> Self {
77        // io::ErrorKind -> io::Error
78        let io_error = io::Error::from(error_kind);
79        // io::Error -> IoError -> IonError
80        IoError::from(io_error).into()
81    }
82}
83
84impl From<fmt::Error> for IonError {
85    fn from(error: Error) -> Self {
86        EncodingError::new(error.to_string()).into()
87    }
88}
89
90impl From<IonError> for fmt::Error {
91    fn from(_ion_error: IonError) -> Self {
92        // This no-op transformation allows `?` to be used in `Debug` implementations wherever
93        // an IonError could surface.
94        fmt::Error
95    }
96}
97
98impl<FromType, ToType> From<ConversionOperationError<FromType, ToType>> for IonError
99where
100    FromType: ValueTypeExpectation,
101    ToType: TypeExpectation,
102{
103    fn from(err: ConversionOperationError<FromType, ToType>) -> Self {
104        ConversionError::from(err).into()
105    }
106}
107
108#[cfg(feature = "experimental-serde")]
109impl de::Error for IonError {
110    fn custom<T>(error: T) -> Self
111    where
112        T: std::fmt::Display,
113    {
114        DecodingError::new(error.to_string()).into()
115    }
116}
117
118#[cfg(feature = "experimental-serde")]
119impl ser::Error for IonError {
120    fn custom<T>(error: T) -> Self
121    where
122        T: std::fmt::Display,
123    {
124        EncodingError::new(error.to_string()).into()
125    }
126}
127
128// Crate-visible convenience methods for constructing error variants and wrapping them in the
129// appropriate type: IonResult<T> or IonError. This is a trait so these methods can be added to
130// `IonResult<T>`, which is just a type alias for `Result<T, IonError>`, whose implementation
131// does not live in this crate.
132pub(crate) trait IonFailure {
133    // Note: this trait does not have an `io(...)` method because the only way we ever construct
134    // an `IonError::Io` is by converting a `std::io::IoError` with the ? operator.
135    // Because this trait is only crate-visible, methods can be added/changed as needed in
136    // the future.
137    fn incomplete(label: impl Into<Cow<'static, str>>, position: impl Into<Position>) -> Self;
138    fn decoding_error<S: Into<Cow<'static, str>>>(description: S) -> Self;
139    fn encoding_error<S: Into<Cow<'static, str>>>(description: S) -> Self;
140    fn illegal_operation<S: Into<Cow<'static, str>>>(operation: S) -> Self;
141}
142
143impl IonFailure for IonError {
144    fn incomplete(label: impl Into<Cow<'static, str>>, position: impl Into<Position>) -> Self {
145        IncompleteError::new(label, position).into()
146    }
147
148    fn decoding_error<S: Into<Cow<'static, str>>>(description: S) -> Self {
149        DecodingError::new(description).into()
150    }
151
152    fn encoding_error<S: Into<Cow<'static, str>>>(description: S) -> Self {
153        EncodingError::new(description).into()
154    }
155
156    fn illegal_operation<S: Into<Cow<'static, str>>>(operation: S) -> Self {
157        IllegalOperation::new(operation).into()
158    }
159}
160
161impl<T> IonFailure for IonResult<T> {
162    fn incomplete(label: impl Into<Cow<'static, str>>, position: impl Into<Position>) -> Self {
163        Err(IonError::incomplete(label, position))
164    }
165
166    fn decoding_error<S: Into<Cow<'static, str>>>(description: S) -> Self {
167        Err(IonError::decoding_error(description))
168    }
169
170    fn encoding_error<S: Into<Cow<'static, str>>>(description: S) -> Self {
171        Err(IonError::encoding_error(description))
172    }
173
174    fn illegal_operation<S: Into<Cow<'static, str>>>(operation: S) -> Self {
175        Err(IonError::illegal_operation(operation))
176    }
177}