Skip to main content

sim_lib_expr_tree_server/
site.rs

1//! Standard `EvalSite`, `EvalFabric`, object, and loadable library surfaces.
2
3use std::{any::Any, sync::Arc, time::Duration};
4
5use sim_kernel::{
6    AbiVersion, ClassRef, Cx, DefaultFactory, Dependency, Error, EvalFabric, EvalReply,
7    EvalRequest, Export, Factory, Lib, LibManifest, LibTarget, Linker, Object, ObjectCompat,
8    Result, Symbol, Value, Version,
9};
10use sim_lib_server::{
11    EvalSite, FrameKind, ServerAddress, ServerFrame, eval_request_from_frame,
12    server_frame_from_reply,
13};
14
15use crate::ExpressionTreeServer;
16
17/// Stable library symbol for the expression-tree server.
18pub fn expr_tree_server_lib_symbol() -> Symbol {
19    Symbol::qualified("lib", "expr-tree-server")
20}
21
22/// Stable placement symbol exported by the expression-tree server library.
23pub fn expr_tree_server_site_symbol() -> Symbol {
24    Symbol::new("site/sim-lib-expr-tree-server")
25}
26
27impl EvalFabric for ExpressionTreeServer {
28    fn realize(&self, cx: &mut Cx, request: EvalRequest) -> Result<EvalReply> {
29        self.realize_request(cx, request)
30    }
31}
32
33impl EvalSite for ExpressionTreeServer {
34    fn site_kind(&self) -> &'static str {
35        "expression-tree"
36    }
37
38    fn address(&self) -> &ServerAddress {
39        self.address()
40    }
41
42    fn codecs(&self) -> &[Symbol] {
43        self.codecs()
44    }
45
46    fn answer(&self, cx: &mut Cx, frame: ServerFrame) -> Result<ServerFrame> {
47        if frame.kind != FrameKind::Request {
48            return Err(Error::Eval(format!(
49                "expression-tree site cannot answer frame kind {}",
50                frame.kind.as_symbol()
51            )));
52        }
53        let correlation = frame.msg_id;
54        let consistency = frame.envelope.consistency;
55        let reply_codec = frame
56            .envelope
57            .reply_codec_hint
58            .clone()
59            .filter(|codec| self.codecs().contains(codec))
60            .unwrap_or_else(|| frame.codec.clone());
61        let request = eval_request_from_frame(cx, &frame)?;
62        let reply = self.realize(cx, request)?;
63        let mut frame = server_frame_from_reply(cx, &reply_codec, reply, consistency)?;
64        frame.correlate = correlation;
65        Ok(frame)
66    }
67
68    fn answer_with_timeout(
69        &self,
70        cx: &mut Cx,
71        frame: ServerFrame,
72        timeout: Option<Duration>,
73    ) -> Result<ServerFrame> {
74        if timeout.is_some_and(|timeout| timeout.is_zero()) {
75            return Err(Error::HostError(
76                "expression-tree server request deadline elapsed".to_owned(),
77            ));
78        }
79        self.answer(cx, frame)
80    }
81
82    fn as_eval_fabric(&self) -> Option<&dyn EvalFabric> {
83        Some(self)
84    }
85
86    fn as_any(&self) -> &dyn Any {
87        self
88    }
89}
90
91impl Object for ExpressionTreeServer {
92    fn display(&self, _cx: &mut Cx) -> Result<String> {
93        Ok(format!(
94            "#<expression-tree-server {}>",
95            expr_tree_server_site_symbol()
96        ))
97    }
98
99    fn as_any(&self) -> &dyn Any {
100        self
101    }
102}
103
104impl ObjectCompat for ExpressionTreeServer {
105    fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
106        if let Some(class) = cx
107            .registry()
108            .class_by_symbol(&Symbol::qualified("core", "EvalFabric"))
109        {
110            return Ok(class.clone());
111        }
112        DefaultFactory.class_stub(
113            sim_kernel::CORE_EVAL_REQUEST_CLASS_ID,
114            Symbol::qualified("core", "EvalFabric"),
115        )
116    }
117
118    fn as_eval_fabric(&self) -> Option<&dyn EvalFabric> {
119        Some(self)
120    }
121
122    fn as_table(&self, cx: &mut Cx) -> Result<Value> {
123        cx.factory().table(vec![
124            (
125                Symbol::new("site"),
126                cx.factory().symbol(expr_tree_server_site_symbol())?,
127            ),
128            (
129                Symbol::new("max-sessions"),
130                cx.factory()
131                    .string(self.limits().max_sessions.to_string())?,
132            ),
133            (
134                Symbol::new("max-idle-ticks"),
135                cx.factory()
136                    .string(self.limits().max_idle_ticks.to_string())?,
137            ),
138        ])
139    }
140}
141
142/// Loadable library exporting one authoritative expression-tree site.
143#[derive(Clone)]
144pub struct ExpressionTreeServerLib {
145    server: Arc<ExpressionTreeServer>,
146}
147
148impl ExpressionTreeServerLib {
149    /// Builds a loadable site around an explicitly configured server.
150    pub fn new(server: Arc<ExpressionTreeServer>) -> Self {
151        Self { server }
152    }
153}
154
155impl Default for ExpressionTreeServerLib {
156    fn default() -> Self {
157        Self::new(Arc::new(ExpressionTreeServer::local()))
158    }
159}
160
161impl Lib for ExpressionTreeServerLib {
162    fn manifest(&self) -> LibManifest {
163        LibManifest {
164            id: expr_tree_server_lib_symbol(),
165            version: Version(env!("CARGO_PKG_VERSION").to_owned()),
166            abi: AbiVersion { major: 0, minor: 1 },
167            target: LibTarget::HostRegistered,
168            requires: vec![Dependency {
169                id: sim_lib_expr_tree::expr_tree_lib_symbol(),
170                minimum_version: None,
171            }],
172            capabilities: Vec::new(),
173            exports: vec![Export::Site {
174                symbol: expr_tree_server_site_symbol(),
175                runtime_id: None,
176            }],
177        }
178    }
179
180    fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
181        linker.site_value(
182            expr_tree_server_site_symbol(),
183            DefaultFactory.opaque(self.server.clone())?,
184        )?;
185        Ok(())
186    }
187}
188
189/// Installs the expression-tree server library exactly once.
190pub fn install_expr_tree_server_lib(cx: &mut Cx) -> Result<()> {
191    if cx.registry().lib(&expr_tree_server_lib_symbol()).is_none() {
192        cx.load_lib(&ExpressionTreeServerLib::default())?;
193    }
194    Ok(())
195}