Coverage Report

Created: 2024-10-22 12:33

/build/source/nativelink-error/src/lib.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2024 The NativeLink Authors. All rights reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
use std::convert::Into;
16
17
use nativelink_metric::{
18
    MetricFieldData, MetricKind, MetricPublishKnownKindData, MetricsComponent,
19
};
20
use prost_types::TimestampError;
21
use serde::{Deserialize, Serialize};
22
23
#[macro_export]
24
macro_rules! make_err {
25
    ($code:expr, $($arg:tt)+) => {{
26
        $crate::Error::new(
27
            $code,
28
            format!("{}", format_args!($($arg)+)),
29
        )
30
    }};
31
}
32
33
#[macro_export]
34
macro_rules! make_input_err {
35
    ($($arg:tt)+) => {{
36
        $crate::make_err!($crate::Code::InvalidArgument, $($arg)+)
37
    }};
38
}
39
40
#[macro_export]
41
macro_rules! error_if {
42
    ($cond:expr, $($arg:tt)+) => {{
43
        if $cond {
44
            Err($crate::make_err!($crate::Code::InvalidArgument, $($arg)+))?;
45
        }
46
    }};
47
}
48
49
0
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
50
pub struct Error {
51
    pub code: Code,
52
    pub messages: Vec<String>,
53
}
54
55
impl MetricsComponent for Error {
56
0
    fn publish(
57
0
        &self,
58
0
        kind: MetricKind,
59
0
        field_metadata: MetricFieldData,
60
0
    ) -> Result<MetricPublishKnownKindData, nativelink_metric::Error> {
61
0
        self.to_string().publish(kind, field_metadata)
62
0
    }
63
}
64
65
impl Error {
66
631
    pub fn new(code: Code, msg: String) -> Self {
67
631
        let mut msgs = Vec::with_capacity(1);
68
631
        if !msg.is_empty() {
  Branch (68:12): [True: 631, False: 0]
  Branch (68:12): [Folded - Ignored]
69
631
            msgs.push(msg);
70
631
        }
0
71
631
        Self {
72
631
            code,
73
631
            messages: msgs,
74
631
        }
75
631
    }
76
77
    #[inline]
78
    #[must_use]
79
18
    pub fn append<S: Into<String>>(mut self, msg: S) -> Self {
80
18
        self.messages.push(msg.into());
81
18
        self
82
18
    }
83
84
    #[must_use]
85
2
    pub fn merge<E: Into<Self>>(mut self, other: E) -> Self {
86
2
        let mut other: Self = other.into();
87
2
        // This will help with knowing which messages are tied to different errors.
88
2
        self.messages.push("---".to_string());
89
2
        self.messages.append(&mut other.messages);
90
2
        self
91
2
    }
92
93
    #[must_use]
94
6
    pub fn merge_option<T: Into<Self>, U: Into<Self>>(
95
6
        this: Option<T>,
96
6
        other: Option<U>,
97
6
    ) -> Option<Self> {
98
6
        if let Some(
this1
) = this {
  Branch (98:16): [Folded - Ignored]
  Branch (98:16): [Folded - Ignored]
  Branch (98:16): [True: 1, False: 5]
99
1
            if let Some(
other0
) = other {
  Branch (99:20): [Folded - Ignored]
  Branch (99:20): [Folded - Ignored]
  Branch (99:20): [True: 0, False: 1]
100
0
                return Some(this.into().merge(other));
101
1
            }
102
1
            return Some(this.into());
103
5
        }
104
5
        other.map(Into::into)
105
6
    }
106
107
0
    pub fn to_std_err(self) -> std::io::Error {
108
0
        std::io::Error::new(self.code.into(), self.messages.join(" : "))
109
0
    }
110
111
6
    pub fn message_string(&self) -> String {
112
6
        self.messages.join(" : ")
113
6
    }
114
}
115
116
impl std::error::Error for Error {}
117
118
impl From<Error> for nativelink_proto::google::rpc::Status {
119
6
    fn from(val: Error) -> Self {
120
6
        Self {
121
6
            code: val.code as i32,
122
6
            message: val.message_string(),
123
6
            details: vec![],
124
6
        }
125
6
    }
126
}
127
128
impl From<nativelink_proto::google::rpc::Status> for Error {
129
2
    fn from(val: nativelink_proto::google::rpc::Status) -> Self {
130
2
        Self {
131
2
            code: val.code.into(),
132
2
            messages: vec![val.message],
133
2
        }
134
2
    }
135
}
136
137
impl std::fmt::Display for Error {
138
8
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139
8
        // A manual impl to reduce the noise of frequently empty fields.
140
8
        let mut builder = f.debug_struct("Error");
141
8
142
8
        builder.field("code", &self.code);
143
8
144
8
        if !self.messages.is_empty() {
  Branch (144:12): [True: 8, False: 0]
  Branch (144:12): [Folded - Ignored]
145
8
            builder.field("messages", &self.messages);
146
8
        }
0
147
148
8
        builder.finish()
149
8
    }
150
}
151
152
impl From<prost::DecodeError> for Error {
153
0
    fn from(err: prost::DecodeError) -> Self {
154
0
        make_err!(Code::Internal, "{}", err.to_string())
155
0
    }
156
}
157
158
impl From<prost::EncodeError> for Error {
159
0
    fn from(err: prost::EncodeError) -> Self {
160
0
        make_err!(Code::Internal, "{}", err.to_string())
161
0
    }
162
}
163
164
impl From<prost::UnknownEnumValue> for Error {
165
0
    fn from(err: prost::UnknownEnumValue) -> Self {
166
0
        make_err!(Code::Internal, "{}", err.to_string())
167
0
    }
168
}
169
170
impl From<std::num::TryFromIntError> for Error {
171
0
    fn from(err: std::num::TryFromIntError) -> Self {
172
0
        make_err!(Code::InvalidArgument, "{}", err.to_string())
173
0
    }
174
}
175
176
impl From<tokio::task::JoinError> for Error {
177
0
    fn from(err: tokio::task::JoinError) -> Self {
178
0
        make_err!(Code::Internal, "{}", err.to_string())
179
0
    }
180
}
181
182
impl From<std::num::ParseIntError> for Error {
183
0
    fn from(err: std::num::ParseIntError) -> Self {
184
0
        make_err!(Code::InvalidArgument, "{}", err.to_string())
185
0
    }
186
}
187
188
impl From<hex::FromHexError> for Error {
189
0
    fn from(err: hex::FromHexError) -> Self {
190
0
        make_err!(Code::InvalidArgument, "{}", err.to_string())
191
0
    }
192
}
193
194
impl From<std::convert::Infallible> for Error {
195
0
    fn from(_err: std::convert::Infallible) -> Self {
196
0
        // Infallible is an error type that can never happen.
197
0
        unreachable!();
198
    }
199
}
200
201
impl From<TimestampError> for Error {
202
0
    fn from(err: TimestampError) -> Self {
203
0
        make_err!(Code::InvalidArgument, "{}", err)
204
0
    }
205
}
206
207
impl From<std::io::Error> for Error {
208
4
    fn from(err: std::io::Error) -> Self {
209
4
        Self {
210
4
            code: err.kind().into(),
211
4
            messages: vec![err.to_string()],
212
4
        }
213
4
    }
214
}
215
216
impl From<Code> for Error {
217
0
    fn from(code: Code) -> Self {
218
0
        make_err!(code, "")
219
0
    }
220
}
221
222
impl From<fred::error::RedisError> for Error {
223
0
    fn from(error: fred::error::RedisError) -> Self {
224
        use fred::error::RedisErrorKind::{
225
            Auth, Backpressure, Canceled, Cluster, Config, InvalidArgument, InvalidCommand,
226
            NotFound, Parse, Protocol, Sentinel, Timeout, Tls, Unknown, Url, IO,
227
        };
228
229
        // Conversions here are based on https://grpc.github.io/grpc/core/md_doc_statuscodes.html.
230
0
        let code = match error.kind() {
231
0
            Config | InvalidCommand | InvalidArgument | Url => Code::InvalidArgument,
232
0
            IO | Protocol | Tls | Cluster | Parse | Sentinel => Code::Internal,
233
0
            Auth => Code::PermissionDenied,
234
0
            Canceled => Code::Aborted,
235
0
            Unknown => Code::Unknown,
236
0
            Timeout => Code::DeadlineExceeded,
237
0
            NotFound => Code::NotFound,
238
0
            Backpressure => Code::Unavailable,
239
        };
240
241
0
        make_err!(code, "{error}")
242
0
    }
243
}
244
245
impl From<tonic::transport::Error> for Error {
246
0
    fn from(error: tonic::transport::Error) -> Self {
247
0
        make_err!(Code::Internal, "{}", error.to_string())
248
0
    }
249
}
250
251
impl From<tonic::Status> for Error {
252
2
    fn from(status: tonic::Status) -> Self {
253
2
        make_err!(status.code().into(), "{}", status.to_string())
254
2
    }
255
}
256
257
impl From<Error> for tonic::Status {
258
11
    fn from(val: Error) -> Self {
259
11
        Self::new(val.code.into(), val.messages.join(" : "))
260
11
    }
261
}
262
263
pub trait ResultExt<T> {
264
    fn err_tip_with_code<F, S>(self, tip_fn: F) -> Result<T, Error>
265
    where
266
        Self: Sized,
267
        S: std::string::ToString,
268
        F: (std::ops::FnOnce(&Error) -> (Code, S)) + Sized;
269
270
    #[inline]
271
159k
    fn err_tip<F, S>(self, tip_fn: F) -> Result<T, Error>
272
159k
    where
273
159k
        Self: Sized,
274
159k
        S: std::string::ToString,
275
159k
        F: (std::ops::FnOnce() -> S) + Sized,
276
159k
    {
277
159k
        self.err_tip_with_code(|e| 
(e.code, tip_fn())98
)
278
159k
    }
279
280
0
    fn merge<U>(self, _other: Result<U, Error>) -> Result<U, Error>
281
0
    where
282
0
        Self: Sized,
283
0
    {
284
0
        unreachable!();
285
    }
286
}
287
288
impl<T, E: Into<Error>> ResultExt<T> for Result<T, E> {
289
    #[inline]
290
158k
    fn err_tip_with_code<F, S>(self, tip_fn: F) -> Result<T, Error>
291
158k
    where
292
158k
        Self: Sized,
293
158k
        S: std::string::ToString,
294
158k
        F: (std::ops::FnOnce(&Error) -> (Code, S)) + Sized,
295
158k
    {
296
158k
        self.map_err(|e| {
297
88
            let mut error: Error = e.into();
298
88
            let (code, message) = tip_fn(&error);
299
88
            error.code = code;
300
88
            error.messages.push(message.to_string());
301
88
            error
302
158k
        })
303
158k
    }
304
305
5.64k
    fn merge<U>(self, other: Result<U, Error>) -> Result<U, Error>
306
5.64k
    where
307
5.64k
        Self: Sized,
308
5.64k
    {
309
5.64k
        if let Err(
e15
) = self {
  Branch (309:16): [Folded - Ignored]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 1, False: 5]
  Branch (309:16): [True: 3, False: 37]
  Branch (309:16): [True: 4, False: 158]
  Branch (309:16): [True: 0, False: 1]
  Branch (309:16): [True: 0, False: 1]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 1, False: 17]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 1.23k]
  Branch (309:16): [True: 0, False: 1]
  Branch (309:16): [True: 3, False: 4.04k]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 1]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 10]
  Branch (309:16): [True: 0, False: 1]
  Branch (309:16): [True: 0, False: 3]
  Branch (309:16): [True: 0, False: 2]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 16]
  Branch (309:16): [True: 0, False: 4]
  Branch (309:16): [True: 1, False: 3]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [Folded - Ignored]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 1, False: 4]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 2]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 25]
  Branch (309:16): [True: 0, False: 5]
  Branch (309:16): [True: 0, False: 4]
  Branch (309:16): [True: 0, False: 1]
  Branch (309:16): [True: 0, False: 5]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 1, False: 43]
  Branch (309:16): [True: 0, False: 4]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 0]
  Branch (309:16): [True: 0, False: 0]
310
15
            let mut e: Error = e.into();
311
15
            if let Err(
other_err13
) = other {
  Branch (311:20): [Folded - Ignored]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 1]
  Branch (311:20): [True: 3, False: 0]
  Branch (311:20): [True: 4, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 1, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 3, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 1, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [Folded - Ignored]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 1, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 1]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
  Branch (311:20): [True: 0, False: 0]
312
13
                let mut other_err: Error = other_err;
313
13
                // This will help with knowing which messages are tied to different errors.
314
13
                e.messages.push("---".to_string());
315
13
                e.messages.append(&mut other_err.messages);
316
13
            }
2
317
15
            return Err(e);
318
5.63k
        }
319
5.63k
        other
320
5.64k
    }
321
}
322
323
impl<T> ResultExt<T> for Option<T> {
324
    #[inline]
325
5.44k
    fn err_tip_with_code<F, S>(self, tip_fn: F) -> Result<T, Error>
326
5.44k
    where
327
5.44k
        Self: Sized,
328
5.44k
        S: std::string::ToString,
329
5.44k
        F: (std::ops::FnOnce(&Error) -> (Code, S)) + Sized,
330
5.44k
    {
331
5.44k
        self.ok_or_else(|| {
332
17
            let mut error = Error {
333
17
                code: Code::Internal,
334
17
                messages: vec![],
335
17
            };
336
17
            let (code, message) = tip_fn(&error);
337
17
            error.code = code;
338
17
            error.messages.push(message.to_string());
339
17
            error
340
5.44k
        })
341
5.44k
    }
342
}
343
344
0
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
345
#[non_exhaustive] // New Codes may be added in the future, so never exhaustively match!
346
pub enum Code {
347
    Ok = 0,
348
    Cancelled = 1,
349
    Unknown = 2,
350
    InvalidArgument = 3,
351
    DeadlineExceeded = 4,
352
    NotFound = 5,
353
    AlreadyExists = 6,
354
    PermissionDenied = 7,
355
    ResourceExhausted = 8,
356
    FailedPrecondition = 9,
357
    Aborted = 10,
358
    OutOfRange = 11,
359
    Unimplemented = 12,
360
    Internal = 13,
361
    Unavailable = 14,
362
    DataLoss = 15,
363
    Unauthenticated = 16,
364
    // NOTE: Additional codes must be added to stores.rs in ErrorCodes and also
365
    // in both match statements in retry.rs.
366
}
367
368
impl From<i32> for Code {
369
2
    fn from(code: i32) -> Self {
370
2
        match code {
371
2
            
x0
if x == Self::Ok as i32 =>
Self::Ok0
,
  Branch (371:18): [True: 0, False: 2]
  Branch (371:18): [Folded - Ignored]
372
2
            
x0
if x == Self::Cancelled as i32 =>
Self::Cancelled0
,
  Branch (372:18): [True: 0, False: 2]
  Branch (372:18): [Folded - Ignored]
373
2
            
x0
if x == Self::Unknown as i32 =>
Self::Unknown0
,
  Branch (373:18): [True: 0, False: 2]
  Branch (373:18): [Folded - Ignored]
374
2
            
x0
if x == Self::InvalidArgument as i32 =>
Self::InvalidArgument0
,
  Branch (374:18): [True: 0, False: 2]
  Branch (374:18): [Folded - Ignored]
375
2
            
x0
if x == Self::DeadlineExceeded as i32 =>
Self::DeadlineExceeded0
,
  Branch (375:18): [True: 0, False: 2]
  Branch (375:18): [Folded - Ignored]
376
2
            
x0
if x == Self::NotFound as i32 =>
Self::NotFound0
,
  Branch (376:18): [True: 0, False: 2]
  Branch (376:18): [Folded - Ignored]
377
2
            
x0
if x == Self::AlreadyExists as i32 =>
Self::AlreadyExists0
,
  Branch (377:18): [True: 0, False: 2]
  Branch (377:18): [Folded - Ignored]
378
2
            
x0
if x == Self::PermissionDenied as i32 =>
Self::PermissionDenied0
,
  Branch (378:18): [True: 0, False: 2]
  Branch (378:18): [Folded - Ignored]
379
2
            
x0
if x == Self::ResourceExhausted as i32 =>
Self::ResourceExhausted0
,
  Branch (379:18): [True: 0, False: 2]
  Branch (379:18): [Folded - Ignored]
380
2
            x if x == Self::FailedPrecondition as i32 => Self::FailedPrecondition,
  Branch (380:18): [True: 2, False: 0]
  Branch (380:18): [Folded - Ignored]
381
0
            x if x == Self::Aborted as i32 => Self::Aborted,
  Branch (381:18): [True: 0, False: 0]
  Branch (381:18): [Folded - Ignored]
382
0
            x if x == Self::OutOfRange as i32 => Self::OutOfRange,
  Branch (382:18): [True: 0, False: 0]
  Branch (382:18): [Folded - Ignored]
383
0
            x if x == Self::Unimplemented as i32 => Self::Unimplemented,
  Branch (383:18): [True: 0, False: 0]
  Branch (383:18): [Folded - Ignored]
384
0
            x if x == Self::Internal as i32 => Self::Internal,
  Branch (384:18): [True: 0, False: 0]
  Branch (384:18): [Folded - Ignored]
385
0
            x if x == Self::Unavailable as i32 => Self::Unavailable,
  Branch (385:18): [True: 0, False: 0]
  Branch (385:18): [Folded - Ignored]
386
0
            x if x == Self::DataLoss as i32 => Self::DataLoss,
  Branch (386:18): [True: 0, False: 0]
  Branch (386:18): [Folded - Ignored]
387
0
            x if x == Self::Unauthenticated as i32 => Self::Unauthenticated,
  Branch (387:18): [True: 0, False: 0]
  Branch (387:18): [Folded - Ignored]
388
0
            _ => Self::Unknown,
389
        }
390
2
    }
391
}
392
393
impl From<tonic::Code> for Code {
394
2
    fn from(code: tonic::Code) -> Self {
395
2
        match code {
396
0
            tonic::Code::Ok => Self::Ok,
397
0
            tonic::Code::Cancelled => Self::Cancelled,
398
0
            tonic::Code::Unknown => Self::Unknown,
399
0
            tonic::Code::InvalidArgument => Self::InvalidArgument,
400
0
            tonic::Code::DeadlineExceeded => Self::DeadlineExceeded,
401
1
            tonic::Code::NotFound => Self::NotFound,
402
0
            tonic::Code::AlreadyExists => Self::AlreadyExists,
403
0
            tonic::Code::PermissionDenied => Self::PermissionDenied,
404
0
            tonic::Code::ResourceExhausted => Self::ResourceExhausted,
405
0
            tonic::Code::FailedPrecondition => Self::FailedPrecondition,
406
0
            tonic::Code::Aborted => Self::Aborted,
407
1
            tonic::Code::OutOfRange => Self::OutOfRange,
408
0
            tonic::Code::Unimplemented => Self::Unimplemented,
409
0
            tonic::Code::Internal => Self::Internal,
410
0
            tonic::Code::Unavailable => Self::Unavailable,
411
0
            tonic::Code::DataLoss => Self::DataLoss,
412
0
            tonic::Code::Unauthenticated => Self::Unauthenticated,
413
        }
414
2
    }
415
}
416
417
impl From<Code> for tonic::Code {
418
11
    fn from(val: Code) -> Self {
419
11
        match val {
420
0
            Code::Ok => Self::Ok,
421
0
            Code::Cancelled => Self::Cancelled,
422
0
            Code::Unknown => Self::Unknown,
423
7
            Code::InvalidArgument => Self::InvalidArgument,
424
0
            Code::DeadlineExceeded => Self::DeadlineExceeded,
425
3
            Code::NotFound => Self::NotFound,
426
0
            Code::AlreadyExists => Self::AlreadyExists,
427
0
            Code::PermissionDenied => Self::PermissionDenied,
428
0
            Code::ResourceExhausted => Self::ResourceExhausted,
429
0
            Code::FailedPrecondition => Self::FailedPrecondition,
430
0
            Code::Aborted => Self::Aborted,
431
1
            Code::OutOfRange => Self::OutOfRange,
432
0
            Code::Unimplemented => Self::Unimplemented,
433
0
            Code::Internal => Self::Internal,
434
0
            Code::Unavailable => Self::Unavailable,
435
0
            Code::DataLoss => Self::DataLoss,
436
0
            Code::Unauthenticated => Self::Unauthenticated,
437
        }
438
11
    }
439
}
440
441
impl From<std::io::ErrorKind> for Code {
442
4
    fn from(kind: std::io::ErrorKind) -> Self {
443
4
        match kind {
444
4
            std::io::ErrorKind::NotFound => Self::NotFound,
445
0
            std::io::ErrorKind::PermissionDenied => Self::PermissionDenied,
446
            std::io::ErrorKind::ConnectionRefused
447
            | std::io::ErrorKind::ConnectionReset
448
0
            | std::io::ErrorKind::ConnectionAborted => Self::Unavailable,
449
0
            std::io::ErrorKind::AlreadyExists => Self::AlreadyExists,
450
            std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData => {
451
0
                Self::InvalidArgument
452
            }
453
0
            std::io::ErrorKind::TimedOut => Self::DeadlineExceeded,
454
0
            std::io::ErrorKind::Interrupted => Self::Aborted,
455
            std::io::ErrorKind::NotConnected
456
            | std::io::ErrorKind::AddrInUse
457
            | std::io::ErrorKind::AddrNotAvailable
458
            | std::io::ErrorKind::BrokenPipe
459
            | std::io::ErrorKind::WouldBlock
460
            | std::io::ErrorKind::WriteZero
461
            | std::io::ErrorKind::Other
462
0
            | std::io::ErrorKind::UnexpectedEof => Self::Internal,
463
0
            _ => Self::Unknown,
464
        }
465
4
    }
466
}
467
468
impl From<Code> for std::io::ErrorKind {
469
0
    fn from(kind: Code) -> Self {
470
0
        match kind {
471
0
            Code::Aborted => Self::Interrupted,
472
0
            Code::AlreadyExists => Self::AlreadyExists,
473
0
            Code::DeadlineExceeded => Self::TimedOut,
474
0
            Code::InvalidArgument => Self::InvalidInput,
475
0
            Code::NotFound => Self::NotFound,
476
0
            Code::PermissionDenied => Self::PermissionDenied,
477
0
            Code::Unavailable => Self::ConnectionRefused,
478
0
            _ => Self::Other,
479
        }
480
0
    }
481
}
482
483
// Allows for mapping this type into a generic serialization error.
484
impl serde::ser::Error for Error {
485
0
    fn custom<T: std::fmt::Display>(msg: T) -> Self {
486
0
        Self::new(Code::InvalidArgument, msg.to_string())
487
0
    }
488
}
489
490
// Allows for mapping this type into a generic deserialization error.
491
impl serde::de::Error for Error {
492
0
    fn custom<T: std::fmt::Display>(msg: T) -> Self {
493
0
        Self::new(Code::InvalidArgument, msg.to_string())
494
0
    }
495
}