88//! TODO: Implement proper error handling, this would include defining the error enum,
99//! impl std::error::Error using `thiserror` and ensuring all errors are handled appropriately
1010
11+ use std:: borrow:: Cow ;
1112use std:: num:: { ParseIntError , TryFromIntError } ;
1213
1314// reexport logging helpers.
@@ -71,12 +72,12 @@ pub enum NimbusError {
7172 #[ error( "TryInto error: {0}" ) ]
7273 TryFromSliceError ( #[ from] std:: array:: TryFromSliceError ) ,
7374
74- #[ error( "Error parsing URL: {0}" ) ]
75- UrlParsingError ( #[ from] url:: ParseError ) ,
76-
7775 #[ error( "UniFFI callback error: {0}" ) ]
7876 UniFFICallbackError ( #[ from] uniffi:: UnexpectedUniFFICallbackError ) ,
7977
78+ #[ error( "Error parsing URL: {0}" ) ]
79+ UrlParsingError ( #[ from] url:: ParseError ) ,
80+
8081 #[ error( "UUID parsing error: {0}" ) ]
8182 UuidError ( #[ from] uuid:: Error ) ,
8283
@@ -92,14 +93,14 @@ pub enum NimbusError {
9293 #[ error( "Error with Remote Settings client: {0}" ) ]
9394 ClientError ( #[ from] remote_settings:: RemoteSettingsError ) ,
9495
95- #[ cfg( feature = "stateful" ) ]
96- #[ error( "Rkv error: {0}" ) ]
97- RkvError ( #[ from] rkv:: StoreError ) ,
98-
9996 #[ cfg( feature = "stateful" ) ]
10097 #[ error( "Regex error: {0}" ) ]
10198 RegexError ( #[ from] regex:: Error ) ,
10299
100+ #[ cfg( feature = "stateful" ) ]
101+ #[ error( "Rkv error: {0}" ) ]
102+ RkvError ( #[ from] rkv:: StoreError ) ,
103+
103104 // Cirrus-only errors.
104105 #[ cfg( not( feature = "stateful" ) ) ]
105106 #[ error( "Error in Cirrus: {0}" ) ]
@@ -162,3 +163,83 @@ impl From<VersionParsingError> for NimbusError {
162163}
163164
164165pub type Result < T , E = NimbusError > = std:: result:: Result < T , E > ;
166+
167+ /// An Error extension trait that allows simplified error codes to be submitted
168+ /// in telemetry.
169+ pub trait ErrorCode : std:: error:: Error {
170+ /// Return the error code for the given error.
171+ fn error_code ( & self ) -> Cow < ' static , str > ;
172+ }
173+
174+ #[ cfg( feature = "stateful" ) ]
175+ impl ErrorCode for NimbusError {
176+ fn error_code ( & self ) -> Cow < ' static , str > {
177+ match self {
178+ Self :: BehaviorError ( e) => format ! ( "BehaviorError({})" , e. error_code( ) ) . into ( ) ,
179+ Self :: ClientError ( ..) => "ClientError" . into ( ) ,
180+ Self :: DatabaseNotReady => "DatabaseNotReady" . into ( ) ,
181+ Self :: EmptyRatiosError => "EmptyRatiosError" . into ( ) ,
182+ Self :: EvaluationError ( ..) => "EvaluationError" . into ( ) ,
183+ Self :: IOError ( e) => format ! ( "IOError({:?})" , e. kind( ) ) . into ( ) ,
184+ Self :: InternalError ( ..) => "InternalError" . into ( ) ,
185+ Self :: InvalidExperimentFormat => "InvalidExperimentFormat" . into ( ) ,
186+ Self :: InvalidExpression => "InvalidExpression" . into ( ) ,
187+ Self :: InvalidFraction => "InvalidFraction" . into ( ) ,
188+ Self :: InvalidPath ( ..) => "InvalidPath" . into ( ) ,
189+ Self :: InvalidPersistedData => "InvalidPersistedData" . into ( ) ,
190+ Self :: JSONError ( ..) => "JSONError" . into ( ) ,
191+ Self :: NoSuchBranch ( ..) => "NoSuchBranch" . into ( ) ,
192+ Self :: NoSuchExperiment ( ..) => "NoSuchExperiment" . into ( ) ,
193+ Self :: OutOfBoundsError => "OutOfBoundsError" . into ( ) ,
194+ Self :: ParseIntError ( ..) => "ParseIntError" . into ( ) ,
195+ Self :: RegexError ( ..) => "RegexError" . into ( ) ,
196+ Self :: RkvError ( e) => format ! ( "RkvError({})" , e. error_code( ) ) . into ( ) ,
197+ Self :: TransformParameterError ( ..) => "TransformParameterError" . into ( ) ,
198+ Self :: TryFromIntError ( ..) => "TryFromIntError" . into ( ) ,
199+ Self :: TryFromSliceError ( ..) => "TryFromSliceError" . into ( ) ,
200+ Self :: UniFFICallbackError ( ..) => "UniFFICallbackError" . into ( ) ,
201+ Self :: UrlParsingError ( ..) => "UrlParsingError" . into ( ) ,
202+ Self :: UuidError ( ..) => "UuidError" . into ( ) ,
203+ Self :: VersionParsingError ( ..) => "VersionParsingError" . into ( ) ,
204+ }
205+ }
206+ }
207+
208+ #[ cfg( feature = "stateful" ) ]
209+ impl ErrorCode for rkv:: StoreError {
210+ fn error_code ( & self ) -> Cow < ' static , str > {
211+ match self {
212+ Self :: ManagerPoisonError => "ManagerPoisonError" . into ( ) ,
213+ Self :: DatabaseCorrupted => "DatabaseCorrupted" . into ( ) ,
214+ Self :: KeyValuePairNotFound => "KeyValuePairNotFound" . into ( ) ,
215+ Self :: KeyValuePairBadSize => "KeyValuePairBadSize" . into ( ) ,
216+ Self :: FileInvalid => "FileInvalid" . into ( ) ,
217+ Self :: MapFull => "MapFull" . into ( ) ,
218+ Self :: DbsFull => "DbsFull" . into ( ) ,
219+ Self :: ReadersFull => "ReadersFull" . into ( ) ,
220+ Self :: IoError ( e) => format ! ( "IoError({:?})" , e. kind( ) ) . into ( ) ,
221+ Self :: UnsuitableEnvironmentPath ( ..) => "UnsuitableEnvironmentPath" . into ( ) ,
222+ Self :: DataError ( ..) => "DataError" . into ( ) ,
223+ Self :: SafeModeError ( ..) => "SafeModeError" . into ( ) ,
224+ Self :: ReadTransactionAlreadyExists ( ..) => "ReadTransactionAlreadyExists" . into ( ) ,
225+ Self :: OpenAttemptedDuringTransaction ( ..) => "OpenAttemptedDuringTransaction" . into ( ) ,
226+ }
227+ }
228+ }
229+
230+ #[ cfg( feature = "stateful" ) ]
231+ impl ErrorCode for BehaviorError {
232+ fn error_code ( & self ) -> Cow < ' static , str > {
233+ match self {
234+ Self :: EventQueryParseError ( ..) => "EventQueryParseError" ,
235+ Self :: EventQueryTypeParseError ( ..) => "EventQueryTypeParseError" ,
236+ Self :: IntervalParseError ( ..) => "IntervalParseError" ,
237+ Self :: InvalidDuration ( ..) => "InvalidDuration" ,
238+ Self :: InvalidState ( ..) => "InvalidState" ,
239+ Self :: MissingEventStore => "MissingEventStore" ,
240+ Self :: MissingRecordedContext => "MissingRecordedContext" ,
241+ Self :: TypeError ( ..) => "TypeError" ,
242+ }
243+ . into ( )
244+ }
245+ }
0 commit comments