crb_superagent/
molting.rs1use async_trait::async_trait;
2use crb_agent::performers::{ConsumptionReason, Next, StatePerformer, Transition};
3use crb_agent::{Address, Agent, AgentContext, AgentSession, Context, Envelope, RunAgent};
4use crb_runtime::{Controller, Interruptor, ManagedContext, ReachableContext, Runtime, Task};
5use std::marker::PhantomData;
6
7pub trait NextExt<A> {
8 fn molt<T>() -> Self
9 where
10 A: MoltTo<T>,
11 T: Agent<Context = MoltingSession<T>>;
12}
13
14impl<A> NextExt<A> for Next<A>
15where
16 A: Agent<Context = MoltingSession<A>>,
17{
18 fn molt<T>() -> Self
19 where
20 A: MoltTo<T>,
21 T: Agent<Context = MoltingSession<T>>,
22 {
23 Self::new(MoltPerformer::<T> { _type: PhantomData })
24 }
25}
26
27pub trait MoltTo<T>: Sized {
28 fn molt(self) -> Option<T> {
29 None
30 }
31}
32
33pub struct MoltPerformer<T> {
34 _type: PhantomData<T>,
35}
36
37#[async_trait]
38impl<A, T> StatePerformer<A> for MoltPerformer<T>
39where
40 A: Agent<Context = MoltingSession<A>>,
41 A: MoltTo<T>,
42 T: Agent<Context = MoltingSession<T>>,
43{
44 async fn perform(&mut self, agent: A, session: &mut Context<A>) -> Transition<A> {
45 let next_agent = agent.molt();
46 if let Some(next_agent) = next_agent {
47 let next_runtime = RunAgent::new(next_agent);
48 session.next_runtime = Some(Box::new(next_runtime));
49 }
50 let reason = ConsumptionReason::Transformed;
51 Transition::Consume { reason }
52 }
53}
54
55pub struct MoltingSession<A: Agent> {
56 pub session: AgentSession<A>,
57 pub next_runtime: Option<Box<dyn MoltingRuntime>>,
58}
59
60impl<A: Agent> Default for MoltingSession<A> {
61 fn default() -> Self {
62 Self {
63 session: AgentSession::default(),
64 next_runtime: None,
65 }
66 }
67}
68
69impl<A: Agent> ReachableContext for MoltingSession<A> {
70 type Address = Address<A>;
71
72 fn address(&self) -> &Self::Address {
73 self.session.address()
74 }
75}
76
77impl<A> ManagedContext for MoltingSession<A>
78where
79 A: Agent,
80{
81 fn is_alive(&self) -> bool {
82 self.session.is_alive()
83 }
84
85 fn shutdown(&mut self) {
86 self.session.shutdown();
87 }
88
89 fn stop(&mut self) {
90 self.session.stop();
91 }
92}
93
94#[async_trait]
95impl<A: Agent> AgentContext<A> for MoltingSession<A> {
96 fn session(&mut self) -> &mut AgentSession<A> {
97 &mut self.session
98 }
99
100 async fn next_envelope(&mut self) -> Option<Envelope<A>> {
101 self.session.next_envelope().await
102 }
103}
104
105pub struct MoltAgent {
106 current_runtime: Option<Box<dyn MoltingRuntime>>,
107 controller: Controller,
108}
109
110impl MoltAgent {
111 pub fn new<A>(agent: A) -> Self
112 where
113 A: Agent<Context = MoltingSession<A>>,
114 {
115 let runtime = RunAgent::new(agent);
116 Self {
117 current_runtime: Some(Box::new(runtime)),
118 controller: Controller::default(),
119 }
120 }
121}
122
123impl Task for MoltAgent {}
124
125#[async_trait]
126impl Runtime for MoltAgent {
127 fn get_interruptor(&mut self) -> Box<dyn Interruptor> {
128 Box::new(self.controller.stopper.clone())
129 }
130
131 async fn routine(&mut self) {
132 while let Some(mut runtime) = self.current_runtime.take() {
133 runtime.routine().await;
134 let next_runtime = runtime.do_molting();
135 self.current_runtime = next_runtime;
136 }
137 }
138}
139
140pub trait MoltingRuntime: Runtime {
141 fn do_molting(self: Box<Self>) -> Option<Box<dyn MoltingRuntime>>;
142}
143
144impl<A> MoltingRuntime for RunAgent<A>
145where
146 A: Agent<Context = MoltingSession<A>>,
147{
148 fn do_molting(mut self: Box<Self>) -> Option<Box<dyn MoltingRuntime>> {
149 self.context.next_runtime.take()
150 }
151}