1use std::fmt;
5use std::rc::{Rc, Weak};
6use std::sync::Arc;
7
8use nifty_download::Downloads;
9use nifty_runtime::{
10 Backend, Dialogs, Engine, Logic, Shown, StateSet, Templates, Ui, Waker, WindowRequest,
11};
12
13use crate::context::{AppError, Context};
14use crate::dialog::Answer;
15use crate::download::Targets;
16use crate::program::{ActionFn, ExpandFn, FrameDesc, ReadFn, WriteFn};
17use crate::show::Sink;
18use crate::value::{
19 BOOL, INT, LIST_OF_STRINGS, STRING, Slot, TypeDesc, Value, as_list, as_str, int, int_slot,
20 release, retain, string_slot, strings_slot,
21};
22
23pub struct Frame {
25 slots: Box<[Slot]>,
26 types: &'static [&'static TypeDesc],
27}
28
29impl Frame {
30 pub(crate) fn empty(desc: &'static FrameDesc) -> Self {
32 let types = desc.locals.items();
33 Self {
34 slots: vec![0; types.len()].into(),
35 types,
36 }
37 }
38
39 pub(crate) fn as_ptr(&self) -> *const Slot {
40 self.slots.as_ptr()
41 }
42
43 pub(crate) fn as_mut_ptr(&mut self) -> *mut Slot {
44 self.slots.as_mut_ptr()
45 }
46}
47
48impl Clone for Frame {
49 fn clone(&self) -> Self {
50 for (slot, ty) in self.slots.iter().zip(self.types) {
51 retain(*slot, ty);
52 }
53 Self {
54 slots: self.slots.clone(),
55 types: self.types,
56 }
57 }
58}
59
60impl Drop for Frame {
61 fn drop(&mut self) {
62 for (slot, ty) in self.slots.iter().zip(self.types) {
63 release(*slot, ty);
64 }
65 }
66}
67
68impl fmt::Debug for Frame {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 f.debug_struct("Frame")
71 .field("locals", &self.slots.len())
72 .finish_non_exhaustive()
73 }
74}
75
76#[derive(Clone, Copy, Debug)]
78pub struct Binding {
79 pub(crate) read: ReadFn,
80 pub(crate) write: WriteFn,
81}
82
83#[derive(Debug)]
85pub struct Region {
86 pub(crate) expand: ExpandFn,
87 pub(crate) lists: Vec<Templates<Compiled>>,
88}
89
90#[derive(Debug)]
91pub(crate) struct ViewTemplate {
92 pub body: Templates<Compiled>,
93 pub frame: &'static FrameDesc,
94}
95
96pub struct Compiled {
97 context: Context,
98 views: Vec<ViewTemplate>,
100 downloads: Downloads<Targets>,
101 dialogs: Dialogs<Answer>,
102}
103
104impl Compiled {
105 pub(crate) fn new<B: Backend>(
108 context: Context,
109 views: Vec<ViewTemplate>,
110 ui: &Ui<B>,
111 engine: Weak<Engine<Self, B>>,
112 ) -> Self {
113 let waker: Arc<dyn Waker> = Arc::new(ui.waker(Box::new(move || {
114 if let Some(engine) = engine.upgrade() {
115 engine.logic().dialogs.show_asked();
116 engine.handle_event(Self::receive);
117 }
118 })));
119 Self {
120 context,
121 views,
122 downloads: Downloads::new(Arc::clone(&waker)),
123 dialogs: Dialogs::new(ui.dialogs(), waker),
124 }
125 }
126
127 #[cfg(test)]
128 pub(crate) fn context(&self) -> &Context {
129 &self.context
130 }
131
132 #[cfg(any(test, feature = "testing"))]
134 pub fn wait_for_downloads(&self) {
135 self.downloads.wait();
136 }
137
138 #[cfg(any(test, feature = "testing"))]
140 pub fn wait_for_download_report(&self) {
141 self.downloads.wait_for_report();
142 }
143
144 fn event(&self, run: impl FnOnce() -> Result<(), AppError>) -> Result<(), AppError> {
147 let result = run();
148 for request in self.context.take_downloads() {
149 self.downloads.start(request);
150 }
151 for (command, id) in self.context.take_download_commands() {
152 self.downloads.command(&id, command);
153 }
154 self.downloads
155 .cancel_unheld(|targets| self.context.follow_download(targets));
156 for (dialog, answer) in self.context.take_dialogs() {
157 self.dialogs.ask(dialog, answer);
158 }
159 result
160 }
161
162 fn receive(&self) -> Result<(), AppError> {
163 self.downloads.receive(
164 |targets| self.context.follow_download(targets),
165 |targets, report| self.context.report_download(targets, report),
166 )?;
167 self.dialogs
168 .receive(|answer, picked| self.context.answer_dialog(answer, picked))
169 }
170
171 fn call(&self, run: impl FnOnce(*const Context) -> bool) -> Result<(), AppError> {
173 if run(&raw const self.context) {
174 Ok(())
175 } else {
176 Err(self.context.take_error())
177 }
178 }
179
180 fn read(&self, read: ReadFn, frame: &Frame, ty: &'static TypeDesc) -> Result<Value, AppError> {
182 let mut out = 0;
183 self.call(|context| unsafe { read(context, frame.as_ptr(), &raw mut out) })?;
186 Ok(Value::owned(out, ty))
187 }
188
189 fn write(&self, binding: &Binding, frame: &Frame, value: Slot) -> Result<(), AppError> {
190 self.event(|| {
193 self.call(|context| unsafe { (binding.write)(context, frame.as_ptr(), value) })
194 })
195 }
196}
197
198impl Logic for Compiled {
199 type Frame = Frame;
200 type Value = ReadFn;
201 type Binding = Binding;
202 type Action = ActionFn;
203 type Region = Region;
204 type Error = AppError;
205
206 fn text(&self, text: &ReadFn, frame: &Frame) -> Result<String, AppError> {
207 let value = self.read(*text, frame, &STRING)?;
208 Ok(as_str(value.slot()).to_owned())
209 }
210
211 fn number(&self, number: &ReadFn, frame: &Frame) -> Result<i64, AppError> {
212 Ok(int(self.read(*number, frame, &INT)?.slot()))
213 }
214
215 fn flag(&self, flag: &ReadFn, frame: &Frame) -> Result<bool, AppError> {
216 Ok(self.read(*flag, frame, &BOOL)?.slot() != 0)
217 }
218
219 fn texts(&self, texts: &ReadFn, frame: &Frame) -> Result<Vec<String>, AppError> {
220 let list = self.read(*texts, frame, &LIST_OF_STRINGS)?;
221 Ok(as_list(list.slot())
222 .items
223 .iter()
224 .map(|item| as_str(*item).to_owned())
225 .collect())
226 }
227
228 fn read_number(&self, binding: &Binding, frame: &Frame) -> Result<i64, AppError> {
229 self.number(&binding.read, frame)
230 }
231
232 fn read_text(&self, binding: &Binding, frame: &Frame) -> Result<String, AppError> {
233 self.text(&binding.read, frame)
234 }
235
236 fn read_checked(&self, binding: &Binding, frame: &Frame) -> Result<bool, AppError> {
237 self.flag(&binding.read, frame)
238 }
239
240 fn write_text(&self, binding: &Binding, frame: &Frame, text: &str) -> Result<(), AppError> {
241 self.write(binding, frame, string_slot(text))
242 }
243
244 fn write_checked(
245 &self,
246 binding: &Binding,
247 frame: &Frame,
248 checked: bool,
249 ) -> Result<(), AppError> {
250 self.write(binding, frame, Slot::from(checked))
251 }
252
253 fn write_number(&self, binding: &Binding, frame: &Frame, number: i64) -> Result<(), AppError> {
254 self.write(binding, frame, int_slot(number))
255 }
256
257 fn write_texts(
258 &self,
259 binding: &Binding,
260 frame: &Frame,
261 texts: Vec<String>,
262 ) -> Result<(), AppError> {
263 self.write(binding, frame, strings_slot(texts))
264 }
265
266 fn run(&self, action: &ActionFn, frame: &Frame) -> Result<(), AppError> {
267 let mut scratch = frame.clone();
268 self.event(|| self.call(|context| unsafe { action(context, scratch.as_mut_ptr()) }))
270 }
271
272 fn expand(&self, region: &Region, frame: &Rc<Frame>) -> Result<Vec<Shown<Self>>, AppError> {
273 let mut sink = Sink::new(region, &self.views, frame);
274 self.call(|context| unsafe { (region.expand)(context, frame.as_ptr(), &raw mut sink) })?;
277 Ok(sink.finish())
278 }
279
280 fn take_changed(&self) -> StateSet {
281 self.context.take_changed()
282 }
283
284 fn take_window_requests(&self) -> Vec<WindowRequest> {
285 self.context.take_window_requests()
286 }
287}
288
289impl fmt::Debug for Compiled {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 f.debug_struct("Compiled")
292 .field("context", &self.context)
293 .finish_non_exhaustive()
294 }
295}