Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ maintenance = { status = "actively-developed" }

[dependencies]
async-trait = "0.1.80"
lazy_static = "1.5"
mockall = { version = "0.13.0", optional = true }
serde_json = { version = "1.0.116", optional = true }
time = "0.3.36"
tokio = { version = "1.40", features = ["full"] }
tokio = { version = "1.40", features = ["sync"] }
typed-builder = "0.22.0"

log = { package = "log", version = "0.4", optional = true }
Expand All @@ -30,6 +29,7 @@ log = { package = "log", version = "0.4", optional = true }
env_logger = "0.11.5"
structured-logger = "1.0.3"
spec = { path = "spec" }
tokio = { version = "1.40", features = ["macros", "rt-multi-thread"] }

[features]
default = ["test-util", "dep:log"]
Expand Down
19 changes: 11 additions & 8 deletions src/api/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use lazy_static::lazy_static;
use std::sync::OnceLock;

use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};

use crate::{
Expand All @@ -11,11 +12,9 @@ use super::{
provider_registry::ProviderRegistry,
};

lazy_static! {
/// The singleton instance of [`OpenFeature`] struct.
/// The client should always use this instance to access OpenFeature APIs.
static ref SINGLETON: RwLock<OpenFeature> = RwLock::new(OpenFeature::default());
}
/// The singleton instance of [`OpenFeature`] struct.
/// The client should always use this instance to access OpenFeature APIs.
static SINGLETON: OnceLock<RwLock<OpenFeature>> = OnceLock::new();

/// THE struct of the OpenFeature API.
/// Access it via the [`SINGLETON`] instance.
Expand All @@ -27,15 +26,19 @@ pub struct OpenFeature {
provider_registry: ProviderRegistry,
}

fn get_or_init() -> &'static RwLock<OpenFeature> {
SINGLETON.get_or_init(|| RwLock::new(OpenFeature::default()))
}

impl OpenFeature {
/// Get the singleton of [`OpenFeature`].
pub async fn singleton() -> RwLockReadGuard<'static, Self> {
SINGLETON.read().await
get_or_init().read().await
}

/// Get a mutable singleton of [`OpenFeature`].
pub async fn singleton_mut() -> RwLockWriteGuard<'static, Self> {
SINGLETON.write().await
get_or_init().write().await
}

/// Set the global evaluation context.
Expand Down
5 changes: 1 addition & 4 deletions src/api/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,10 +622,7 @@ mod tests {

let client = create_client(provider).await;

assert_eq!(
client.get_bool_value("key", None, None).await.unwrap(),
true
);
assert!(client.get_bool_value("key", None, None).await.unwrap());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that this is equivalent with the old one, but I personally prefer assert_eq! because it makes it explicit that we are expecting a boolean value.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite unconventional, and the use of assert! is prevalent in src/evaluation/value.rs.
Sure about this?


assert_eq!(client.get_int_value("key", None, None).await.unwrap(), 123);

Expand Down
4 changes: 2 additions & 2 deletions src/evaluation/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ mod tests {
fn merge_missing_given_targeting_key() {
let mut context = EvaluationContext::default()
.with_targeting_key("Targeting Key")
.to_owned();
.clone();

let expected = context.clone();

Expand All @@ -122,7 +122,7 @@ mod tests {
.with_targeting_key("Targeting Key")
.with_custom_field("Key", "Value")
.with_custom_field("Another Key", "Value")
)
);
}

#[test]
Expand Down
6 changes: 3 additions & 3 deletions src/evaluation/context_field_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ mod tests {
.with_custom_field("Int", 42)
.with_custom_field("Float", 42.0)
.with_custom_field("String", "StringValue")
.with_custom_field("DateTime", now.clone())
.with_custom_field("DateTime", now)
.with_custom_field(
"Struct",
EvaluationContextFieldValue::new_struct(EvaluationReason::Cached),
Expand All @@ -237,7 +237,7 @@ mod tests {
// Assert bool
if let EvaluationContextFieldValue::Bool(value) = context.custom_fields.get("Bool").unwrap()
{
assert_eq!(true, *value);
assert!(*value);
} else {
panic!()
}
Expand Down Expand Up @@ -284,6 +284,6 @@ mod tests {
assert_eq!(EvaluationReason::Cached, *v);
} else {
panic!()
};
}
}
}
2 changes: 1 addition & 1 deletion src/evaluation/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ mod tests {

let is_male = alex.fields.get("is_male").unwrap();
assert!(is_male.is_bool());
assert_eq!(false, is_male.as_bool().unwrap());
assert!(!is_male.as_bool().unwrap());

let id = alex.fields.get("id").unwrap();
assert!(id.is_i64());
Expand Down
12 changes: 6 additions & 6 deletions src/hooks/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl LoggingHook {

#[cfg(feature = "structured-logging")]
mod structured {
use super::*;
use super::{EvaluationDetails, EvaluationError, HookContext, LoggingHook, Value};
use log::{kv::Value as LogValue, Level, Record};

const DOMAIN_KEY: &str = "domain";
Expand Down Expand Up @@ -154,7 +154,7 @@ mod structured {
// See issue https://github.com/rust-lang/rust/issues/92698
log::logger().log(
&Record::builder()
.args(format_args!("{}", msg))
.args(format_args!("{msg}"))
.level(level)
.target("open_feature")
.module_path_static(Some(module_path!()))
Expand Down Expand Up @@ -188,9 +188,9 @@ mod structured {
}
}

fn evaluation_details_to_kvs<'a>(
details: &'a EvaluationDetails<Value>,
) -> Vec<(&'static str, LogValue<'a>)> {
fn evaluation_details_to_kvs(
details: &EvaluationDetails<Value>,
) -> Vec<(&'static str, LogValue<'_>)> {
let kvs = vec![
(REASON_KEY, LogValue::from_debug(&details.reason)),
(VARIANT_KEY, LogValue::from_debug(&details.variant)),
Expand All @@ -200,7 +200,7 @@ mod structured {
kvs
}

fn error_to_kvs<'a>(error: &'a EvaluationError) -> Vec<(&'static str, LogValue<'a>)> {
fn error_to_kvs(error: &EvaluationError) -> Vec<(&'static str, LogValue<'_>)> {
let kvs = vec![(ERROR_MESSAGE_KEY, LogValue::from_debug(&error.message))];

kvs
Expand Down
2 changes: 1 addition & 1 deletion src/serde_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn json_value_to_value(value: &serde_json::Value) -> EvaluationResult<Value> {
serde_json::Value::Array(array) => Ok(Value::Array(
array
.iter()
.map(|x| json_value_to_value(x))
.map(json_value_to_value)
.collect::<Result<Vec<_>, _>>()?,
)),
serde_json::Value::Object(object) => {
Expand Down