sozu_lib/
features.rs

1use std::{cell::RefCell, collections::HashMap};
2
3thread_local! {
4  pub static FEATURES: RefCell<FeatureFlags> = RefCell::new(FeatureFlags::new());
5}
6
7/// accepting feature flags from env var with the format FEATURES=key;type;value,key;type;value
8/// with type 'b' for boolean, 's' for string, 'i' for i64, value in the expected type
9pub struct FeatureFlags {
10    features: HashMap<String, Feature>,
11}
12
13impl Default for FeatureFlags {
14    fn default() -> Self {
15        Self::new()
16    }
17}
18
19impl FeatureFlags {
20    pub fn new() -> FeatureFlags {
21        let mut features = HashMap::new();
22        if let Ok(val) = std::env::var("FEATURES") {
23            for feature_val in val.split(',') {
24                if let Some((key, f)) = parse_feature(feature_val) {
25                    info!("adding feature flag ({}, {:?})", key, f);
26                    features.insert(key, f);
27                }
28            }
29        }
30
31        FeatureFlags { features }
32    }
33
34    pub fn get(&self, key: &str) -> Option<&Feature> {
35        self.features.get(key)
36    }
37}
38
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub enum Feature {
41    Boolean(bool),
42    String(String),
43    Number(i64),
44}
45
46impl Feature {
47    pub fn is_true(&self) -> bool {
48        self == &Feature::Boolean(true)
49    }
50
51    pub fn is_string(&self, s: &str) -> bool {
52        if let Feature::String(ref s1) = self {
53            s1 == s
54        } else {
55            false
56        }
57    }
58}
59
60fn parse_feature(s: &str) -> Option<(String, Feature)> {
61    let v = s.split(';').collect::<Vec<_>>();
62    if v.len() != 3 {
63        return None;
64    }
65
66    let f = if v[1] == "b" {
67        if let Ok(b) = v[2].parse() {
68            Feature::Boolean(b)
69        } else {
70            return None;
71        }
72    } else if v[1] == "s" {
73        Feature::String(v[2].to_string())
74    } else if v[1] == "i" {
75        if let Ok(i) = v[2].parse() {
76            Feature::Number(i)
77        } else {
78            return None;
79        }
80    } else {
81        return None;
82    };
83
84    Some((v[0].to_string(), f))
85}