sim_lib_expr_tree/
handle.rs1use std::{
2 collections::BTreeMap,
3 sync::{
4 Arc, Mutex,
5 atomic::{AtomicU64, Ordering},
6 },
7};
8
9use sim_kernel::{Cx, HandleSeed, Object, ObjectCompat, Result};
10
11use crate::runtime::TreeState;
12
13const MAX_STORAGE_NAME_BYTES: usize = 256;
14
15#[derive(Clone)]
21pub struct TreeHandle {
22 pub(crate) state: Arc<Mutex<TreeState>>,
23}
24
25impl TreeHandle {
26 fn new(state: Arc<Mutex<TreeState>>) -> Self {
27 Self { state }
28 }
29}
30
31impl Object for TreeHandle {
32 fn display(&self, _cx: &mut Cx) -> Result<String> {
33 let state = self
34 .state
35 .lock()
36 .map_err(|_| sim_kernel::Error::Eval("expression-tree state poisoned".to_owned()))?;
37 Ok(format!("#<expr-tree {}>", state.storage_name()))
38 }
39
40 fn as_any(&self) -> &dyn std::any::Any {
41 self
42 }
43}
44
45impl ObjectCompat for TreeHandle {}
46
47pub(crate) struct TreeRuntime {
48 stores: Mutex<BTreeMap<String, Arc<Mutex<TreeState>>>>,
49 next_handle_seed: Arc<AtomicU64>,
50}
51
52impl TreeRuntime {
53 pub(crate) fn new(first_handle_seed: HandleSeed) -> Self {
54 Self {
55 stores: Mutex::new(BTreeMap::new()),
56 next_handle_seed: Arc::new(AtomicU64::new(first_handle_seed.0)),
57 }
58 }
59
60 pub(crate) fn open(
61 &self,
62 cx: &Cx,
63 storage_name: &str,
64 ) -> std::result::Result<TreeHandle, String> {
65 if storage_name.is_empty() || storage_name.len() > MAX_STORAGE_NAME_BYTES {
66 return Err(format!(
67 "storage name must contain 1..={MAX_STORAGE_NAME_BYTES} bytes"
68 ));
69 }
70 let mut stores = self
71 .stores
72 .lock()
73 .map_err(|_| "expression-tree storage registry poisoned".to_owned())?;
74 let state = match stores.get(storage_name) {
75 Some(state) => Arc::clone(state),
76 None => {
77 let state = Arc::new(Mutex::new(TreeState::new(
78 cx,
79 storage_name.to_owned(),
80 Arc::clone(&self.next_handle_seed),
81 )?));
82 stores.insert(storage_name.to_owned(), Arc::clone(&state));
83 state
84 }
85 };
86 Ok(TreeHandle::new(state))
87 }
88}
89
90pub(crate) fn next_handle_seed(sequence: &AtomicU64) -> HandleSeed {
91 let seed = sequence
92 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |seed| {
93 seed.checked_add(1)
94 })
95 .expect("expression-tree handle seed space exhausted");
96 HandleSeed::new(seed)
97}