nimbus/
lib.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
5mod defaults;
6mod enrollment;
7mod evaluator;
8mod json;
9mod sampling;
10mod strings;
11mod targeting;
12
13pub mod error;
14pub mod metrics;
15pub mod schema;
16
17pub use crate::enrollment::{EnrolledFeature, EnrollmentStatus};
18pub use crate::error::{NimbusError, Result};
19#[cfg(debug_assertions)]
20pub use crate::evaluator::evaluate_enrollment;
21pub use crate::schema::*;
22pub use crate::targeting::NimbusTargetingHelper;
23
24cfg_if::cfg_if! {
25    if #[cfg(feature = "stateful")] {
26
27        pub mod stateful;
28
29        pub use remote_settings::{RemoteSettingsConfig, RemoteSettingsServer};
30
31        pub use crate::stateful::nimbus_client::*;
32        pub use crate::stateful::matcher::AppContext;
33    } else {
34        pub mod stateless;
35
36        pub use crate::stateless::cirrus_client::*;
37        pub use crate::stateless::matcher::AppContext;
38    }
39}
40
41#[cfg(feature = "stateful-uniffi-bindings")]
42use json::{JsonObject, PrefValue};
43
44#[cfg(feature = "stateful-uniffi-bindings")]
45uniffi::custom_type!(JsonObject, String, {
46    remote,
47    try_lift: |val| {
48        let json: serde_json::Value = serde_json::from_str(&val)?;
49
50        match json.as_object() {
51            Some(obj) => Ok(obj.clone()),
52            _ => Err(uniffi::deps::anyhow::anyhow!(
53                "Unexpected JSON-non-object in the bagging area"
54            )),
55        }
56    },
57    lower: |obj| serde_json::Value::Object(obj).to_string(),
58});
59
60#[cfg(feature = "stateful-uniffi-bindings")]
61uniffi::custom_type!(PrefValue, String, {
62    remote,
63    try_lift: |val| {
64        // Raw strings that are not valid JSON (e.g. pref values read directly from Gecko)
65        // should be treated as JSON string values.
66        let json: serde_json::Value = match serde_json::from_str(&val) {
67            Ok(json) => json,
68            Err(_) => serde_json::Value::String(val),
69        };
70        let is_valid_pref_type = json.is_string() || json.is_boolean()
71            || (json.is_number() && !json.is_f64()) || json.is_null();
72        if is_valid_pref_type {
73            Ok(json)
74        } else {
75            Err(anyhow::anyhow!(format!("Value {} is not a string, boolean, number, or null, or is a float", json)))
76        }
77    },
78    lower: |val| {
79        val.to_string()
80    }
81});
82
83// Exposed for Example only
84pub use evaluator::TargetingAttributes;
85
86pub(crate) const SLUG_REPLACEMENT_PATTERN: &str = "{experiment}";
87
88#[cfg(test)]
89mod tests;