sim_lib_expr_tree_server/
model.rs1use std::collections::VecDeque;
4
5use sim_kernel::{Expr, Symbol};
6use sim_value::build;
7
8#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
10pub struct SessionId(pub(crate) String);
11
12impl SessionId {
13 pub fn from_resource(resource: &Symbol) -> Option<Self> {
15 (resource.namespace.as_deref() == Some("expr-tree/session"))
16 .then(|| Self(resource.name.to_string()))
17 }
18
19 pub fn resource(&self) -> Symbol {
21 Symbol::qualified("expr-tree/session", self.0.clone())
22 }
23}
24
25#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
27pub struct WatchId(pub(crate) String);
28
29#[derive(Clone, Copy, Debug, Eq, PartialEq)]
31pub struct ExpressionTreeServerLimits {
32 pub max_sessions: usize,
34 pub max_idle_ticks: u64,
36 pub max_watches_per_session: usize,
38 pub watch_capacity: usize,
40 pub max_page_entries: usize,
42 pub max_snapshot_depth: usize,
44}
45
46impl Default for ExpressionTreeServerLimits {
47 fn default() -> Self {
48 Self {
49 max_sessions: 128,
50 max_idle_ticks: 10_000,
51 max_watches_per_session: 16,
52 watch_capacity: 128,
53 max_page_entries: 128,
54 max_snapshot_depth: 16,
55 }
56 }
57}
58
59impl ExpressionTreeServerLimits {
60 pub(crate) fn validate(self) -> bool {
61 self.max_sessions > 0
62 && self.max_idle_ticks > 0
63 && self.max_watches_per_session > 0
64 && self.watch_capacity > 0
65 && self.max_page_entries > 0
66 && self.max_snapshot_depth > 0
67 }
68}
69
70#[derive(Clone, Debug, Eq, PartialEq)]
72pub struct ChangeEvent {
73 pub resource: Symbol,
75 pub revision: u64,
77 pub logical_tick: u64,
79 pub wall_ms: Option<u64>,
81 pub kind: String,
83 pub path: Option<String>,
85}
86
87impl ChangeEvent {
88 pub(crate) fn to_expr(&self) -> Expr {
89 build::map(vec![
90 ("resource", Expr::Symbol(self.resource.clone())),
91 ("revision", build::uint(self.revision)),
92 ("logical-tick", build::uint(self.logical_tick)),
93 (
94 "wall-ms",
95 self.wall_ms.map(build::uint).unwrap_or(Expr::Nil),
96 ),
97 ("kind", build::sym(&self.kind)),
98 (
99 "path",
100 self.path.as_ref().map(build::text).unwrap_or(Expr::Nil),
101 ),
102 ])
103 }
104}
105
106#[derive(Clone, Debug, Eq, PartialEq)]
108pub struct WatchBatch {
109 pub events: Vec<ChangeEvent>,
111 pub dropped: u64,
113 pub cancelled: bool,
115}
116
117pub(crate) struct WatchState {
118 pub(crate) events: VecDeque<ChangeEvent>,
119 pub(crate) dropped: u64,
120 pub(crate) cancelled: bool,
121}
122
123impl WatchState {
124 pub(crate) fn new() -> Self {
125 Self {
126 events: VecDeque::new(),
127 dropped: 0,
128 cancelled: false,
129 }
130 }
131
132 pub(crate) fn push(&mut self, event: ChangeEvent, capacity: usize) {
133 if self.cancelled {
134 return;
135 }
136 if self.events.len() == capacity {
137 self.events.pop_front();
138 self.dropped = self.dropped.saturating_add(1);
139 }
140 self.events.push_back(event);
141 }
142}