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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use async_trait::async_trait;

use crate::{EvaluationContext, EvaluationResult, StructValue};

use super::ResolutionDetails;

// ============================================================
//  FeatureProvider
// ============================================================

/// This trait defines interfaces that Provider Authors can use to abstract a particular flag
/// management system, thus enabling the use of the evaluation API by Application Authors.
///
/// Providers are the "translator" between the flag evaluation calls made in application code, and
/// the flag management system that stores flags and in some cases evaluates flags. At a minimum,
/// providers should implement some basic evaluation methods which return flag values of the
/// expected type. In addition, providers may transform the evaluation context appropriately in
/// order to be used in dynamic evaluation of their associated flag management system, provide
/// insight into why evaluation proceeded the way it did, and expose configuration options for
/// their associated flag management system. Hypothetical provider implementations might wrap a
/// vendor SDK, embed an REST client, or read flags from a local file.
///
/// See the [spec](https://openfeature.dev/specification/sections/providers).
#[cfg_attr(feature = "test-util", mockall::automock)]
#[async_trait]
pub trait FeatureProvider: Send + Sync + 'static {
    /// The provider MAY define an initialize function which accepts the global evaluation
    /// context as an argument and performs initialization logic relevant to the provider.
    ///
    /// Note the following rules:
    /// * The provider MUST set its status field/accessor to READY if its initialize function
    /// terminates normally.
    /// * The provider MUST set its status field to ERROR if its initialize function terminates
    /// abnormally.
    /// * The provider SHOULD indicate an error if flag resolution is attempted before the provider
    /// is ready.
    #[allow(unused_variables)]
    async fn initialize(&mut self, context: &EvaluationContext) {}

    /// The provider MAY define a status field/accessor which indicates the readiness of the
    /// provider, with possible values NOT_READY, READY, or ERROR.
    ///
    /// Providers without this field can be assumed to be ready immediately.
    fn status(&self) -> ProviderStatus {
        ProviderStatus::Ready
    }

    /// The provider interface MUST define a metadata member or accessor, containing a name field
    /// or accessor of type string, which identifies the provider implementation.
    fn metadata(&self) -> &ProviderMetadata;

    /// Resolve given `flag_key` as a bool value.
    async fn resolve_bool_value(
        &self,
        flag_key: &str,
        evaluation_context: &EvaluationContext,
    ) -> EvaluationResult<ResolutionDetails<bool>>;

    /// Resolve given `flag_key` as an i64 value.
    async fn resolve_int_value(
        &self,
        flag_key: &str,
        evaluation_context: &EvaluationContext,
    ) -> EvaluationResult<ResolutionDetails<i64>>;

    /// Resolve given `flag_key` as a f64 value.
    async fn resolve_float_value(
        &self,
        flag_key: &str,
        evaluation_context: &EvaluationContext,
    ) -> EvaluationResult<ResolutionDetails<f64>>;

    /// Resolve given `flag_key` as a string value.
    async fn resolve_string_value(
        &self,
        flag_key: &str,
        evaluation_context: &EvaluationContext,
    ) -> EvaluationResult<ResolutionDetails<String>>;

    /// Resolve given `flag_key` as a struct value.
    async fn resolve_struct_value(
        &self,
        flag_key: &str,
        evaluation_context: &EvaluationContext,
    ) -> EvaluationResult<ResolutionDetails<StructValue>>;
}

// ============================================================
//  ProviderMetadata
// ============================================================

/// The metadata of a feature provider.
#[derive(Clone, Default, Debug)]
pub struct ProviderMetadata {
    /// The name of provider.
    pub name: String,
}

impl ProviderMetadata {
    /// Create a new instance out of a string.
    pub fn new<S: Into<String>>(name: S) -> Self {
        Self { name: name.into() }
    }
}
//
// ============================================================
//  ProviderStatus
// ============================================================

/// The status of a feature provider.
#[derive(Default, PartialEq, Eq, Debug)]
pub enum ProviderStatus {
    /// The provider has not been initialized.
    #[default]
    NotReady,

    /// The provider has been initialized, and is able to reliably resolve flag values.
    Ready,

    /// The provider is initialized but is not able to reliably resolve flag values.
    Error,

    /// The provider's cached state is no longer valid and may not be up-to-date with the source of
    /// truth.
    STALE,
}