[go: up one dir, main page]

speedy/
error.rs

1use {
2    std::{
3        fmt,
4        io
5    }
6};
7
8#[derive(Debug)]
9pub struct Error {
10    kind: ErrorKind
11}
12
13#[derive(Debug)]
14pub enum ErrorKind {
15    InvalidChar,
16    InvalidEnumVariant,
17    InvalidUtf8,
18    InvalidSystemTime,
19    ZeroNonZero,
20    OutOfRangeLength,
21    OutOfRangeUsize,
22    UnexpectedEndOfInput,
23    UnexpectedEndOfOutputBuffer,
24    InputBufferIsTooSmall {
25        actual_size: usize,
26        expected_size: usize
27    },
28    OutputBufferIsTooSmall {
29        actual_size: usize,
30        expected_size: usize
31    },
32
33    LengthIsNotTheSameAsLengthAttribute {
34        field_name: &'static str
35    },
36    ExpectedConstant {
37        constant: &'static [u8]
38    },
39
40    Unsized,
41    EndiannessMismatch,
42    IoError( io::Error )
43}
44
45impl Error {
46    #[inline]
47    fn new( kind: ErrorKind ) -> Self {
48        Error { kind }
49    }
50
51    pub fn custom( message: impl fmt::Display ) -> Self {
52        // The LLVM optimizer doesn't like us adding a new variant,
53        // so instead we reuse the `IoError` one.
54        Error {
55            kind: ErrorKind::IoError( io::Error::new( io::ErrorKind::Other, message.to_string() ) )
56        }
57    }
58
59    #[inline]
60    pub(crate) fn from_io_error( error: io::Error ) -> Self {
61        Error {
62            kind: ErrorKind::IoError( error )
63        }
64    }
65}
66
67impl From< Error > for io::Error {
68    fn from( error: Error ) -> Self {
69        if let ErrorKind::IoError( error ) = error.kind {
70            return error;
71        }
72
73        let is_eof = error.is_eof();
74        let kind = if is_eof {
75            io::ErrorKind::UnexpectedEof
76        } else {
77            io::ErrorKind::InvalidData
78        };
79
80        io::Error::new( kind, format!( "{}", error ) )
81    }
82}
83
84#[inline]
85pub fn get_error_kind( error: &Error ) -> &ErrorKind {
86    &error.kind
87}
88
89impl fmt::Display for Error {
90    fn fmt( &self, fmt: &mut fmt::Formatter<'_> ) -> fmt::Result {
91        match self.kind {
92            ErrorKind::InvalidChar => write!( fmt, "out of range char" ),
93            ErrorKind::InvalidEnumVariant => write!( fmt, "invalid enum variant" ),
94            ErrorKind::InvalidUtf8 => write!( fmt, "encountered invalid utf-8" ),
95            ErrorKind::InvalidSystemTime => write!( fmt, "encountered invalid system time object" ),
96            ErrorKind::ZeroNonZero => write!( fmt, "a field which is supposed to be non-zero is zero" ),
97            ErrorKind::OutOfRangeLength => write!( fmt, "out of range length" ),
98            ErrorKind::OutOfRangeUsize => write!( fmt, "value cannot fit into an usize on this architecture" ),
99            ErrorKind::UnexpectedEndOfInput => write!( fmt, "unexpected end of input" ),
100            ErrorKind::UnexpectedEndOfOutputBuffer => write!( fmt, "unexpected end of output buffer" ),
101            ErrorKind::InputBufferIsTooSmall { actual_size, expected_size } => write!( fmt, "input buffer is too small; expected at least {} bytes, got {}", expected_size, actual_size ),
102            ErrorKind::OutputBufferIsTooSmall { actual_size, expected_size } => write!( fmt, "output buffer is too small; expected at least {} bytes, got {}", expected_size, actual_size ),
103            ErrorKind::LengthIsNotTheSameAsLengthAttribute { field_name } => write!( fmt, "the length of '{}' is not the same as its 'length' attribute", field_name ),
104            ErrorKind::ExpectedConstant { constant } => write!( fmt, "expected a predefined {} bytes(s) long constant", constant.len() ),
105            ErrorKind::Unsized => write!( fmt, "type is unsized hence requires zero-copy deserialization; use `read_from_buffer` or similar to deserialize it" ),
106            ErrorKind::EndiannessMismatch => write!( fmt, "endianness mismatch" ),
107            ErrorKind::IoError( ref error ) => write!( fmt, "{}", error )
108        }
109    }
110}
111
112impl std::error::Error for Error {
113    fn source( &self ) -> Option< &(dyn std::error::Error + 'static) > {
114        match self.kind {
115            ErrorKind::IoError( ref error ) => Some( error ),
116            _ => None
117        }
118    }
119}
120
121pub trait IsEof {
122    fn is_eof( &self ) -> bool;
123}
124
125impl IsEof for Error {
126    fn is_eof( &self ) -> bool {
127        match self.kind {
128            ErrorKind::UnexpectedEndOfInput |
129            ErrorKind::UnexpectedEndOfOutputBuffer => true,
130            ErrorKind::IoError( ref error ) => error.kind() == std::io::ErrorKind::UnexpectedEof,
131            _ => false
132        }
133    }
134}
135
136#[cold]
137pub fn error_invalid_string_utf8< T >( _: std::string::FromUtf8Error ) -> T where T: From< Error > {
138    T::from( Error::new( ErrorKind::InvalidUtf8 ) )
139}
140
141#[cold]
142pub fn error_invalid_str_utf8< T >( _: std::str::Utf8Error ) -> T where T: From< Error > {
143    T::from( Error::new( ErrorKind::InvalidUtf8 ) )
144}
145
146#[cold]
147pub fn error_length_is_not_the_same_as_length_attribute< T >( field_name: &'static str ) -> T where T: From< Error > {
148    T::from( Error::new( ErrorKind::LengthIsNotTheSameAsLengthAttribute { field_name } ) )
149}
150
151#[cold]
152pub fn error_out_of_range_length< T >() -> T where T: From< Error > {
153    T::from( Error::new( ErrorKind::OutOfRangeLength ) )
154}
155
156#[cold]
157pub fn error_invalid_enum_variant< T >() -> T where T: From< Error > {
158    T::from( Error::new( ErrorKind::InvalidEnumVariant ) )
159}
160
161#[cold]
162pub fn error_out_of_range_char< T >() -> T where T: From< Error > {
163    T::from( Error::new( ErrorKind::InvalidChar ) )
164}
165
166#[cold]
167pub fn error_too_big_usize_for_this_architecture< T >() -> T where T: From< Error > {
168    T::from( Error::new( ErrorKind::OutOfRangeUsize ) )
169}
170
171#[cold]
172pub fn error_end_of_input< T >() -> T where T: From< Error > {
173    T::from( Error::new( ErrorKind::UnexpectedEndOfInput ) )
174}
175
176#[cold]
177pub fn error_end_of_output_buffer< T >() -> T where T: From< Error > {
178    T::from( Error::new( ErrorKind::UnexpectedEndOfOutputBuffer ) )
179}
180
181#[cold]
182pub fn error_input_buffer_is_too_small< T >( actual_size: usize, expected_size: usize ) -> T where T: From< Error > {
183    T::from( Error::new( ErrorKind::InputBufferIsTooSmall { actual_size, expected_size } ) )
184}
185
186#[cold]
187pub fn error_output_buffer_is_too_small< T >( actual_size: usize, expected_size: usize ) -> T where T: From< Error > {
188    T::from( Error::new( ErrorKind::OutputBufferIsTooSmall { actual_size, expected_size } ) )
189}
190
191#[cold]
192pub fn error_zero_non_zero< T >() -> T where T: From< Error > {
193    T::from( Error::new( ErrorKind::ZeroNonZero ) )
194}
195
196#[cold]
197pub fn error_invalid_system_time< T >() -> T where T: From< Error > {
198    T::from( Error::new( ErrorKind::InvalidSystemTime ) )
199}
200
201#[cold]
202pub fn error_expected_constant< T >( constant: &'static [u8] ) -> T where T: From< Error > {
203    T::from( Error::new( ErrorKind::ExpectedConstant { constant } ) )
204}
205
206#[cold]
207pub fn error_unsized< T >() -> T where T: From< Error > {
208    T::from( Error::new( ErrorKind::Unsized ) )
209}
210
211#[cold]
212pub fn error_endianness_mismatch< T >() -> T where T: From< Error > {
213    T::from( Error::new( ErrorKind::EndiannessMismatch ) )
214}