statsig_rust/specs_response/
spec_directory.rs1use super::spec_types::Spec;
2use crate::{event_logging::exposable_string::ExposableString, hashing::ahash_str};
3use ahash::HashMap;
4use serde::{Deserialize, Deserializer, Serialize};
5use std::sync::Arc;
6
7#[derive(Debug, PartialEq)]
8pub struct AddressableSpec {
9 pub name: ExposableString,
10 pub spec: Arc<Spec>,
11}
12
13#[derive(Debug, Default, PartialEq)]
14pub struct SpecDirectory {
15 pub specs: HashMap<u64, AddressableSpec>,
16}
17
18impl SpecDirectory {
19 pub fn get(&self, name: &str) -> Option<&AddressableSpec> {
20 let hash = ahash_str(name);
21 self.specs.get(&hash)
22 }
23
24 pub fn keys(&self) -> impl Iterator<Item = &str> {
25 self.specs.values().map(|v| v.name.as_str())
26 }
27
28 pub fn unperformant_keys(&self) -> Vec<String> {
29 self.specs
30 .values()
31 .map(|v| v.name.unperformant_to_string())
32 .collect()
33 }
34
35 pub fn unperformant_keys_entity_filter(&self, entity_type: &str) -> Vec<String> {
36 self.specs
37 .iter()
38 .filter(|(_, v)| v.spec.entity == entity_type)
39 .map(|(_, v)| v.name.unperformant_to_string())
40 .collect()
41 }
42}
43
44impl<'de> Deserialize<'de> for SpecDirectory {
45 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
46 where
47 D: Deserializer<'de>,
48 {
49 let specs = HashMap::<String, Spec>::deserialize(deserializer)?
50 .into_iter()
51 .map(|(k, v)| {
52 let name = ExposableString::from_str_ref(k.as_str());
53 let hash = name.hash_value;
54 let addressable = AddressableSpec {
55 name,
56 spec: Arc::new(v),
57 };
58
59 (hash, addressable)
60 })
61 .collect();
62
63 Ok(SpecDirectory { specs })
64 }
65}
66
67impl Serialize for SpecDirectory {
68 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
69 where
70 S: serde::Serializer,
71 {
72 let map: HashMap<&str, &Spec> = self
73 .specs
74 .values()
75 .map(|v| (v.name.as_str(), v.spec.as_ref()))
76 .collect();
77
78 map.serialize(serializer)
79 }
80}