1use std::error::Error as StdError;
2use std::fmt;
3use std::io;
4use std::result;
5use std::str;
6use std::str::Utf8Error;
7
8use protobuf::Error as ProtobufError;
9
10pub(crate) fn new_error(kind: ErrorKind) -> Error {
13 Error(Box::new(kind))
14}
15
16pub(crate) fn new_blob_error(kind: BlobError) -> Error {
17 Error(Box::new(ErrorKind::Blob(kind)))
18}
19
20pub(crate) fn new_protobuf_error(err: ProtobufError, location: &'static str) -> Error {
21 Error(Box::new(ErrorKind::Protobuf { err, location }))
22}
23
24pub type Result<T> = result::Result<T, Error>;
26
27#[derive(Debug)]
29pub struct Error(Box<ErrorKind>);
30
31impl Error {
32 pub fn kind(&self) -> &ErrorKind {
34 &self.0
35 }
36
37 pub fn into_kind(self) -> ErrorKind {
39 *self.0
40 }
41}
42
43#[non_exhaustive]
45#[derive(Debug)]
46pub enum ErrorKind {
47 Io(io::Error),
49 Protobuf {
51 err: ProtobufError,
52 location: &'static str,
53 },
54 StringtableUtf8 { err: Utf8Error, index: usize },
57 StringtableIndexOutOfBounds { index: usize },
59 Blob(BlobError),
61 }
63
64#[non_exhaustive]
66#[derive(Debug)]
67pub enum BlobError {
68 InvalidHeaderSize,
70 HeaderTooBig {
72 size: u64,
74 },
75 MessageTooBig {
77 size: u64,
79 },
80 Empty,
82}
83
84impl From<io::Error> for Error {
85 fn from(err: io::Error) -> Error {
86 new_error(ErrorKind::Io(err))
87 }
88}
89
90impl From<Error> for io::Error {
91 fn from(err: Error) -> io::Error {
92 io::Error::other(err)
93 }
94}
95
96impl StdError for Error {
97 fn description(&self) -> &str {
98 match *self.0 {
99 ErrorKind::Io(ref err, ..) => {
100 use std::io::ErrorKind;
101 match err.kind() {
102 ErrorKind::NotFound => "io error: not found",
103 ErrorKind::PermissionDenied => "io error: permission denied",
104 ErrorKind::ConnectionRefused => "io error: connection refused",
105 ErrorKind::ConnectionReset => "io error: connection reset",
106 ErrorKind::ConnectionAborted => "io error: connection aborted",
107 ErrorKind::NotConnected => "io error: not connected",
108 ErrorKind::AddrInUse => "io error: address in use",
109 ErrorKind::AddrNotAvailable => "io error: address not available",
110 ErrorKind::BrokenPipe => "io error: broken pipe",
111 ErrorKind::AlreadyExists => "io error: already exists",
112 ErrorKind::WouldBlock => "io error: would block",
113 ErrorKind::InvalidInput => "io error: invalid input",
114 ErrorKind::InvalidData => "io error: invalid data",
115 ErrorKind::TimedOut => "io error: timed out",
116 ErrorKind::WriteZero => "io error: write zero",
117 ErrorKind::Interrupted => "io error: interrupted",
118 ErrorKind::Other => "io error: other",
119 ErrorKind::UnexpectedEof => "io error: unexpected EOF",
120 _ => "io error",
121 }
122 }
123 ErrorKind::Protobuf { .. } => "protobuf error",
124 ErrorKind::StringtableUtf8 { .. } => "UTF-8 error in stringtable",
125 ErrorKind::StringtableIndexOutOfBounds { .. } => "stringtable index out of bounds",
126 ErrorKind::Blob(BlobError::InvalidHeaderSize) => {
127 "blob header size could not be decoded"
128 }
129 ErrorKind::Blob(BlobError::HeaderTooBig { .. }) => "blob header is too big",
130 ErrorKind::Blob(BlobError::MessageTooBig { .. }) => "blob message is too big",
131 ErrorKind::Blob(BlobError::Empty) => "blob is missing fields 'raw' and 'zlib_data",
132 }
133 }
134
135 fn cause(&self) -> Option<&dyn StdError> {
136 match *self.0 {
137 ErrorKind::Io(ref err) => Some(err),
138 ErrorKind::Protobuf { ref err, .. } => Some(err),
139 ErrorKind::StringtableUtf8 { ref err, .. } => Some(err),
140 ErrorKind::StringtableIndexOutOfBounds { .. } => None,
141 ErrorKind::Blob(BlobError::InvalidHeaderSize) => None,
142 ErrorKind::Blob(BlobError::HeaderTooBig { .. }) => None,
143 ErrorKind::Blob(BlobError::MessageTooBig { .. }) => None,
144 ErrorKind::Blob(BlobError::Empty) => None,
145 }
146 }
147}
148
149impl fmt::Display for Error {
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 match *self.0 {
152 ErrorKind::Io(ref err) => err.fmt(f),
153 ErrorKind::Protobuf { ref err, location } => {
154 write!(f, "protobuf error at '{location}': {err}")
155 }
156 ErrorKind::StringtableUtf8 { ref err, index } => {
157 write!(f, "invalid UTF-8 at string table index {index}: {err}")
158 }
159 ErrorKind::StringtableIndexOutOfBounds { index } => {
160 write!(f, "stringtable index out of bounds: {index}")
161 }
162 ErrorKind::Blob(BlobError::InvalidHeaderSize) => {
163 write!(f, "blob header size could not be decoded")
164 }
165 ErrorKind::Blob(BlobError::HeaderTooBig { size }) => {
166 write!(f, "blob header is too big: {size} bytes")
167 }
168 ErrorKind::Blob(BlobError::MessageTooBig { size }) => {
169 write!(f, "blob message is too big: {size} bytes")
170 }
171 ErrorKind::Blob(BlobError::Empty) => {
172 write!(f, "blob is missing fields 'raw' and 'zlib_data'")
173 }
174 }
175 }
176}