diff --git a/README.md b/README.md index 2d0dd29..2867f73 100644 --- a/README.md +++ b/README.md @@ -22,5 +22,8 @@ TBD ## Pending Feature List -- [ ] Provider hooks (2.3.*) - +- Some requirements of Flag Evaluation API. +- Provider hooks (2.3) +- Evaluation context levels and merging (3.2) +- Hooks (4) +- Events (5) diff --git a/src/api/api.rs b/src/api/api.rs index 23f70b4..039df47 100644 --- a/src/api/api.rs +++ b/src/api/api.rs @@ -1,4 +1,4 @@ -use std::sync::{Arc, RwLock}; +use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; use lazy_static::lazy_static; @@ -24,6 +24,14 @@ pub struct OpenFeature { } impl OpenFeature { + pub fn singleton() -> RwLockReadGuard<'static, Self> { + SINGLETON.read().unwrap() + } + + pub fn singleton_mut() -> RwLockWriteGuard<'static, Self> { + SINGLETON.write().unwrap() + } + pub fn set_provider(&mut self, provider: T) where T: FeatureProvider, @@ -46,6 +54,8 @@ impl OpenFeature { #[cfg(test)] mod tests { + use std::thread; + use super::*; use crate::provider::*; @@ -69,4 +79,26 @@ mod tests { assert_eq!(true, value); } + + #[tokio::test] + async fn test_singleton_multi_thread() { + let reader1 = thread::spawn(|| { + let _ = OpenFeature::singleton().provider_metadata(); + }); + + let writer = thread::spawn(|| { + OpenFeature::singleton_mut().set_provider(FixedValueProvider::default()); + }); + + let reader2 = thread::spawn(|| { + let _ = OpenFeature::singleton().provider_metadata(); + }); + + let _ = (reader1.join(), reader2.join(), writer.join()); + + assert_eq!( + "Fixed Value", + OpenFeature::singleton().provider_metadata().name + ); + } } diff --git a/src/provider/feature_provider.rs b/src/provider/feature_provider.rs index 22e08cf..da9ebfe 100644 --- a/src/provider/feature_provider.rs +++ b/src/provider/feature_provider.rs @@ -95,7 +95,7 @@ pub trait FeatureProvider: Send + Sync + 'static { #[derive(Clone, TypedBuilder, Default, Debug)] pub struct ProviderMetadata { #[builder(setter(into))] - name: String, + pub name: String, } impl ProviderMetadata {