1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * */

//! Not complete yet
//! This is where the error definitions can go
//! TODO: Implement proper error handling, this would include defining the error enum,
//! impl std::error::Error using `thiserror` and ensuring all errors are handled appropriately

use std::num::{ParseIntError, TryFromIntError};

#[derive(Debug, thiserror::Error)]
pub enum NimbusError {
    #[error("Invalid persisted data")]
    InvalidPersistedData,
    #[cfg(feature = "stateful")]
    #[error("Rkv error: {0}")]
    RkvError(#[from] rkv::StoreError),
    #[error("IO error: {0}")]
    IOError(#[from] std::io::Error),
    #[error("JSON Error: {0}")]
    JSONError(#[from] serde_json::Error),
    #[error("EvaluationError: {0}")]
    EvaluationError(String),
    #[error("Invalid Expression - didn't evaluate to a bool")]
    InvalidExpression,
    #[error("InvalidFractionError: Should be between 0 and 1")]
    InvalidFraction,
    #[error("TryInto error: {0}")]
    TryFromSliceError(#[from] std::array::TryFromSliceError),
    #[error("Empty ratios!")]
    EmptyRatiosError,
    #[error("Attempt to access an element that is out of bounds")]
    OutOfBoundsError,
    #[error("Error parsing URL: {0}")]
    UrlParsingError(#[from] url::ParseError),
    #[error("UUID parsing error: {0}")]
    UuidError(#[from] uuid::Error),
    #[error("Invalid experiment data received")]
    InvalidExperimentFormat,
    #[error("Invalid path: {0}")]
    InvalidPath(String),
    #[error("Internal error: {0}")]
    InternalError(&'static str),
    #[error("The experiment {0} does not exist")]
    NoSuchExperiment(String),
    #[error("The branch {0} does not exist for the experiment {1}")]
    NoSuchBranch(String, String),
    #[error("Initialization of the database is not yet complete")]
    DatabaseNotReady,
    #[error("Error parsing a string into a version {0}")]
    VersionParsingError(String),
    #[cfg(feature = "stateful")]
    #[error("Behavior error: {0}")]
    BehaviorError(#[from] BehaviorError),
    #[error("TryFromIntError: {0}")]
    TryFromIntError(#[from] TryFromIntError),
    #[error("ParseIntError: {0}")]
    ParseIntError(#[from] ParseIntError),
    #[error("Transform parameter error: {0}")]
    TransformParameterError(String),
    #[cfg(feature = "stateful")]
    #[error("Error with Remote Settings client: {0}")]
    ClientError(#[from] remote_settings::RemoteSettingsError),
    #[cfg(not(feature = "stateful"))]
    #[error("Error in Cirrus: {0}")]
    CirrusError(#[from] CirrusClientError),
    #[error("UniFFI callback error: {0}")]
    UniFFICallbackError(#[from] uniffi::UnexpectedUniFFICallbackError),
}

#[cfg(feature = "stateful")]
#[derive(Debug, thiserror::Error)]
pub enum BehaviorError {
    #[error("Invalid state: {0}")]
    InvalidState(String),
    #[error("Invalid duration: {0}")]
    InvalidDuration(String),
    #[error("IntervalParseError: {0} is not a valid Interval")]
    IntervalParseError(String),
    #[error("The event store is not available on the targeting attributes")]
    MissingEventStore,
}

#[cfg(not(feature = "stateful"))]
#[derive(Debug, thiserror::Error)]
pub enum CirrusClientError {
    #[error("Request missing parameter: {0}")]
    RequestMissingParameter(String),
}

impl<'a> From<jexl_eval::error::EvaluationError<'a>> for NimbusError {
    fn from(eval_error: jexl_eval::error::EvaluationError<'a>) -> Self {
        NimbusError::EvaluationError(eval_error.to_string())
    }
}

pub type Result<T, E = NimbusError> = std::result::Result<T, E>;