1use std::collections::BTreeMap;
5use std::ops::{Deref, DerefMut};
6use std::sync::{Arc, Mutex};
7
8use super::{AsyncEngineContext, AsyncEngineContextProvider, Data};
9use crate::engine::AsyncEngineController;
10use async_trait::async_trait;
11
12use super::registry::Registry;
13
14pub struct Context<T: Data> {
15 current: T,
16 controller: Arc<Controller>, registry: Registry,
18 stages: Vec<String>,
19 metadata: BTreeMap<String, String>,
20}
21
22impl<T: Send + Sync + 'static> Context<T> {
23 pub fn new(current: T) -> Self {
25 Context {
26 current,
27 controller: Arc::new(Controller::default()),
28 registry: Registry::new(),
29 stages: Vec::new(),
30 metadata: BTreeMap::new(),
31 }
32 }
33
34 pub fn rejoin<U: Send + Sync + 'static>(current: T, context: Context<U>) -> Self {
35 Context {
36 current,
37 controller: context.controller,
38 registry: context.registry,
39 stages: context.stages,
40 metadata: context.metadata,
41 }
42 }
43
44 pub fn with_controller(current: T, controller: Controller) -> Self {
45 Context {
46 current,
47 controller: Arc::new(controller),
48 registry: Registry::new(),
49 stages: Vec::new(),
50 metadata: BTreeMap::new(),
51 }
52 }
53
54 pub fn with_id_and_metadata(
55 current: T,
56 id: String,
57 metadata: BTreeMap<String, String>,
58 ) -> Self {
59 Context {
60 current,
61 controller: Arc::new(Controller::new(id)),
62 registry: Registry::new(),
63 stages: Vec::new(),
64 metadata,
65 }
66 }
67
68 pub fn id(&self) -> &str {
70 self.controller.id()
71 }
72
73 pub fn content(&self) -> &T {
75 &self.current
76 }
77
78 pub fn controller(&self) -> &Controller {
79 &self.controller
80 }
81
82 pub fn metadata(&self) -> &BTreeMap<String, String> {
83 &self.metadata
84 }
85
86 pub fn metadata_mut(&mut self) -> &mut BTreeMap<String, String> {
87 &mut self.metadata
88 }
89
90 pub fn set_metadata(&mut self, metadata: BTreeMap<String, String>) {
91 self.metadata = metadata;
92 }
93
94 pub fn insert_metadata<K: Into<String>, V: Into<String>>(&mut self, key: K, value: V) {
95 self.metadata.insert(key.into(), value.into());
96 }
97
98 pub fn insert<K: ToString, U: Send + Sync + 'static>(&mut self, key: K, value: U) {
100 self.registry.insert_shared(key, value);
101 }
102
103 pub fn insert_unique<K: ToString, U: Send + Sync + 'static>(&mut self, key: K, value: U) {
105 self.registry.insert_unique(key, value);
106 }
107
108 pub fn get<V: Send + Sync + 'static>(&self, key: &str) -> Result<Arc<V>, String> {
110 self.registry.get_shared(key)
111 }
112
113 pub fn get_optional<V: Send + Sync + 'static>(
115 &self,
116 key: &str,
117 ) -> Result<Option<Arc<V>>, String> {
118 self.registry.get_shared_optional(key)
119 }
120
121 pub fn clone_unique<V: Clone + Send + Sync + 'static>(&self, key: &str) -> Result<V, String> {
123 self.registry.clone_unique(key)
124 }
125
126 pub fn take_unique<V: Send + Sync + 'static>(&mut self, key: &str) -> Result<V, String> {
128 self.registry.take_unique(key)
129 }
130
131 pub fn transfer<U: Send + Sync + 'static>(self, new_current: U) -> (T, Context<U>) {
134 (
135 self.current,
136 Context {
137 current: new_current,
138 controller: self.controller,
139 registry: self.registry,
140 stages: self.stages,
141 metadata: self.metadata,
142 },
143 )
144 }
145
146 pub fn into_parts(self) -> (T, Context<()>) {
148 self.transfer(())
149 }
150
151 pub fn stages(&self) -> &Vec<String> {
152 &self.stages
153 }
154
155 pub fn add_stage(&mut self, stage: &str) {
156 self.stages.push(stage.to_string());
157 }
158
159 pub fn map<U: Send + Sync + 'static, F>(self, f: F) -> Context<U>
161 where
162 F: FnOnce(T) -> U,
163 {
164 let (current, temp_context) = self.transfer(());
166
167 let new_current = f(current);
169
170 temp_context.transfer(new_current).1
172 }
173
174 pub fn try_map<U, F, E>(self, f: F) -> Result<Context<U>, E>
175 where
176 F: FnOnce(T) -> Result<U, E>,
177 U: Send + Sync + 'static,
178 {
179 let (current, temp_context) = self.transfer(());
181
182 let new_current = f(current)?;
184
185 Ok(temp_context.transfer(new_current).1)
187 }
188}
189
190impl<T: Data> std::fmt::Debug for Context<T> {
191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192 f.debug_struct("Context")
193 .field("id", &self.controller.id())
194 .finish()
195 }
196}
197
198impl<T: Data> Deref for Context<T> {
200 type Target = T;
201
202 fn deref(&self) -> &Self::Target {
203 &self.current
204 }
205}
206
207impl<T: Data> DerefMut for Context<T> {
209 fn deref_mut(&mut self) -> &mut Self::Target {
210 &mut self.current
211 }
212}
213
214impl<T> From<T> for Context<T>
216where
217 T: Send + Sync + 'static,
218{
219 fn from(current: T) -> Self {
220 Context::new(current)
221 }
222}
223
224pub trait IntoContext<U: Data> {
226 fn into_context(self) -> Context<U>;
227}
228
229impl<T, U> IntoContext<U> for Context<T>
231where
232 T: Send + Sync + 'static + Into<U>,
233 U: Send + Sync + 'static,
234{
235 fn into_context(self) -> Context<U> {
236 self.map(|current| current.into())
237 }
238}
239
240impl<T: Data> AsyncEngineContextProvider for Context<T> {
241 fn context(&self) -> Arc<dyn AsyncEngineContext> {
242 self.controller.clone()
243 }
244}
245
246#[derive(Debug, Clone)]
247pub struct StreamContext {
248 controller: Arc<Controller>,
249 registry: Arc<Registry>,
250 stages: Vec<String>,
251 metadata: BTreeMap<String, String>,
252}
253
254impl StreamContext {
255 fn new(
256 controller: Arc<Controller>,
257 registry: Registry,
258 metadata: BTreeMap<String, String>,
259 ) -> Self {
260 StreamContext {
261 controller,
262 registry: Arc::new(registry),
263 stages: Vec::new(),
264 metadata,
265 }
266 }
267
268 pub fn get<V: Send + Sync + 'static>(&self, key: &str) -> Result<Arc<V>, String> {
270 self.registry.get_shared(key)
271 }
272
273 pub fn clone_unique<V: Clone + Send + Sync + 'static>(&self, key: &str) -> Result<V, String> {
275 self.registry.clone_unique(key)
276 }
277
278 pub fn registry(&self) -> Arc<Registry> {
279 self.registry.clone()
280 }
281
282 pub fn stages(&self) -> &Vec<String> {
283 &self.stages
284 }
285
286 pub fn add_stage(&mut self, stage: &str) {
287 self.stages.push(stage.to_string());
288 }
289
290 pub fn metadata(&self) -> &BTreeMap<String, String> {
291 &self.metadata
292 }
293}
294
295#[async_trait]
296impl AsyncEngineContext for StreamContext {
297 fn id(&self) -> &str {
298 self.controller.id()
299 }
300
301 fn stop(&self) {
302 self.controller.stop();
303 }
304
305 fn kill(&self) {
306 self.controller.kill();
307 }
308
309 fn stop_generating(&self) {
310 self.controller.stop_generating();
311 }
312
313 fn is_stopped(&self) -> bool {
314 self.controller.is_stopped()
315 }
316
317 fn is_killed(&self) -> bool {
318 self.controller.is_killed()
319 }
320
321 async fn stopped(&self) {
322 self.controller.stopped().await
323 }
324
325 async fn killed(&self) {
326 self.controller.killed().await
327 }
328
329 fn link_child(&self, child: Arc<dyn AsyncEngineContext>) {
330 self.controller.link_child(child);
331 }
332}
333
334impl AsyncEngineContextProvider for StreamContext {
335 fn context(&self) -> Arc<dyn AsyncEngineContext> {
336 self.controller.clone()
337 }
338}
339
340impl<T: Send + Sync + 'static> From<Context<T>> for StreamContext {
341 fn from(value: Context<T>) -> Self {
342 StreamContext::new(value.controller, value.registry, value.metadata)
343 }
344}
345
346use tokio::sync::watch::{Receiver, Sender, channel};
349
350#[derive(Debug, Eq, PartialEq)]
351enum State {
352 Live,
353 Stopped,
354 Killed,
355}
356
357#[derive(Debug)]
359pub struct Controller {
360 id: String,
361 tx: Sender<State>,
362 rx: Receiver<State>,
363 child_context: Mutex<Vec<Arc<dyn AsyncEngineContext>>>,
364}
365
366impl Controller {
367 pub fn new(id: String) -> Self {
368 let (tx, rx) = channel(State::Live);
369 Self {
370 id,
371 tx,
372 rx,
373 child_context: Mutex::new(Vec::new()),
374 }
375 }
376
377 pub fn id(&self) -> &str {
378 &self.id
379 }
380}
381
382impl Default for Controller {
383 fn default() -> Self {
384 Self::new(uuid::Uuid::new_v4().to_string())
385 }
386}
387
388impl AsyncEngineController for Controller {}
389
390#[async_trait]
391impl AsyncEngineContext for Controller {
392 fn id(&self) -> &str {
393 &self.id
394 }
395
396 fn is_stopped(&self) -> bool {
397 *self.rx.borrow() != State::Live
398 }
399
400 fn is_killed(&self) -> bool {
401 *self.rx.borrow() == State::Killed
402 }
403
404 async fn stopped(&self) {
405 let mut rx = self.rx.clone();
406 loop {
407 if *rx.borrow_and_update() != State::Live || rx.changed().await.is_err() {
408 return;
409 }
410 }
411 }
412
413 async fn killed(&self) {
414 let mut rx = self.rx.clone();
415 loop {
416 if *rx.borrow_and_update() == State::Killed || rx.changed().await.is_err() {
417 return;
418 }
419 }
420 }
421
422 fn stop_generating(&self) {
423 let children = self
425 .child_context
426 .lock()
427 .expect("Failed to lock child context")
428 .iter()
429 .cloned()
430 .collect::<Vec<_>>();
431 for child in children {
432 child.stop_generating();
433 }
434
435 let _ = self.tx.send(State::Stopped);
436 }
437
438 fn stop(&self) {
439 let children = self
441 .child_context
442 .lock()
443 .expect("Failed to lock child context")
444 .iter()
445 .cloned()
446 .collect::<Vec<_>>();
447 for child in children {
448 child.stop();
449 }
450
451 let _ = self.tx.send(State::Stopped);
452 }
453
454 fn kill(&self) {
455 let children = self
457 .child_context
458 .lock()
459 .expect("Failed to lock child context")
460 .iter()
461 .cloned()
462 .collect::<Vec<_>>();
463 for child in children {
464 child.kill();
465 }
466
467 let _ = self.tx.send(State::Killed);
468 }
469
470 fn link_child(&self, child: Arc<dyn AsyncEngineContext>) {
471 self.child_context
472 .lock()
473 .expect("Failed to lock child context")
474 .push(child);
475 }
476}
477
478#[cfg(test)]
479mod tests {
480 use super::*;
481
482 #[derive(Debug, Clone)]
483 struct Input {
484 value: String,
485 }
486
487 #[derive(Debug, Clone)]
488 struct Processed {
489 length: usize,
490 }
491
492 #[derive(Debug, Clone)]
493 struct Final {
494 message: String,
495 }
496
497 impl From<Input> for Processed {
498 fn from(input: Input) -> Self {
499 Processed {
500 length: input.value.len(),
501 }
502 }
503 }
504
505 impl From<Processed> for Final {
506 fn from(processed: Processed) -> Self {
507 Final {
508 message: format!("Processed length: {}", processed.length),
509 }
510 }
511 }
512
513 #[test]
514 fn test_insert_and_get() {
515 let mut ctx = Context::new(Input {
516 value: "Hello".to_string(),
517 });
518
519 ctx.insert("key1", 42);
520 ctx.insert("key2", "some data".to_string());
521
522 assert_eq!(*ctx.get::<i32>("key1").unwrap(), 42);
523 assert_eq!(*ctx.get::<String>("key2").unwrap(), "some data");
524 assert!(ctx.get::<f64>("key1").is_err()); }
526
527 #[test]
528 fn test_metadata_preserved_across_transfers() {
529 let mut ctx = Context::new(Input {
530 value: "Hello".to_string(),
531 });
532 ctx.insert_metadata("tenant", "alpha");
533
534 let (_, transferred) = ctx.transfer(Processed { length: 5 });
535 assert_eq!(
536 transferred.metadata().get("tenant").map(String::as_str),
537 Some("alpha")
538 );
539 }
540
541 #[test]
542 fn test_with_id_and_metadata_constructor() {
543 let metadata = BTreeMap::from([("tenant".to_string(), "alpha".to_string())]);
544 let ctx = Context::with_id_and_metadata(
545 Input {
546 value: "Hello".to_string(),
547 },
548 "request-123".to_string(),
549 metadata,
550 );
551
552 assert_eq!(ctx.id(), "request-123");
553 assert_eq!(
554 ctx.metadata().get("tenant").map(String::as_str),
555 Some("alpha")
556 );
557 }
558
559 #[test]
560 fn test_metadata_preserved_across_rejoin() {
561 let mut ctx = Context::new(Input {
562 value: "Hello".to_string(),
563 });
564 ctx.insert_metadata("tenant", "alpha");
565
566 let (input, empty_ctx) = ctx.into_parts();
567 let rejoined = Context::rejoin(input, empty_ctx);
568 assert_eq!(
569 rejoined.metadata().get("tenant").map(String::as_str),
570 Some("alpha")
571 );
572 }
573
574 #[test]
575 fn test_metadata_preserved_in_stream_context() {
576 let mut ctx = Context::new(Input {
577 value: "Hello".to_string(),
578 });
579 ctx.insert_metadata("tenant", "alpha");
580
581 let stream_ctx = StreamContext::from(ctx);
582 assert_eq!(
583 stream_ctx.metadata().get("tenant").map(String::as_str),
584 Some("alpha")
585 );
586 }
587
588 #[test]
589 fn test_transfer() {
590 let ctx = Context::new(Input {
591 value: "Hello".to_string(),
592 });
593
594 let (input, ctx) = ctx.transfer(Processed { length: 5 });
595
596 assert_eq!(input.value, "Hello");
597 assert_eq!(ctx.length, 5);
598 }
599
600 #[test]
601 fn test_map() {
602 let ctx = Context::new(Input {
603 value: "Hello".to_string(),
604 });
605
606 let ctx: Context<Processed> = ctx.map(|input| input.into());
607 let ctx: Context<Final> = ctx.map(|processed| processed.into());
608
609 assert_eq!(ctx.current.message, "Processed length: 5");
610 }
611
612 #[test]
613 fn test_into_context() {
614 let ctx = Context::new(Input {
615 value: "Hello".to_string(),
616 });
617
618 let ctx: Context<Processed> = ctx.into_context();
619 let ctx: Context<Final> = ctx.into_context();
620
621 assert_eq!(ctx.current.message, "Processed length: 5");
622 }
623}