bt_bencode/
error.rs

1//! Possible crate errors.
2
3use serde::{de, ser};
4
5#[cfg(all(feature = "alloc", not(feature = "std")))]
6use alloc::{
7    boxed::Box,
8    format,
9    string::{String, ToString},
10};
11#[cfg(feature = "std")]
12use std::{
13    boxed::Box,
14    error, format,
15    string::{String, ToString},
16};
17
18use core::{
19    fmt::{self, Display},
20    result,
21};
22
23/// Alias for a [`Result`][std::result::Result] with a [`bt_bencode::Error`][Error] error type.
24pub type Result<T> = result::Result<T, Error>;
25
26/// Errors during serialization and deserialization.
27pub struct Error {
28    inner: Box<ErrorImpl>,
29}
30
31impl Error {
32    /// Constructs an error with the kind and the byte offset where the error
33    /// was detected.
34    ///
35    /// A byte offset value of `0` indicates that the byte offset is either
36    /// unknown or not relevant.
37    #[must_use]
38    #[inline]
39    pub fn new(kind: ErrorKind, byte_offset: usize) -> Self {
40        Self {
41            inner: Box::new(ErrorImpl { kind, byte_offset }),
42        }
43    }
44
45    #[must_use]
46    #[inline]
47    pub(crate) fn with_kind(kind: ErrorKind) -> Self {
48        Self::new(kind, 0)
49    }
50
51    /// The kind of error encountered
52    #[must_use]
53    #[inline]
54    pub fn kind(&self) -> &ErrorKind {
55        &self.inner.kind
56    }
57
58    /// The byte offset where the error was detected.
59    ///
60    /// Usually, the byte offset is after the problem has been detected. For
61    /// instance, if an integer is not encoded correctly like `i12ae`, the byte
62    /// offset may be after the `a` byte is read.
63    #[must_use]
64    #[inline]
65    pub fn byte_offset(&self) -> usize {
66        self.inner.byte_offset
67    }
68}
69
70impl Display for Error {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        Display::fmt(&self.inner, f)
73    }
74}
75
76impl fmt::Debug for Error {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        fmt::Debug::fmt(&self.inner, f)
79    }
80}
81
82impl de::StdError for Error {
83    #[cfg(feature = "std")]
84    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
85        self.inner.kind.source()
86    }
87}
88
89impl de::Error for Error {
90    fn custom<T: Display>(msg: T) -> Self {
91        Error::with_kind(ErrorKind::Deserialize(msg.to_string()))
92    }
93
94    fn invalid_type(unexp: de::Unexpected<'_>, exp: &dyn de::Expected) -> Self {
95        Error::with_kind(ErrorKind::Deserialize(format!(
96            "unexpected type error. invalid_type={}, expected_type={}",
97            unexp, exp
98        )))
99    }
100}
101
102impl ser::Error for Error {
103    fn custom<T: Display>(msg: T) -> Self {
104        Error::with_kind(ErrorKind::Serialize(msg.to_string()))
105    }
106}
107
108#[cfg(feature = "std")]
109impl From<Error> for std::io::Error {
110    fn from(error: Error) -> Self {
111        if let ErrorKind::Io(error) = error.inner.kind {
112            return error;
113        }
114        std::io::Error::new(std::io::ErrorKind::Other, error.to_string())
115    }
116}
117
118struct ErrorImpl {
119    kind: ErrorKind,
120    byte_offset: usize,
121}
122
123impl Display for ErrorImpl {
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        if self.byte_offset == 0 {
126            Display::fmt(&self.kind, f)
127        } else {
128            write!(f, "{} at byte offset {}", self.kind, self.byte_offset)
129        }
130    }
131}
132
133impl fmt::Debug for ErrorImpl {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        f.debug_struct("Error")
136            .field("kind", &self.kind)
137            .field("byte_offset", &self.byte_offset)
138            .finish()
139    }
140}
141
142/// All possible crate errors.
143#[allow(clippy::module_name_repetitions)]
144// Should the type be non_exhaustive? Probably if this crate was version 1.0+ but would need to bump MSRV to 1.40.0
145// #[non_exhaustive]
146pub enum ErrorKind {
147    /// General deserialization error.
148    ///
149    /// Usually the error is due to mismatching types (e.g. a struct was expecting an u64 but the data had a string).
150    Deserialize(String),
151    /// End of file was encountered while parsing a value.
152    EofWhileParsingValue,
153    /// A value was expected but the deserializer did not find a valid bencoded value.
154    ExpectedSomeValue,
155    /// When deserializing a byte string, the length was not a valid number.
156    InvalidByteStrLen,
157    /// When deserializing an integer, the integer contained non-number characters.
158    InvalidInteger,
159    /// When deserializing a dictionary, the dictionary was not encoded correctly.
160    InvalidDict,
161    /// When deserializing a list, the list was not encoded correctly.
162    InvalidList,
163    #[cfg(feature = "std")]
164    /// An I/O error.
165    Io(std::io::Error),
166    /// When deserializing, a dictionary key was found which was not a byte string.
167    KeyMustBeAByteStr,
168    /// A dictionary key was serialized but a call to serialize the key's value
169    /// was never made after.
170    KeyWithoutValue,
171    /// General serialization error.
172    Serialize(String),
173    /// Unparsed trailing data was detected
174    TrailingData,
175    /// An unsupported type was used during serialization.
176    ///
177    /// Bencode only supports integers, byte strings, lists, and dictionaries.
178    /// Types like `bool`, `f64`, and enums are not supported in general.
179    ///
180    /// Dictionaries only support byte strings as keys.
181    UnsupportedType,
182    /// A dictionary value was serialized but a call to serialize the key was
183    /// never made beforehand.
184    ValueWithoutKey,
185}
186
187#[cfg(feature = "std")]
188impl error::Error for ErrorKind {
189    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
190        match self {
191            ErrorKind::Deserialize(_)
192            | ErrorKind::EofWhileParsingValue
193            | ErrorKind::ExpectedSomeValue
194            | ErrorKind::InvalidByteStrLen
195            | ErrorKind::InvalidInteger
196            | ErrorKind::InvalidDict
197            | ErrorKind::InvalidList
198            | ErrorKind::KeyMustBeAByteStr
199            | ErrorKind::KeyWithoutValue
200            | ErrorKind::Serialize(_)
201            | ErrorKind::TrailingData
202            | ErrorKind::UnsupportedType
203            | ErrorKind::ValueWithoutKey => None,
204            #[cfg(feature = "std")]
205            ErrorKind::Io(source) => Some(source),
206        }
207    }
208}
209
210impl Display for ErrorKind {
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        match self {
213            ErrorKind::Deserialize(str) | ErrorKind::Serialize(str) => f.write_str(str),
214            ErrorKind::EofWhileParsingValue => f.write_str("eof while parsing value"),
215            ErrorKind::ExpectedSomeValue => f.write_str("expected some value"),
216            ErrorKind::InvalidByteStrLen => f.write_str("invalid byte string length"),
217            ErrorKind::InvalidInteger => f.write_str("invalid integer"),
218            ErrorKind::InvalidDict => f.write_str("invalid dictionary"),
219            ErrorKind::InvalidList => f.write_str("invalid list"),
220            ErrorKind::KeyMustBeAByteStr => f.write_str("key must be a byte string"),
221            ErrorKind::KeyWithoutValue => f.write_str("key without value"),
222            ErrorKind::TrailingData => f.write_str("trailing data error"),
223            ErrorKind::UnsupportedType => f.write_str("unsupported type"),
224            ErrorKind::ValueWithoutKey => f.write_str("value without key"),
225            #[cfg(feature = "std")]
226            ErrorKind::Io(source) => Display::fmt(source, f),
227        }
228    }
229}
230
231impl fmt::Debug for ErrorKind {
232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233        match self {
234            ErrorKind::Deserialize(str) | ErrorKind::Serialize(str) => f.write_str(str),
235            ErrorKind::EofWhileParsingValue => f.write_str("eof while parsing value"),
236            ErrorKind::ExpectedSomeValue => f.write_str("expected some value"),
237            ErrorKind::InvalidByteStrLen => f.write_str("invalid byte string length"),
238            ErrorKind::InvalidInteger => f.write_str("invalid integer"),
239            ErrorKind::InvalidDict => f.write_str("invalid dictionary"),
240            ErrorKind::InvalidList => f.write_str("invalid list"),
241            ErrorKind::KeyMustBeAByteStr => f.write_str("key must be a byte string"),
242            ErrorKind::KeyWithoutValue => f.write_str("key without value"),
243            ErrorKind::TrailingData => f.write_str("trailing data error"),
244            ErrorKind::UnsupportedType => f.write_str("unsupported type"),
245            ErrorKind::ValueWithoutKey => f.write_str("value without key"),
246            #[cfg(feature = "std")]
247            ErrorKind::Io(source) => fmt::Debug::fmt(source, f),
248        }
249    }
250}