1use super::*;
2use crate::callback::Callback;
3use crate::html::ImplicitClone;
4use crate::scheduler::{scheduler, Runnable, Shared};
5use std::cell::RefCell;
6use std::fmt;
7use std::rc::Rc;
8
9pub(crate) trait Responder<AGN: Agent> {
11 fn respond(&self, id: HandlerId, output: AGN::Output);
13}
14
15pub struct AgentLink<AGN: Agent> {
17 scope: AgentScope<AGN>,
18 responder: Rc<dyn Responder<AGN>>,
19}
20
21impl<AGN: Agent> AgentLink<AGN> {
22 pub(crate) fn connect<T>(scope: &AgentScope<AGN>, responder: T) -> Self
24 where
25 T: Responder<AGN> + 'static,
26 {
27 AgentLink {
28 scope: scope.clone(),
29 responder: Rc::new(responder),
30 }
31 }
32
33 pub fn respond(&self, id: HandlerId, output: AGN::Output) {
35 self.responder.respond(id, output);
36 }
37
38 pub fn send_message<T>(&self, msg: T)
40 where
41 T: Into<AGN::Message>,
42 {
43 self.scope.send(AgentLifecycleEvent::Message(msg.into()));
44 }
45
46 pub fn send_input<T>(&self, input: T)
48 where
49 T: Into<AGN::Input>,
50 {
51 let handler_id = HandlerId::new(0, false);
52 self.scope
53 .send(AgentLifecycleEvent::Input(input.into(), handler_id));
54 }
55
56 pub fn callback<F, IN, M>(&self, function: F) -> Callback<IN>
58 where
59 M: Into<AGN::Message>,
60 F: Fn(IN) -> M + 'static,
61 {
62 let scope = self.scope.clone();
63 let closure = move |input| {
64 let output = function(input).into();
65 scope.send(AgentLifecycleEvent::Message(output));
66 };
67 closure.into()
68 }
69}
70
71impl<AGN: Agent> fmt::Debug for AgentLink<AGN> {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 f.write_str("AgentLink<_>")
74 }
75}
76
77impl<AGN: Agent> Clone for AgentLink<AGN> {
78 fn clone(&self) -> Self {
79 AgentLink {
80 scope: self.scope.clone(),
81 responder: self.responder.clone(),
82 }
83 }
84}
85pub(crate) struct AgentScope<AGN: Agent> {
87 state: Shared<AgentState<AGN>>,
88}
89
90impl<AGN: Agent> fmt::Debug for AgentScope<AGN> {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 f.write_str("AgentScope<_>")
93 }
94}
95
96impl<AGN: Agent> Clone for AgentScope<AGN> {
97 fn clone(&self) -> Self {
98 AgentScope {
99 state: self.state.clone(),
100 }
101 }
102}
103
104impl<AGN: Agent> AgentScope<AGN> {
105 pub fn new() -> Self {
107 let state = Rc::new(RefCell::new(AgentState::new()));
108 AgentScope { state }
109 }
110
111 pub fn send(&self, event: AgentLifecycleEvent<AGN>) {
113 let runnable: Box<dyn Runnable> = Box::new(AgentRunnable {
114 state: self.state.clone(),
115 event,
116 });
117 scheduler().push(runnable);
118 }
119}
120
121impl<AGN: Agent> Default for AgentScope<AGN> {
122 fn default() -> Self {
123 Self::new()
124 }
125}
126
127impl<AGN: Agent> ImplicitClone for AgentScope<AGN> {}
128
129struct AgentState<AGN> {
130 agent: Option<AGN>,
131 destroyed: bool,
133}
134
135impl<AGN> AgentState<AGN> {
136 fn new() -> Self {
137 AgentState {
138 agent: None,
139 destroyed: false,
140 }
141 }
142}
143
144#[derive(Debug)]
146pub(crate) enum AgentLifecycleEvent<AGN: Agent> {
147 Create(AgentLink<AGN>),
149 Message(AGN::Message),
151 Connected(HandlerId),
153 Input(AGN::Input, HandlerId),
155 Disconnected(HandlerId),
157 Destroy,
159}
160
161struct AgentRunnable<AGN: Agent> {
162 state: Shared<AgentState<AGN>>,
163 event: AgentLifecycleEvent<AGN>,
164}
165
166impl<AGN> Runnable for AgentRunnable<AGN>
167where
168 AGN: Agent,
169{
170 fn run(self: Box<Self>) {
171 let mut state = self.state.borrow_mut();
172 if state.destroyed {
173 return;
174 }
175 match self.event {
176 AgentLifecycleEvent::Create(link) => {
177 state.agent = Some(AGN::create(link));
178 }
179 AgentLifecycleEvent::Message(msg) => {
180 state
181 .agent
182 .as_mut()
183 .expect("agent was not created to process messages")
184 .update(msg);
185 }
186 AgentLifecycleEvent::Connected(id) => {
187 state
188 .agent
189 .as_mut()
190 .expect("agent was not created to send a connected message")
191 .connected(id);
192 }
193 AgentLifecycleEvent::Input(inp, id) => {
194 state
195 .agent
196 .as_mut()
197 .expect("agent was not created to process inputs")
198 .handle_input(inp, id);
199 }
200 AgentLifecycleEvent::Disconnected(id) => {
201 state
202 .agent
203 .as_mut()
204 .expect("agent was not created to send a disconnected message")
205 .disconnected(id);
206 }
207 AgentLifecycleEvent::Destroy => {
208 let mut agent = state
209 .agent
210 .take()
211 .expect("trying to destroy not existent agent");
212 agent.destroy();
213 }
214 }
215 }
216}