use std::collections::VecDeque;
use sim_kernel::{Expr, Symbol};
use sim_value::build;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SessionId(pub(crate) String);
impl SessionId {
pub fn from_resource(resource: &Symbol) -> Option<Self> {
(resource.namespace.as_deref() == Some("expr-tree/session"))
.then(|| Self(resource.name.to_string()))
}
pub fn resource(&self) -> Symbol {
Symbol::qualified("expr-tree/session", self.0.clone())
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct WatchId(pub(crate) String);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ExpressionTreeServerLimits {
pub max_sessions: usize,
pub max_idle_ticks: u64,
pub max_watches_per_session: usize,
pub watch_capacity: usize,
pub max_page_entries: usize,
pub max_snapshot_depth: usize,
}
impl Default for ExpressionTreeServerLimits {
fn default() -> Self {
Self {
max_sessions: 128,
max_idle_ticks: 10_000,
max_watches_per_session: 16,
watch_capacity: 128,
max_page_entries: 128,
max_snapshot_depth: 16,
}
}
}
impl ExpressionTreeServerLimits {
pub(crate) fn validate(self) -> bool {
self.max_sessions > 0
&& self.max_idle_ticks > 0
&& self.max_watches_per_session > 0
&& self.watch_capacity > 0
&& self.max_page_entries > 0
&& self.max_snapshot_depth > 0
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ChangeEvent {
pub resource: Symbol,
pub revision: u64,
pub logical_tick: u64,
pub wall_ms: Option<u64>,
pub kind: String,
pub path: Option<String>,
}
impl ChangeEvent {
pub(crate) fn to_expr(&self) -> Expr {
build::map(vec![
("resource", Expr::Symbol(self.resource.clone())),
("revision", build::uint(self.revision)),
("logical-tick", build::uint(self.logical_tick)),
(
"wall-ms",
self.wall_ms.map(build::uint).unwrap_or(Expr::Nil),
),
("kind", build::sym(&self.kind)),
(
"path",
self.path.as_ref().map(build::text).unwrap_or(Expr::Nil),
),
])
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WatchBatch {
pub events: Vec<ChangeEvent>,
pub dropped: u64,
pub cancelled: bool,
}
pub(crate) struct WatchState {
pub(crate) events: VecDeque<ChangeEvent>,
pub(crate) dropped: u64,
pub(crate) cancelled: bool,
}
impl WatchState {
pub(crate) fn new() -> Self {
Self {
events: VecDeque::new(),
dropped: 0,
cancelled: false,
}
}
pub(crate) fn push(&mut self, event: ChangeEvent, capacity: usize) {
if self.cancelled {
return;
}
if self.events.len() == capacity {
self.events.pop_front();
self.dropped = self.dropped.saturating_add(1);
}
self.events.push_back(event);
}
}