glean_core/
error.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use std::ffi::OsString;
6use std::fmt::{self, Display};
7use std::io;
8use std::result;
9
10use rkv::StoreError;
11
12/// A specialized [`Result`] type for this crate's operations.
13///
14/// This is generally used to avoid writing out [`Error`] directly and
15/// is otherwise a direct mapping to [`Result`].
16///
17/// [`Result`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html
18/// [`Error`]: std.struct.Error.html
19pub type Result<T, E = Error> = result::Result<T, E>;
20
21/// A list enumerating the categories of errors in this crate.
22///
23/// [`Error`]: https://doc.rust-lang.org/stable/std/error/trait.Error.html
24///
25/// This list is intended to grow over time and it is not recommended to
26/// exhaustively match against it.
27#[derive(Debug)]
28#[non_exhaustive]
29pub enum ErrorKind {
30    /// Lifetime conversion failed
31    Lifetime(i32),
32
33    /// IO error
34    IoError(io::Error),
35
36    /// IO error
37    Rkv(StoreError),
38
39    /// JSON error
40    Json(serde_json::error::Error),
41
42    /// TimeUnit conversion failed
43    TimeUnit(i32),
44
45    /// MemoryUnit conversion failed
46    MemoryUnit(i32),
47
48    /// HistogramType conversion failed
49    HistogramType(i32),
50
51    /// [`OsString`] conversion failed
52    OsString(OsString),
53
54    /// Unknown error
55    Utf8Error,
56
57    /// Glean initialization was attempted with an invalid configuration
58    InvalidConfig,
59
60    /// Glean not initialized
61    NotInitialized,
62
63    /// Ping request body size overflowed
64    PingBodyOverflow(usize),
65
66    /// Parsing a UUID from a string failed
67    UuidError(uuid::Error),
68}
69
70/// A specialized [`Error`] type for this crate's operations.
71///
72/// [`Error`]: https://doc.rust-lang.org/stable/std/error/trait.Error.html
73#[derive(Debug)]
74pub struct Error {
75    kind: ErrorKind,
76}
77
78impl Error {
79    /// Returns a new UTF-8 error
80    ///
81    /// This is exposed in order to expose conversion errors on the FFI layer.
82    pub fn utf8_error() -> Error {
83        Error {
84            kind: ErrorKind::Utf8Error,
85        }
86    }
87
88    /// Indicates an error that no requested global object is initialized
89    pub fn not_initialized() -> Error {
90        Error {
91            kind: ErrorKind::NotInitialized,
92        }
93    }
94
95    /// Returns the kind of the current error instance.
96    pub fn kind(&self) -> &ErrorKind {
97        &self.kind
98    }
99}
100
101impl std::error::Error for Error {}
102
103impl Display for Error {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        use ErrorKind::*;
106        match self.kind() {
107            Lifetime(l) => write!(f, "Lifetime conversion from {} failed", l),
108            IoError(e) => write!(f, "An I/O error occurred: {}", e),
109            Rkv(e) => write!(f, "An Rkv error occurred: {}", e),
110            Json(e) => write!(f, "A JSON error occurred: {}", e),
111            TimeUnit(t) => write!(f, "TimeUnit conversion from {} failed", t),
112            MemoryUnit(m) => write!(f, "MemoryUnit conversion from {} failed", m),
113            HistogramType(h) => write!(f, "HistogramType conversion from {} failed", h),
114            OsString(s) => write!(f, "OsString conversion from {:?} failed", s),
115            Utf8Error => write!(f, "Invalid UTF-8 byte sequence in string"),
116            InvalidConfig => write!(f, "Invalid Glean configuration provided"),
117            NotInitialized => write!(f, "Global Glean object missing"),
118            PingBodyOverflow(s) => write!(
119                f,
120                "Ping request body size exceeded maximum size allowed: {}kB.",
121                s / 1024
122            ),
123            UuidError(e) => write!(f, "Failed to parse UUID: {}", e),
124        }
125    }
126}
127
128impl From<ErrorKind> for Error {
129    fn from(kind: ErrorKind) -> Error {
130        Error { kind }
131    }
132}
133
134impl From<io::Error> for Error {
135    fn from(error: io::Error) -> Error {
136        Error {
137            kind: ErrorKind::IoError(error),
138        }
139    }
140}
141
142impl From<StoreError> for Error {
143    fn from(error: StoreError) -> Error {
144        Error {
145            kind: ErrorKind::Rkv(error),
146        }
147    }
148}
149
150impl From<serde_json::error::Error> for Error {
151    fn from(error: serde_json::error::Error) -> Error {
152        Error {
153            kind: ErrorKind::Json(error),
154        }
155    }
156}
157
158impl From<OsString> for Error {
159    fn from(error: OsString) -> Error {
160        Error {
161            kind: ErrorKind::OsString(error),
162        }
163    }
164}
165
166/// To satisfy integer conversion done by the macros on the FFI side, we need to be able to turn
167/// something infallible into an error.
168/// This will never actually be reached, as an integer-to-integer conversion is infallible.
169impl From<std::convert::Infallible> for Error {
170    fn from(_: std::convert::Infallible) -> Error {
171        unreachable!()
172    }
173}
174
175impl From<uuid::Error> for Error {
176    fn from(error: uuid::Error) -> Self {
177        Error {
178            kind: ErrorKind::UuidError(error),
179        }
180    }
181}
182
183#[derive(Debug)]
184pub enum ClientIdFileError {
185    /// The file could not be found.
186    NotFound,
187    /// Can't access the file due to permissions
188    PermissionDenied,
189    /// Another io error happened
190    IoError(io::Error),
191    /// Parsing the content into a UUID failed
192    ParseError(uuid::Error),
193}
194
195impl Display for ClientIdFileError {
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        use ClientIdFileError::*;
198        match self {
199            NotFound => write!(f, "File not found"),
200            PermissionDenied => write!(
201                f,
202                "The operation lacked the necessary privileges to complete."
203            ),
204            IoError(e) => write!(f, "IO error occured: {e}"),
205            ParseError(e) => write!(f, "Parse error occured: {e}"),
206        }
207    }
208}
209
210impl From<io::Error> for ClientIdFileError {
211    fn from(error: io::Error) -> Self {
212        match error.kind() {
213            io::ErrorKind::NotFound => ClientIdFileError::NotFound,
214            io::ErrorKind::PermissionDenied => ClientIdFileError::PermissionDenied,
215            _ => ClientIdFileError::IoError(error),
216        }
217    }
218}
219
220impl From<uuid::Error> for ClientIdFileError {
221    fn from(error: uuid::Error) -> Self {
222        ClientIdFileError::ParseError(error)
223    }
224}