crb_superagent/
molting.rs

1use 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}