statsig_rust/specs_adapter/
specs_adapter_trait.rs

1use crate::statsig_err::StatsigErr;
2use crate::StatsigRuntime;
3use async_trait::async_trait;
4use serde::Deserialize;
5use serde::Serialize;
6use std::fmt::{self, Debug};
7use std::sync::Arc;
8use tokio::time::Duration;
9
10#[repr(u8)]
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub enum SpecsSource {
13    Uninitialized = 0,
14    NoValues,
15    Error,
16    Loading,
17    Network,
18    Bootstrap,
19    Adapter(String),
20}
21
22impl fmt::Display for SpecsSource {
23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24        let s = match self {
25            SpecsSource::Adapter(name) => {
26                let type_name = format!("Adapter{name}");
27                type_name
28            }
29            SpecsSource::Uninitialized => "Uninitialized".to_string(),
30            SpecsSource::NoValues => "NoValues".to_string(),
31            SpecsSource::Error => "Error".to_string(),
32            SpecsSource::Loading => "Loading".to_string(),
33            SpecsSource::Network => "Network".to_string(),
34            SpecsSource::Bootstrap => "Bootstrap".to_string(),
35        };
36        write!(f, "{s}")
37    }
38}
39
40#[async_trait]
41pub trait SpecsAdapter: Send + Sync {
42    fn initialize(&self, listener: Arc<dyn SpecsUpdateListener>);
43
44    async fn start(
45        self: Arc<Self>,
46        statsig_runtime: &Arc<StatsigRuntime>,
47    ) -> Result<(), StatsigErr>;
48
49    async fn shutdown(
50        &self,
51        timeout: Duration,
52        statsig_runtime: &Arc<StatsigRuntime>,
53    ) -> Result<(), StatsigErr>;
54
55    async fn schedule_background_sync(
56        self: Arc<Self>,
57        statsig_runtime: &Arc<StatsigRuntime>,
58    ) -> Result<(), StatsigErr>;
59
60    fn get_type_name(&self) -> String;
61}
62
63pub struct SpecsUpdate {
64    pub data: String,
65    pub source: SpecsSource,
66    pub received_at: u64,
67}
68
69#[repr(C)]
70#[derive(Serialize, Deserialize, Debug)]
71pub struct SpecsInfo {
72    pub lcut: Option<u64>,
73    pub checksum: Option<String>,
74    pub source: SpecsSource,
75}
76
77impl SpecsInfo {
78    #[must_use]
79    pub fn empty() -> Self {
80        Self {
81            lcut: None,
82            checksum: None,
83            source: SpecsSource::NoValues,
84        }
85    }
86
87    #[must_use]
88    pub fn error() -> Self {
89        Self {
90            lcut: None,
91            checksum: None,
92            source: SpecsSource::Error,
93        }
94    }
95}
96
97pub trait SpecsUpdateListener: Send + Sync {
98    fn did_receive_specs_update(&self, update: SpecsUpdate) -> Result<(), StatsigErr>;
99
100    fn get_current_specs_info(&self) -> SpecsInfo;
101}
102
103impl fmt::Debug for dyn SpecsAdapter {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        write!(f, "{}", self.get_type_name())
106    }
107}