1use std::sync::Arc;
2
3use sim_kernel::{Cx, Error, EvalFabric, EvalReply, ReadPolicy, Result, Symbol};
4use sim_lib_stream_core::{ClockDomain, LatencyClass, StreamEndpoint, StreamEndpointKind};
5
6use crate::{
7 Coroutine, FrameKind, ServerAddress, ServerFrame, decode_frame_payload,
8 eval_request_from_frame, server_frame_from_reply,
9};
10
11use super::core::{
12 EvalSite, Site, SiteKind, eval_site_clock_domain, eval_site_endpoint_kind,
13 eval_site_latency_class, reply_codec_for_frame, site_endpoint_id,
14};
15use super::pipeline::{enforce_trigger_eval_policy, eval_request_from_trigger_frame};
16
17#[derive(Clone)]
19pub struct LocalEvalSite {
20 address: ServerAddress,
21 codecs: Vec<Symbol>,
22}
23
24impl LocalEvalSite {
25 pub fn new(address: ServerAddress, codecs: Vec<Symbol>) -> Self {
27 Self { address, codecs }
28 }
29}
30
31impl EvalSite for LocalEvalSite {
32 fn site_kind(&self) -> &'static str {
33 "local"
34 }
35
36 fn address(&self) -> &ServerAddress {
37 &self.address
38 }
39
40 fn codecs(&self) -> &[Symbol] {
41 &self.codecs
42 }
43
44 fn answer(&self, cx: &mut Cx, frame: ServerFrame) -> Result<ServerFrame> {
45 match frame.kind {
46 FrameKind::Request => {
47 let consistency = frame.envelope.consistency;
48 let reply_codec = reply_codec_for_frame(self, &frame);
49 let request = eval_request_from_frame(cx, &frame)?;
50 let reply = realize_locally(cx, request)?;
51 server_frame_from_reply(cx, &reply_codec, reply, consistency)
52 }
53 FrameKind::Trigger { .. } => {
54 realize_trigger_locally(cx, &frame)?;
55 Ok(frame)
56 }
57 FrameKind::Notify => {
58 realize_notify_locally(cx, &frame)?;
59 Ok(frame)
60 }
61 _ => Err(Error::Eval(format!(
62 "local eval site cannot answer frame kind {}",
63 frame.kind.as_symbol()
64 ))),
65 }
66 }
67
68 fn as_any(&self) -> &dyn std::any::Any {
69 self
70 }
71}
72
73impl StreamEndpoint for LocalEvalSite {
74 fn endpoint_id(&self) -> Symbol {
75 site_endpoint_id(SiteKind::Local, &self.address)
76 }
77
78 fn endpoint_kind(&self) -> StreamEndpointKind {
79 eval_site_endpoint_kind()
80 }
81
82 fn clock_domain(&self) -> ClockDomain {
83 eval_site_clock_domain()
84 }
85
86 fn latency_class(&self) -> LatencyClass {
87 eval_site_latency_class()
88 }
89}
90
91impl Site for LocalEvalSite {
92 fn kind(&self) -> SiteKind {
93 SiteKind::Local
94 }
95}
96
97#[derive(Clone)]
99pub struct FabricEvalSite {
100 kind: &'static str,
101 address: ServerAddress,
102 codecs: Vec<Symbol>,
103 fabric: Arc<dyn EvalFabric>,
104}
105
106impl FabricEvalSite {
107 pub fn new(
110 kind: &'static str,
111 address: ServerAddress,
112 codecs: Vec<Symbol>,
113 fabric: Arc<dyn EvalFabric>,
114 ) -> Self {
115 Self {
116 kind,
117 address,
118 codecs,
119 fabric,
120 }
121 }
122}
123
124impl EvalSite for FabricEvalSite {
125 fn site_kind(&self) -> &'static str {
126 self.kind
127 }
128
129 fn address(&self) -> &ServerAddress {
130 &self.address
131 }
132
133 fn codecs(&self) -> &[Symbol] {
134 &self.codecs
135 }
136
137 fn answer(&self, cx: &mut Cx, frame: ServerFrame) -> Result<ServerFrame> {
138 match frame.kind {
139 FrameKind::Request => {
140 let consistency = frame.envelope.consistency;
141 let reply_codec = reply_codec_for_frame(self, &frame);
142 let request = eval_request_from_frame(cx, &frame)?;
143 let reply = self.fabric.realize(cx, request)?;
144 server_frame_from_reply(cx, &reply_codec, reply, consistency)
145 }
146 FrameKind::Trigger { .. } => {
147 let request = eval_request_from_trigger_frame(cx, &frame)?;
148 let _ = self.fabric.realize(cx, request)?;
149 Ok(frame)
150 }
151 FrameKind::StreamStart | FrameKind::StreamChunk | FrameKind::StreamEnd => Ok(frame),
152 _ => Err(Error::Eval(format!(
153 "fabric eval site cannot answer frame kind {}",
154 frame.kind.as_symbol()
155 ))),
156 }
157 }
158
159 fn as_eval_fabric(&self) -> Option<&dyn EvalFabric> {
160 Some(self.fabric.as_ref())
161 }
162
163 fn as_any(&self) -> &dyn std::any::Any {
164 self
165 }
166}
167
168impl StreamEndpoint for FabricEvalSite {
169 fn endpoint_id(&self) -> Symbol {
170 site_endpoint_id(SiteKind::Fabric, &self.address)
171 }
172
173 fn endpoint_kind(&self) -> StreamEndpointKind {
174 eval_site_endpoint_kind()
175 }
176
177 fn clock_domain(&self) -> ClockDomain {
178 eval_site_clock_domain()
179 }
180
181 fn latency_class(&self) -> LatencyClass {
182 eval_site_latency_class()
183 }
184}
185
186impl Site for FabricEvalSite {
187 fn kind(&self) -> SiteKind {
188 SiteKind::Fabric
189 }
190}
191
192#[derive(Clone)]
194pub struct CoroutineEvalSite {
195 address: ServerAddress,
196 codecs: Vec<Symbol>,
197 coroutine: Arc<Coroutine>,
198}
199
200impl CoroutineEvalSite {
201 pub fn new(address: ServerAddress, codecs: Vec<Symbol>, coroutine: Arc<Coroutine>) -> Self {
204 Self {
205 address,
206 codecs,
207 coroutine,
208 }
209 }
210
211 pub fn coroutine(&self) -> &Arc<Coroutine> {
213 &self.coroutine
214 }
215}
216
217impl EvalSite for CoroutineEvalSite {
218 fn site_kind(&self) -> &'static str {
219 "coroutine"
220 }
221
222 fn address(&self) -> &ServerAddress {
223 &self.address
224 }
225
226 fn codecs(&self) -> &[Symbol] {
227 &self.codecs
228 }
229
230 fn answer(&self, cx: &mut Cx, frame: ServerFrame) -> Result<ServerFrame> {
231 match frame.kind {
232 FrameKind::Request => {
233 let consistency = frame.envelope.consistency;
234 let reply_codec = reply_codec_for_frame(self, &frame);
235 let request = eval_request_from_frame(cx, &frame)?;
236 let input = cx.factory().expr(request.expr)?;
237 let reply = self.coroutine.resume(cx, input)?;
238 let diagnostics = cx.take_diagnostics();
239 server_frame_from_reply(
240 cx,
241 &reply_codec,
242 EvalReply {
243 value: reply,
244 diagnostics,
245 trace: None,
246 },
247 consistency,
248 )
249 }
250 FrameKind::Trigger { .. } => {
251 let expr = frame.decode_expr(cx, ReadPolicy::default())?;
252 enforce_trigger_eval_policy(cx, &expr)?;
253 let input = cx.factory().expr(expr)?;
254 let _ = self.coroutine.resume(cx, input)?;
255 Ok(frame)
256 }
257 FrameKind::Notify => {
258 let expr = decode_frame_payload(
259 cx,
260 &frame.codec,
261 &frame.payload,
262 ReadPolicy::default(),
263 Default::default(),
264 )?;
265 let input = cx.factory().expr(expr)?;
266 let _ = self.coroutine.resume(cx, input)?;
267 Ok(frame)
268 }
269 _ => Err(Error::Eval(format!(
270 "coroutine eval site cannot answer frame kind {}",
271 frame.kind.as_symbol()
272 ))),
273 }
274 }
275
276 fn as_any(&self) -> &dyn std::any::Any {
277 self
278 }
279}
280
281impl StreamEndpoint for CoroutineEvalSite {
282 fn endpoint_id(&self) -> Symbol {
283 site_endpoint_id(SiteKind::Coroutine, &self.address)
284 }
285
286 fn endpoint_kind(&self) -> StreamEndpointKind {
287 eval_site_endpoint_kind()
288 }
289
290 fn clock_domain(&self) -> ClockDomain {
291 eval_site_clock_domain()
292 }
293
294 fn latency_class(&self) -> LatencyClass {
295 eval_site_latency_class()
296 }
297}
298
299impl Site for CoroutineEvalSite {
300 fn kind(&self) -> SiteKind {
301 SiteKind::Coroutine
302 }
303}
304
305fn realize_locally(cx: &mut Cx, request: sim_kernel::EvalRequest) -> Result<EvalReply> {
306 for capability in &request.required_capabilities {
307 cx.require(capability)?;
308 }
309 let value = cx.eval_expr(request.expr)?;
310 if let Some(shape) = &request.result_shape {
311 let Some(shape_object) = shape.object().as_shape() else {
312 return Err(Error::TypeMismatch {
313 expected: "shape",
314 found: "non-shape",
315 });
316 };
317 let matched = shape_object.check_value(cx, value.clone())?;
318 if !matched.accepted {
319 return Err(Error::WrongShape {
320 expected: shape_object.id().unwrap_or(sim_kernel::ShapeId(0)),
321 diagnostics: matched.diagnostics,
322 });
323 }
324 }
325 Ok(EvalReply {
326 value,
327 diagnostics: cx.take_diagnostics(),
328 trace: request
329 .trace
330 .then(|| cx.factory().symbol(Symbol::new("local")).ok())
331 .flatten(),
332 })
333}
334
335fn realize_notify_locally(cx: &mut Cx, frame: &ServerFrame) -> Result<()> {
336 for capability in &frame.envelope.required_capabilities {
337 cx.require(capability)?;
338 }
339 let expr = decode_frame_payload(
340 cx,
341 &frame.codec,
342 &frame.payload,
343 ReadPolicy::default(),
344 Default::default(),
345 )?;
346 cx.eval_expr(expr)?;
347 Ok(())
348}
349
350fn realize_trigger_locally(cx: &mut Cx, frame: &ServerFrame) -> Result<()> {
351 for capability in &frame.envelope.required_capabilities {
352 cx.require(capability)?;
353 }
354 let expr = frame.decode_expr(cx, ReadPolicy::default())?;
355 enforce_trigger_eval_policy(cx, &expr)?;
356 cx.eval_expr(expr)?;
357 Ok(())
358}