browscap_rs/
capabilities.rs

1use crate::mapper::{MAPPER};
2use crate::{
3    BROWSER, BROWSER_MAJOR_VERSION, BROWSER_TYPE, BrowsCapField, Capabilities, DEVICE_TYPE,
4    PLATFORM, PLATFORM_VERSION, capabilities,
5};
6use hashbrown::HashSet;
7use std::cell::{RefCell};
8use std::hash::Hash;
9use std::sync::{Arc, OnceLock};
10use ustr::Ustr;
11
12pub const UNKNOWN_BROWSCAP_VALUE: &'static str = "Unknown";
13
14pub static DEFAULT_CAPABILITIES: OnceLock<Capabilities> = OnceLock::new();
15
16#[derive(Debug)]
17pub struct CapaCache {
18    cache: RefCell<HashSet<Arc<Capabilities>>>,
19}
20
21impl CapaCache {
22    pub fn new() -> CapaCache {
23        CapaCache {
24            cache: RefCell::new(HashSet::new()),
25        }
26    }
27
28    pub fn get_or_insert(&self, capa: Capabilities) -> Arc<Capabilities> {
29        self.cache.borrow_mut().get_or_insert(Arc::new(capa)).clone()
30    }
31}
32
33impl Capabilities {
34    fn new(values: Vec<Ustr>) -> Capabilities {
35        Capabilities { my_values: values }
36    }
37    pub fn get_value(&self, field: &BrowsCapField) -> Option<&str> {
38        let u_str = MAPPER
39            .get()
40            .unwrap()
41            .read()
42            .unwrap()
43            .get_value(&self.my_values, field);
44        return u_str.map(|x| x.as_str());
45    }
46
47    pub fn get_browser(&self) -> Option<&str> {
48        self.get_value(&BROWSER)
49    }
50
51    pub fn get_browser_type(&self) -> Option<&str> {
52        self.get_value(&BROWSER_TYPE)
53    }
54
55    pub fn get_browser_major_version(&self) -> Option<&str> {
56        self.get_value(&BROWSER_MAJOR_VERSION)
57    }
58
59    pub fn get_platform(&self) -> Option<&str> {
60        self.get_value(&PLATFORM)
61    }
62
63    pub fn get_platform_version(&self) -> Option<&str> {
64        self.get_value(&PLATFORM_VERSION)
65    }
66
67    pub fn get_device_type(&self) -> Option<&str> {
68        self.get_value(&DEVICE_TYPE)
69    }
70}
71
72impl Hash for Capabilities {
73    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
74        for value in self.my_values.iter() {
75            value.hash(state);
76        }
77    }
78}
79impl Eq for Capabilities {}
80
81impl PartialEq for Capabilities {
82    fn eq(&self, other: &Self) -> bool {
83        self.my_values == other.my_values
84    }
85}
86
87pub fn init_default_capa<'a>(fields: &Vec<&'static BrowsCapField>) -> &'a Capabilities {
88    DEFAULT_CAPABILITIES.get_or_init(|| {
89        let mut result: Vec<Ustr> = Vec::new();
90        for _i in 0..fields.len() {
91            result.push(Ustr::from(capabilities::UNKNOWN_BROWSCAP_VALUE));
92        }
93        Capabilities::new(result)
94    })
95}
96
97/**
98 * 缓存capabilities
99 */
100pub fn get_capabilities(values: Vec<Ustr>, capa_cache: &CapaCache) -> Arc<Capabilities> {
101    let capabilities: Capabilities = Capabilities::new(values);
102    capa_cache.get_or_insert(capabilities)
103}
104
105pub fn init_wild_card_capa<'a>(fields: &'a Vec<&'static BrowsCapField>) -> Arc<Capabilities> {
106    let mut values = init_default_capa(fields).my_values.clone();
107    let mapper = MAPPER.get().unwrap().read().unwrap();
108    for (index, item) in values.iter_mut().enumerate() {
109        let position_field = mapper.position_field(index);
110        if let Some(field) = position_field {
111            if *field == BROWSER || *field == BROWSER_TYPE {
112                *item = Ustr::from("Default Browser");
113                continue;
114            }
115            if field.is_default {
116                *item = Ustr::from(capabilities::UNKNOWN_BROWSCAP_VALUE);
117            }
118        }
119    }
120    Arc::new(Capabilities::new(values))
121}