spec.rs
1 use candid::{CandidType, Deserialize}; 2 use shared::item::spec::SpecValue; 3 use std::collections::BTreeMap; 4 5 type SpecCategoryKey = u8; 6 #[derive(CandidType, Deserialize, Debug, Clone)] 7 pub struct SpecCategory { 8 name: String, 9 label_map: BTreeMap<SpecLabelKey, SpecLabel>, 10 } 11 12 impl SpecCategory { 13 pub fn builder(name: &str) -> SpecCategoryBuilder { 14 SpecCategoryBuilder::new(name) 15 } 16 17 pub fn get_label(&self, key: SpecLabelKey) -> Option<&SpecLabel> { 18 self.label_map.get(&key) 19 } 20 } 21 22 pub struct SpecCategoryBuilder { 23 name: String, 24 label_map: BTreeMap<SpecLabelKey, SpecLabel>, 25 } 26 27 impl SpecCategoryBuilder { 28 pub fn new(name: &str) -> Self { 29 Self { 30 name: name.to_string(), 31 label_map: BTreeMap::new(), 32 } 33 } 34 35 pub fn label(mut self, key: SpecLabelKey, label: SpecLabel) -> Self { 36 self.label_map.insert(key, label); 37 self 38 } 39 40 pub fn build(self) -> SpecCategory { 41 SpecCategory { 42 name: self.name, 43 label_map: self.label_map, 44 } 45 } 46 } 47 48 type SpecLabelKey = u8; 49 #[derive(CandidType, Deserialize, Debug, Clone)] 50 pub struct SpecLabel { 51 name: String, 52 value_map: BTreeMap<SpecValueKey, SpecValue>, 53 } 54 55 impl SpecLabel { 56 pub fn builder(name: &str) -> SpecLabelBuilder { 57 SpecLabelBuilder::new(name) 58 } 59 60 pub fn get_value(&self, key: &SpecValueKey) -> Option<&shared::item::spec::SpecValue> { 61 self.value_map.get(key) 62 } 63 } 64 65 pub struct SpecLabelBuilder { 66 name: String, 67 value_map: BTreeMap<SpecValueKey, SpecValue>, 68 } 69 70 impl SpecLabelBuilder { 71 pub fn new(name: &str) -> Self { 72 Self { 73 name: name.to_string(), 74 value_map: BTreeMap::new(), 75 } 76 } 77 78 pub fn value(mut self, key: SpecValueKey, value: Vec<&str>) -> Self { 79 let value = value.iter().map(|v| v.to_string()).collect(); 80 81 self.value_map.insert(key, value); 82 self 83 } 84 85 pub fn build(self) -> SpecLabel { 86 SpecLabel { 87 name: self.name, 88 value_map: self.value_map, 89 } 90 } 91 } 92 93 type SpecValueKey = u8; 94 95 pub type SpecIndexKey = u8; 96 97 #[derive(CandidType, Deserialize, Debug, Clone)] 98 pub struct SpecKey { 99 category_key: SpecCategoryKey, 100 label_vec: Vec<SpecKeyLabel>, 101 } 102 103 impl SpecKey { 104 pub fn builder(category_key: SpecCategoryKey) -> SpecKeyBuilder { 105 SpecKeyBuilder::new(category_key) 106 } 107 } 108 109 pub struct SpecKeyBuilder { 110 category_key: SpecCategoryKey, 111 label_vec: Vec<SpecKeyLabel>, 112 } 113 114 impl SpecKeyBuilder { 115 pub fn new(category_key: SpecCategoryKey) -> Self { 116 Self { 117 category_key, 118 label_vec: Vec::new(), 119 } 120 } 121 122 pub fn label(mut self, label_key: SpecLabelKey, value_key: SpecValueKey) -> Self { 123 self.label_vec.push(SpecKeyLabel::new(label_key, value_key)); 124 self 125 } 126 127 pub fn build(self) -> SpecKey { 128 SpecKey { 129 category_key: self.category_key, 130 label_vec: self.label_vec, 131 } 132 } 133 } 134 135 #[derive(CandidType, Deserialize, Debug, Clone)] 136 pub struct SpecKeyLabel { 137 label_key: SpecLabelKey, 138 value_key: SpecValueKey, 139 } 140 141 impl SpecKeyLabel { 142 pub fn new(label_key: SpecLabelKey, value_key: SpecValueKey) -> Self { 143 Self { 144 label_key, 145 value_key, 146 } 147 } 148 } 149 150 #[derive(CandidType, Deserialize, Debug, Clone)] 151 pub struct ItemSpecsV1 { 152 // Actual data of specs 153 pub map: BTreeMap<SpecCategoryKey, SpecCategory>, 154 // Mapping of combination of specs 155 pub index_map: BTreeMap<SpecIndexKey, SpecKey>, 156 } 157 158 impl ItemSpecsV1 { 159 pub fn builder() -> ItemSpecsV1Builder { 160 ItemSpecsV1Builder::default() 161 } 162 163 pub fn get_specs(&self, keys: &Vec<SpecIndexKey>) -> Option<shared::item::spec::SpecResponse> { 164 let mut result = Vec::new(); 165 166 for key in keys { 167 let mut label_vec = Vec::new(); 168 let spec_key = self.get_spec_key(key)?; 169 170 let category = self.get_category(spec_key.category_key)?; 171 for spec_key_label in &spec_key.label_vec { 172 let label = category.get_label(spec_key_label.label_key)?; 173 let value = label.get_value(&spec_key_label.value_key)?; 174 label_vec.push(shared::item::spec::SpecResponseLabel { 175 label_name: label.name.clone(), 176 value: value.clone(), 177 }); 178 } 179 180 result.push(shared::item::spec::SpecResponseCategory { 181 category_name: category.name.clone(), 182 label_vec, 183 }); 184 } 185 186 Some(result) 187 } 188 189 fn get_spec_key(&self, key: &SpecIndexKey) -> Option<&SpecKey> { 190 self.index_map.get(key) 191 } 192 193 fn get_category(&self, key: SpecCategoryKey) -> Option<&SpecCategory> { 194 self.map.get(&key) 195 } 196 } 197 198 #[derive(Default)] 199 pub struct ItemSpecsV1Builder { 200 pub map: BTreeMap<SpecCategoryKey, SpecCategory>, 201 pub index_map: BTreeMap<SpecIndexKey, SpecKey>, 202 } 203 204 impl ItemSpecsV1Builder { 205 /// Add a new spec category to the builder. 206 /// This will be used to store the actual data of the specs. 207 /// 208 /// The key is used to reference the category. 209 /// 210 /// The upper is the actual data of the category. 211 /// It contains the name of the category and the mapping of the labels. 212 pub fn spec(mut self, key: SpecCategoryKey, upper: SpecCategory) -> Self { 213 self.map.insert(key, upper); 214 self 215 } 216 217 /// Add a new spec index to the builder. 218 /// This will be used to store the mapping of the combination of specs. 219 /// 220 /// The key is used to reference the index. 221 /// 222 /// The index is the actual data of the index. 223 /// It contains the category key and the mapping of the labels. 224 pub fn index(mut self, key: SpecIndexKey, index: SpecKey) -> Self { 225 self.index_map.insert(key, index); 226 self 227 } 228 229 pub fn build(self) -> ItemSpecsV1 { 230 ItemSpecsV1 { 231 map: self.map, 232 index_map: self.index_map, 233 } 234 } 235 }