1mod effect;
2mod request;
3mod resolve;
4
5use std::sync::RwLock;
6
7pub use effect::Effect;
8pub use request::Request;
9pub use resolve::ResolveError;
10
11pub(crate) use resolve::Resolve;
12
13use crate::capability::CommandSpawner;
14use crate::capability::{self, channel::Receiver, Operation, ProtoContext, QueuingExecutor};
15use crate::{App, WithContext};
16
17pub struct Core<A>
28where
29 A: App,
30{
31 model: RwLock<A::Model>,
38 capabilities: A::Capabilities,
39 app: A,
40
41 requests: Receiver<A::Effect>,
43 capability_events: Receiver<A::Event>,
44 executor: QueuingExecutor,
45
46 command_spawner: CommandSpawner<A::Effect, A::Event>,
48}
49impl<A> Core<A>
52where
53 A: App,
54{
55 pub fn new() -> Self
62 where
63 A::Capabilities: WithContext<A::Event, A::Effect>,
64 {
65 let (request_sender, request_receiver) = capability::channel();
66 let (event_sender, event_receiver) = capability::channel();
67 let (executor, spawner) = capability::executor_and_spawner();
68 let proto_context = ProtoContext::new(request_sender, event_sender, spawner);
69 let command_spawner = CommandSpawner::new(proto_context.clone());
70
71 Self {
72 model: Default::default(),
73 executor,
74 app: Default::default(),
75 capabilities: <<A as App>::Capabilities>::new_with_context(proto_context),
76 requests: request_receiver,
77 capability_events: event_receiver,
78 command_spawner,
79 }
80 }
81
82 pub fn process_event(&self, event: A::Event) -> Vec<A::Effect> {
87 let mut model = self.model.write().expect("Model RwLock was poisoned.");
88
89 let command = self.app.update(event, &mut model, &self.capabilities);
90
91 drop(model);
93
94 self.command_spawner.spawn(command);
95 self.process()
96 }
97 pub fn resolve<Op>(
108 &self,
109 request: &mut Request<Op>,
110 result: Op::Output,
111 ) -> Result<Vec<A::Effect>, ResolveError>
112 where
113 Op: Operation,
114 {
116 let resolve_result = request.resolve(result);
117 debug_assert!(resolve_result.is_ok());
118
119 resolve_result?;
120
121 Ok(self.process())
122 }
123 pub(crate) fn process(&self) -> Vec<A::Effect> {
128 self.executor.run_all();
129
130 while let Some(capability_event) = self.capability_events.receive() {
131 let mut model = self.model.write().expect("Model RwLock was poisoned.");
132 let command = self
133 .app
134 .update(capability_event, &mut model, &self.capabilities);
135
136 drop(model);
137
138 self.command_spawner.spawn(command);
139 self.executor.run_all();
140 }
141
142 self.requests.drain().collect()
143 }
144 pub fn view(&self) -> A::ViewModel {
148 let model = self.model.read().expect("Model RwLock was poisoned.");
149
150 self.app.view(&model)
151 }
152}
153
154impl<A> Default for Core<A>
155where
156 A: App,
157 A::Capabilities: WithContext<A::Event, A::Effect>,
158{
159 fn default() -> Self {
160 Self::new()
161 }
162}