firebase_rs_sdk/analytics/
gtag.rs

1//! Minimal gtag bootstrapper used to mirror the Firebase Analytics JS SDK's initialization flow.
2//!
3//! The Rust port does not attempt to inject script tags automatically in non-wasm targets, but
4//! the helper keeps track of the desired data layer and configuration so WASM consumers can hook
5//! into the same lifecycle.
6
7use std::collections::BTreeMap;
8use std::sync::{Arc, Mutex};
9
10use std::sync::LazyLock;
11
12#[derive(Clone, Debug, Default, PartialEq, Eq)]
13pub struct GtagState {
14    pub data_layer_name: String,
15    pub measurement_id: Option<String>,
16    pub consent_settings: Option<BTreeMap<String, String>>,
17    pub default_event_parameters: BTreeMap<String, String>,
18    pub config: BTreeMap<String, String>,
19    pub send_page_view: Option<bool>,
20}
21
22#[derive(Debug, Default)]
23pub struct GtagRegistry {
24    state: Mutex<GtagState>,
25}
26
27impl GtagRegistry {
28    pub fn new() -> Self {
29        Self {
30            state: Mutex::new(GtagState {
31                data_layer_name: "dataLayer".to_string(),
32                ..Default::default()
33            }),
34        }
35    }
36
37    pub fn set_data_layer_name(&self, data_layer: impl Into<String>) {
38        self.state.lock().unwrap().data_layer_name = data_layer.into();
39    }
40
41    pub fn set_measurement_id(&self, measurement_id: Option<String>) {
42        self.state.lock().unwrap().measurement_id = measurement_id;
43    }
44
45    pub fn set_consent_defaults(&self, consent: Option<BTreeMap<String, String>>) {
46        self.state.lock().unwrap().consent_settings = consent;
47    }
48
49    pub fn set_default_event_parameters(&self, params: BTreeMap<String, String>) {
50        self.state.lock().unwrap().default_event_parameters = params;
51    }
52
53    pub fn set_config(&self, config: BTreeMap<String, String>) {
54        self.state.lock().unwrap().config = config;
55    }
56
57    pub fn set_send_page_view(&self, value: Option<bool>) {
58        self.state.lock().unwrap().send_page_view = value;
59    }
60
61    pub fn snapshot(&self) -> GtagState {
62        self.state.lock().unwrap().clone()
63    }
64
65    pub fn reset(&self) {
66        *self.state.lock().unwrap() = GtagState {
67            data_layer_name: "dataLayer".to_string(),
68            ..Default::default()
69        };
70    }
71}
72
73#[derive(Clone, Debug)]
74pub struct GlobalGtagRegistry(Arc<GtagRegistry>);
75
76impl GlobalGtagRegistry {
77    pub fn shared() -> Self {
78        static INSTANCE: LazyLock<Arc<GtagRegistry>> =
79            LazyLock::new(|| Arc::new(GtagRegistry::new()));
80        Self(INSTANCE.clone())
81    }
82
83    pub fn inner(&self) -> &GtagRegistry {
84        &self.0
85    }
86}