1use serde_json::Value;
2use std::collections::{HashMap, HashSet};
3use crate::manifest::Manifest;
4use crate::core::fixed_bits;
5use crate::core::codec;
6use crate::store::Store;
7use crate::load::Load;
8use crate::ports::provided::StateError;
9
10pub struct State<'a> {
13 manifest: Manifest,
14 state_keys: Vec<u16>,
15 state_vals: Vec<Value>,
16 store: Store<'a>,
17 load: Load<'a>,
18 max_recursion: usize,
19 called_keys: HashSet<String>,
20}
21
22impl<'a> State<'a> {
23 pub fn new(manifest_dir: &str) -> Self {
33 Self {
34 manifest: Manifest::new(manifest_dir),
35 state_keys: vec![0],
36 state_vals: vec![Value::Null],
37 store: Store::new(),
38 load: Load::new(),
39 max_recursion: 20,
40 called_keys: HashSet::new(),
41 }
42 }
43
44 pub fn with_in_memory(mut self, client: &'a dyn crate::ports::required::InMemoryClient) -> Self {
45 self.store = self.store.with_in_memory(client);
46 self.load = self.load.with_in_memory(client);
47 self
48 }
49
50 pub fn with_kvs(mut self, client: &'a dyn crate::ports::required::KVSClient) -> Self {
51 self.store = self.store.with_kvs(client);
52 self.load = self.load.with_kvs(client);
53 self
54 }
55
56 pub fn with_db(mut self, client: &'a dyn crate::ports::required::DbClient) -> Self {
57 self.load = self.load.with_db(client);
58 self
59 }
60
61 pub fn with_env(mut self, client: &'a dyn crate::ports::required::EnvClient) -> Self {
62 self.load = self.load.with_env(client);
63 self
64 }
65
66 pub fn with_http(mut self, client: &'a dyn crate::ports::required::HttpClient) -> Self {
67 self.store = self.store.with_http(client);
68 self.load = self.load.with_http(client);
69 self
70 }
71
72 pub fn with_file(mut self, client: impl crate::ports::required::FileClient + 'static) -> Self {
73 self.manifest = self.manifest.with_file(client);
74 self
75 }
76
77
78 fn split_key<'k>(key: &'k str) -> (&'k str, &'k str) {
80 match key.find('.') {
81 Some(pos) => (&key[..pos], &key[pos + 1..]),
82 None => (key, ""),
83 }
84 }
85
86 fn resolve_value(&mut self, value_idx: u16) -> Result<Option<Value>, StateError> {
90 crate::fn_log!("State", "resolve_value", &value_idx.to_string());
91 let vo = match self.manifest.values.get(value_idx as usize).copied() {
92 Some(v) => v,
93 None => return Ok(None),
94 };
95 let is_template = fixed_bits::get(vo[0], fixed_bits::V_OFFSET_IS_TEMPLATE, fixed_bits::V_MASK_IS_TEMPLATE) == 1;
96 let is_path = fixed_bits::get(vo[0], fixed_bits::V_OFFSET_T0_IS_PATH, fixed_bits::V_MASK_IS_PATH) == 1;
97 let dyn_idx = fixed_bits::get(vo[0], fixed_bits::V_OFFSET_T0_DYNAMIC, fixed_bits::V_MASK_DYNAMIC) as u16;
98
99 if is_path && dyn_idx != 0 && !is_template {
100 let path_segments = match self.manifest.path_map.get(dyn_idx as usize) {
101 Some(s) => s.to_vec(),
102 None => return Ok(None),
103 };
104 let path_key: String = path_segments.iter()
105 .filter_map(|&seg_idx| self.manifest.dynamic.get(seg_idx).map(|s| s.to_string()))
106 .collect::<Vec<_>>()
107 .join(".");
108 return self.get(&path_key);
109 }
110
111 Ok(self.resolve_value_to_string(value_idx)?.map(Value::String))
112 }
113
114 fn resolve_value_to_string(&mut self, value_idx: u16) -> Result<Option<String>, StateError> {
116 crate::fn_log!("State", "resolve_value_to_string", &value_idx.to_string());
117 let vo = match self.manifest.values.get(value_idx as usize).copied() {
118 Some(v) => v,
119 None => return Ok(None),
120 };
121
122 let is_template = fixed_bits::get(vo[0], fixed_bits::V_OFFSET_IS_TEMPLATE, fixed_bits::V_MASK_IS_TEMPLATE) == 1;
123
124 const TOKEN_OFFSETS: [(u32, u32); 6] = [
125 (fixed_bits::V_OFFSET_T0_IS_PATH, fixed_bits::V_OFFSET_T0_DYNAMIC),
126 (fixed_bits::V_OFFSET_T1_IS_PATH, fixed_bits::V_OFFSET_T1_DYNAMIC),
127 (fixed_bits::V_OFFSET_T2_IS_PATH, fixed_bits::V_OFFSET_T2_DYNAMIC),
128 (fixed_bits::V_OFFSET_T3_IS_PATH, fixed_bits::V_OFFSET_T3_DYNAMIC),
129 (fixed_bits::V_OFFSET_T4_IS_PATH, fixed_bits::V_OFFSET_T4_DYNAMIC),
130 (fixed_bits::V_OFFSET_T5_IS_PATH, fixed_bits::V_OFFSET_T5_DYNAMIC),
131 ];
132
133 let mut result = String::new();
134
135 for (i, (off_is_path, off_dynamic)) in TOKEN_OFFSETS.iter().enumerate() {
136 let word = if i < 3 { 0 } else { 1 };
137 let is_path = fixed_bits::get(vo[word], *off_is_path, fixed_bits::V_MASK_IS_PATH) == 1;
138 let dyn_idx = fixed_bits::get(vo[word], *off_dynamic, fixed_bits::V_MASK_DYNAMIC) as u16;
139
140 if dyn_idx == 0 {
141 break;
142 }
143
144 if is_path {
145 let path_segments = match self.manifest.path_map.get(dyn_idx as usize) {
146 Some(s) => s.to_vec(),
147 None => return Ok(None),
148 };
149 let path_key: String = path_segments.iter()
150 .filter_map(|&seg_idx| self.manifest.dynamic.get(seg_idx).map(|s| s.to_string()))
151 .collect::<Vec<_>>()
152 .join(".");
153 crate::fn_log!("State", "resolve/get", &path_key);
154 let resolved = self.get(&path_key)?;
155 crate::fn_log!("State", "resolve/got", if resolved.is_some() { "Some" } else { "None" });
156 let resolved = match resolved {
157 Some(v) => v,
158 None => return Ok(None),
159 };
160 let s = match &resolved {
161 Value::String(s) => s.clone(),
162 Value::Number(n) => n.to_string(),
163 Value::Bool(b) => b.to_string(),
164 _ => return Ok(None),
165 };
166 result.push_str(&s);
167 } else {
168 let s = match self.manifest.dynamic.get(dyn_idx) {
169 Some(s) => s.to_string(),
170 None => return Ok(None),
171 };
172 result.push_str(&s);
173 }
174
175 if !is_template {
176 break;
177 }
178 }
179
180 Ok(Some(result))
181 }
182
183 fn build_config(&mut self, meta_idx: u16) -> Result<Option<HashMap<String, Value>>, StateError> {
185 crate::fn_log!("State", "build_config", &meta_idx.to_string());
186 let record = match self.manifest.keys.get(meta_idx as usize).copied() {
187 Some(r) => r,
188 None => return Ok(None),
189 };
190 let child_idx = fixed_bits::get(record, fixed_bits::K_OFFSET_CHILD, fixed_bits::K_MASK_CHILD) as usize;
191 if child_idx == 0 { return Ok(None); }
192 let has_children = fixed_bits::get(record, fixed_bits::K_OFFSET_HAS_CHILDREN, fixed_bits::K_MASK_HAS_CHILDREN);
193 let children = if has_children == 1 {
194 match self.manifest.children_map.get(child_idx) {
195 Some(c) => c.to_vec(),
196 None => return Ok(None),
197 }
198 } else {
199 vec![child_idx as u16]
200 };
201
202 let mut config = HashMap::new();
203
204 for &child_idx in &children {
205 let record = match self.manifest.keys.get(child_idx as usize).copied() {
206 Some(r) => r,
207 None => continue,
208 };
209 let prop = fixed_bits::get(record, fixed_bits::K_OFFSET_PROP, fixed_bits::K_MASK_PROP) as u8;
210 let client = fixed_bits::get(record, fixed_bits::K_OFFSET_CLIENT, fixed_bits::K_MASK_CLIENT) as u8;
211 let is_leaf = fixed_bits::get(record, fixed_bits::K_OFFSET_IS_LEAF, fixed_bits::K_MASK_IS_LEAF) == 1;
212 let value_idx = if is_leaf {
213 fixed_bits::get(record, fixed_bits::K_OFFSET_CHILD, fixed_bits::K_MASK_CHILD) as u16
214 } else { 0 };
215
216 if client != 0 {
217 config.insert("client".to_string(), Value::Number(client.into()));
218 continue;
219 }
220
221 let prop_name = match codec::prop_decode(prop as u64) {
222 Some(name) => name,
223 None => continue,
224 };
225
226 if prop_name == "map" {
227 if let Some(map_val) = self.build_map_config(child_idx) {
228 config.insert("map".to_string(), map_val);
229 }
230 } else if prop_name == "connection" {
231 if value_idx != 0 {
232 if let Some(v) = self.resolve_value(value_idx)? {
233 config.insert("connection".to_string(), v);
234 }
235 }
236 } else if value_idx != 0 {
237 if let Some(s) = self.resolve_value_to_string(value_idx)? {
238 config.insert(prop_name.to_string(), Value::String(s));
239 }
240 }
241 }
242
243 Ok(Some(config))
244 }
245
246 fn build_map_config(&self, map_idx: u16) -> Option<Value> {
248 let record = self.manifest.keys.get(map_idx as usize).copied()?;
249 let child_idx = fixed_bits::get(record, fixed_bits::K_OFFSET_CHILD, fixed_bits::K_MASK_CHILD) as usize;
250 if child_idx == 0 { return Some(Value::Object(serde_json::Map::new())); }
251
252 let has_children = fixed_bits::get(record, fixed_bits::K_OFFSET_HAS_CHILDREN, fixed_bits::K_MASK_HAS_CHILDREN);
253 let children = if has_children == 1 {
254 self.manifest.children_map.get(child_idx)?.to_vec()
255 } else {
256 vec![child_idx as u16]
257 };
258
259 let mut map = serde_json::Map::new();
260 for &c in &children {
261 let child = self.manifest.keys.get(c as usize).copied()?;
262 let dyn_idx = fixed_bits::get(child, fixed_bits::K_OFFSET_DYNAMIC, fixed_bits::K_MASK_DYNAMIC) as u16;
263 let value_idx = fixed_bits::get(child, fixed_bits::K_OFFSET_CHILD, fixed_bits::K_MASK_CHILD) as usize;
264 let is_path = fixed_bits::get(child, fixed_bits::K_OFFSET_IS_PATH, fixed_bits::K_MASK_IS_PATH) == 1;
265
266 let key_str = if is_path {
267 let segs = self.manifest.path_map.get(dyn_idx as usize)?;
268 segs.iter()
269 .filter_map(|&s| self.manifest.dynamic.get(s).map(|x| x.to_string()))
270 .collect::<Vec<_>>()
271 .join(".")
272 } else {
273 self.manifest.dynamic.get(dyn_idx)?.to_string()
274 };
275
276 let val_vo = self.manifest.values.get(value_idx).copied()?;
277 let col_dyn = fixed_bits::get(val_vo[0], fixed_bits::V_OFFSET_T0_DYNAMIC, fixed_bits::V_MASK_DYNAMIC) as u16;
278 let col_str = self.manifest.dynamic.get(col_dyn)?.to_string();
279
280 map.insert(key_str, Value::String(col_str));
281 }
282
283 Some(Value::Object(map))
284 }
285
286 fn find_state_value(&self, key_idx: u16) -> Option<usize> {
288 self.state_keys.iter().skip(1).position(|&k| k == key_idx).map(|p| p + 1)
289 }
290
291 pub fn get(&mut self, key: &str) -> Result<Option<Value>, StateError> {
317 crate::fn_log!("State", "get", key);
318 if self.called_keys.len() >= self.max_recursion {
319 return Err(StateError::RecursionLimitExceeded);
320 }
321 if self.called_keys.contains(&key.to_string()) {
322 return Err(StateError::RecursionLimitExceeded);
323 }
324
325 self.called_keys.insert(key.to_string());
326
327 let (file, path) = Self::split_key(key);
328 let file = file.to_string();
329 let path = path.to_string();
330
331 if let Err(e) = self.manifest.load(&file) {
332 self.called_keys.remove(key);
333 return Err(StateError::ManifestLoadFailed(e.to_string()));
334 }
335
336 let key_idx = match self.manifest.find(&file, &path) {
337 Some(idx) => idx,
338 None => {
339 self.called_keys.remove(key);
340 return Err(StateError::KeyNotFound(key.to_string()));
341 }
342 };
343
344 if let Some(sv_idx) = self.find_state_value(key_idx) {
346 let val = self.state_vals.get(sv_idx).cloned();
347 self.called_keys.remove(key);
348 return Ok(val);
349 }
350
351 let meta = self.manifest.get_meta(&file, &path);
352
353 let has_state_client = meta.load.and_then(|load_idx| {
355 self.manifest.keys.get(load_idx as usize).copied()
356 .map(|r| fixed_bits::get(r, fixed_bits::K_OFFSET_CLIENT, fixed_bits::K_MASK_CLIENT) == fixed_bits::CLIENT_STATE)
357 }).unwrap_or(false);
358
359 if !has_state_client {
360 if let Some(store_idx) = meta.store {
361 match self.build_config(store_idx) {
362 Ok(Some(config)) => {
363 if let Some(value) = self.store.get(&config) {
364 self.state_keys.push(key_idx);
365 self.state_vals.push(value.clone());
366 self.called_keys.remove(key);
367 return Ok(Some(value));
368 }
369 }
370 Ok(None) => {}
371 Err(e) => {
372 self.called_keys.remove(key);
373 return Err(e);
374 }
375 }
376 }
377 }
378
379 let result = if let Some(load_idx) = meta.load {
381 match self.build_config(load_idx) {
382 Ok(Some(mut config)) => {
383 if !config.contains_key("client") {
384 self.called_keys.remove(key);
385 return Ok(None);
386 }
387
388 if let Some(Value::Object(map_obj)) = config.get("map").cloned() {
390 let mut unqualified = serde_json::Map::new();
391 for (qk, v) in map_obj {
392 let field = qk.rfind('.').map_or(qk.as_str(), |p| &qk[p+1..]);
393 unqualified.insert(field.to_string(), v);
394 }
395 config.insert("map".to_string(), Value::Object(unqualified));
396 }
397
398 match self.load.handle(&config) {
399 Ok(loaded) => {
400 if let Some(store_idx) = meta.store {
401 match self.build_config(store_idx) {
402 Ok(Some(store_config)) => {
403 if self.store.set(&store_config, loaded.clone(), None).unwrap_or(false) {
404 self.state_keys.push(key_idx);
405 self.state_vals.push(loaded.clone());
406 }
407 }
408 Ok(None) => {
409 self.state_keys.push(key_idx);
410 self.state_vals.push(loaded.clone());
411 }
412 Err(_) => {
413 }
415 }
416 } else {
417 self.state_keys.push(key_idx);
418 self.state_vals.push(loaded.clone());
419 }
420 Ok(Some(loaded))
421 }
422 Err(e) => Err(StateError::LoadFailed(e)),
423 }
424 }
425 Ok(None) => Ok(None),
426 Err(e) => Err(e),
427 }
428 } else { Ok(None) };
429
430 self.called_keys.remove(key);
431 result
432 }
433
434 pub fn set(&mut self, key: &str, value: Value, ttl: Option<u64>) -> Result<bool, StateError> {
456 crate::fn_log!("State", "set", key);
457 let (file, path) = Self::split_key(key);
458 let file = file.to_string();
459 let path = path.to_string();
460
461 if let Err(e) = self.manifest.load(&file) {
462 return Err(StateError::ManifestLoadFailed(e.to_string()));
463 }
464
465 let key_idx = match self.manifest.find(&file, &path) {
466 Some(idx) => idx,
467 None => return Err(StateError::KeyNotFound(key.to_string())),
468 };
469
470 let meta = self.manifest.get_meta(&file, &path);
471
472 if let Some(store_idx) = meta.store {
473 match self.build_config(store_idx)? {
474 Some(config) => {
475 return match self.store.set(&config, value.clone(), ttl) {
476 Ok(ok) => {
477 if ok {
478 if let Some(sv_idx) = self.find_state_value(key_idx) {
479 self.state_vals[sv_idx] = value;
480 } else {
481 self.state_keys.push(key_idx);
482 self.state_vals.push(value);
483 }
484 }
485 Ok(ok)
486 }
487 Err(e) => Err(StateError::StoreFailed(e)),
488 };
489 }
490 None => {}
491 }
492 }
493 Ok(false)
494 }
495
496 pub fn delete(&mut self, key: &str) -> Result<bool, StateError> {
521 crate::fn_log!("State", "delete", key);
522 let (file, path) = Self::split_key(key);
523 let file = file.to_string();
524 let path = path.to_string();
525
526 if let Err(e) = self.manifest.load(&file) {
527 return Err(StateError::ManifestLoadFailed(e.to_string()));
528 }
529
530 let key_idx = match self.manifest.find(&file, &path) {
531 Some(idx) => idx,
532 None => return Err(StateError::KeyNotFound(key.to_string())),
533 };
534
535 let meta = self.manifest.get_meta(&file, &path);
536
537 if let Some(store_idx) = meta.store {
538 match self.build_config(store_idx)? {
539 Some(config) => {
540 return match self.store.delete(&config) {
541 Ok(ok) => {
542 if ok {
543 if let Some(sv_idx) = self.find_state_value(key_idx) {
544 self.state_keys[sv_idx] = 0;
545 self.state_vals[sv_idx] = Value::Null;
546 }
547 }
548 Ok(ok)
549 }
550 Err(e) => Err(StateError::StoreFailed(e)),
551 };
552 }
553 None => {}
554 }
555 }
556 Ok(false)
557 }
558
559 pub fn exists(&mut self, key: &str) -> Result<bool, StateError> {
584 crate::fn_log!("State", "exists", key);
585 let (file, path) = Self::split_key(key);
586 let file = file.to_string();
587 let path = path.to_string();
588
589 if let Err(e) = self.manifest.load(&file) {
590 return Err(StateError::ManifestLoadFailed(e.to_string()));
591 }
592
593 let key_idx = match self.manifest.find(&file, &path) {
594 Some(idx) => idx,
595 None => return Err(StateError::KeyNotFound(key.to_string())),
596 };
597
598 if let Some(sv_idx) = self.find_state_value(key_idx) {
599 return Ok(!self.state_vals.get(sv_idx).map_or(true, |v| v.is_null()));
600 }
601
602 let meta = self.manifest.get_meta(&file, &path);
603 if let Some(store_idx) = meta.store {
604 if let Some(config) = self.build_config(store_idx)? {
605 return Ok(self.store.get(&config).is_some());
606 }
607 }
608 Ok(false)
609 }
610}
611
612#[cfg(test)]
613mod tests {
614 use super::*;
615 use crate::ports::required::{KVSClient, DbClient, EnvClient, FileClient};
616 use serde_json::Value;
617 use std::collections::HashMap;
618
619 struct StubKVS;
620 impl KVSClient for StubKVS {
621 fn get(&self, _: &str) -> Option<String> { None }
622 fn set(&self, _: &str, _: String, _: Option<u64>) -> bool { false }
623 fn delete(&self, _: &str) -> bool { false }
624 }
625
626 struct StubDb;
627 impl DbClient for StubDb {
628 fn get(&self, _: &Value, _: &str, _: &[&str], _: Option<&str>) -> Option<Vec<HashMap<String, Value>>> { None }
629 fn set(&self, _: &Value, _: &str, _: &HashMap<String, Value>, _: Option<&str>) -> bool { false }
630 fn delete(&self, _: &Value, _: &str, _: Option<&str>) -> bool { false }
631 }
632
633 struct StubEnv;
634 impl EnvClient for StubEnv {
635 fn get(&self, _: &str) -> Option<String> { None }
636 fn set(&self, _: &str, _: String) -> bool { false }
637 fn delete(&self, _: &str) -> bool { false }
638 }
639
640 struct StubFile;
641 impl FileClient for StubFile {
642 fn get(&self, _: &str) -> Option<String> { None }
643 fn set(&self, _: &str, _: String) -> bool { false }
644 fn delete(&self, _: &str) -> bool { false }
645 }
646
647 struct StubHttp;
648 impl crate::ports::required::HttpClient for StubHttp {
649 fn get(&self, _: &str, _: Option<&HashMap<String, String>>) -> Option<Value> { None }
650 fn set(&self, _: &str, _: Value, _: Option<&HashMap<String, String>>) -> bool { false }
651 fn delete(&self, _: &str, _: Option<&HashMap<String, String>>) -> bool { false }
652 }
653
654 #[test]
655 fn test_with_clients_build() {
656 let kvs = StubKVS;
657 let db = StubDb;
658 let env = StubEnv;
659 let http = StubHttp;
660
661 let _ = State::new("./examples/manifest").with_kvs(&kvs);
663 let _ = State::new("./examples/manifest").with_db(&db);
664 let _ = State::new("./examples/manifest").with_env(&env);
665 let _ = State::new("./examples/manifest").with_http(&http);
666 let _ = State::new("./examples/manifest").with_file(StubFile);
667 }
668}