1use std::collections::HashSet;
3use std::rc::Rc;
4
5use yew::{
6 agent::{Agent, AgentLink, Context, Dispatcher, HandlerId},
7 prelude::*,
8};
9
10use crate::handler::{HandlerLink, Reduction, ReductionOnce, StateHandler};
11
12pub enum ServiceRequest<H>
14where
15 H: StateHandler,
16{
17 Apply(Reduction<H::Model>),
19 ApplyOnce(ReductionOnce<H::Model>),
21 Subscribe,
23}
24
25pub enum ServiceResponse<H>
27where
28 H: StateHandler,
29{
30 State(Rc<H::Model>),
32 Link(HandlerLink<H>),
34}
35
36pub enum ServiceInput<H>
39where
40 H: StateHandler,
41{
42 Service(ServiceRequest<H>),
43 Handler(H::Input),
44}
45
46pub enum ServiceOutput<H>
49where
50 H: StateHandler,
51{
52 Service(ServiceResponse<H>),
53 Handler(H::Output),
54}
55
56pub struct StateService<HANDLER, SCOPE = HANDLER>
59where
60 HANDLER: StateHandler + 'static,
61 SCOPE: 'static,
62{
63 handler: HANDLER,
64 subscriptions: HashSet<HandlerId>,
65 link: AgentLink<StateService<HANDLER, SCOPE>>,
66 #[allow(dead_code)]
67 self_dispatcher: Dispatcher<Self>,
68}
69
70impl<HANDLER, SCOPE> Agent for StateService<HANDLER, SCOPE>
71where
72 HANDLER: StateHandler + 'static,
73 SCOPE: 'static,
74{
75 type Message = HANDLER::Message;
76 type Reach = Context<Self>;
77 type Input = ServiceInput<HANDLER>;
78 type Output = ServiceOutput<HANDLER>;
79
80 fn create(link: AgentLink<Self>) -> Self {
81 Self {
82 handler: <HANDLER as StateHandler>::new(HandlerLink::new(link.clone())),
83 subscriptions: Default::default(),
84 self_dispatcher: Self::dispatcher(),
85 link,
86 }
87 }
88
89 fn update(&mut self, msg: Self::Message) {
90 let changed = self.handler.update(msg);
91 if changed {
92 self.handler.changed();
93 self.notify_subscribers();
94 }
95 }
96
97 fn handle_input(&mut self, msg: Self::Input, who: HandlerId) {
98 match msg {
99 ServiceInput::Service(msg) => match msg {
100 ServiceRequest::Apply(reduce) => {
101 reduce(Rc::make_mut(self.handler.state()));
102 self.handler.changed();
103 }
104 ServiceRequest::ApplyOnce(reduce) => {
105 reduce(Rc::make_mut(self.handler.state()));
106 self.handler.changed();
107 }
108 ServiceRequest::Subscribe => {
109 self.subscriptions.insert(who);
111 let state = Rc::clone(self.handler.state());
113 self.link
114 .respond(who, ServiceOutput::Service(ServiceResponse::State(state)));
115 self.link.respond(
117 who,
118 ServiceOutput::Service(ServiceResponse::Link(HandlerLink::new(
119 self.link.clone(),
120 ))),
121 );
122 }
123 },
124 ServiceInput::Handler(msg) => {
125 let changed = self.handler.handle_input(msg, who);
126 if changed {
127 self.handler.changed();
128 self.notify_subscribers();
129 }
130 }
131 }
132
133 self.notify_subscribers();
134 }
135
136 fn disconnected(&mut self, who: HandlerId) {
137 self.subscriptions.remove(&who);
138 }
139}
140
141impl<HANDLER, SCOPE> StateService<HANDLER, SCOPE>
142where
143 HANDLER: StateHandler + 'static,
144 SCOPE: 'static,
145{
146 fn notify_subscribers(&mut self) {
147 let state = self.handler.state();
148 for who in self.subscriptions.iter().cloned() {
149 self.link.respond(
150 who,
151 ServiceOutput::Service(ServiceResponse::State(Rc::clone(state))),
152 );
153 }
154 }
155}
156
157pub struct ServiceBridge<H, SCOPE = H>
163where
164 H: StateHandler + 'static,
165 SCOPE: 'static,
166{
167 bridge: Box<dyn Bridge<StateService<H, SCOPE>>>,
168}
169
170impl<H, SCOPE> ServiceBridge<H, SCOPE>
171where
172 H: StateHandler + 'static,
173{
174 pub fn new(callback: Callback<ServiceOutput<H>>) -> Self {
176 let mut bridge = StateService::bridge(callback);
177 bridge.send(ServiceInput::Service(ServiceRequest::Subscribe));
178
179 Self { bridge }
180 }
181
182 pub fn send_service(&mut self, msg: ServiceRequest<H>) {
184 self.bridge.send(ServiceInput::Service(msg));
185 }
186
187 pub fn send_handler(&mut self, msg: H::Input) {
189 self.bridge.send(ServiceInput::Handler(msg));
190 }
191}
192
193impl<H> From<ServiceRequest<H>> for ServiceInput<H>
194where
195 H: StateHandler,
196{
197 fn from(msg: ServiceRequest<H>) -> Self {
198 ServiceInput::Service(msg)
199 }
200}
201
202impl<H> From<ServiceResponse<H>> for ServiceOutput<H>
203where
204 H: StateHandler,
205{
206 fn from(msg: ServiceResponse<H>) -> Self {
207 ServiceOutput::Service(msg)
208 }
209}