1use std::collections::HashMap;
9use std::mem::{offset_of, size_of};
10
11use cranelift_codegen::ir::types::{I8, I64};
12use cranelift_codegen::ir::{InstBuilder, MemFlags, Value};
13use cranelift_module::{FuncId, Module};
14use nifty_check::hir::{
15 Binding, Block as Stmts, Dynamic, Expr, Iterable, LocalId, Loop, NavItem, Node, Nodes, Place,
16 PlaceRoot, PlaceStep, StateSet, Type, ViewId,
17};
18use nifty_rt::{
19 BindingDesc, FrameDesc, RegionDesc, Slice, TemplateDesc, TemplateKind, TypeDesc, ViewDesc,
20 WindowDesc,
21};
22use nifty_runtime::{ImageSize, LabelStyle, StackStyle, ToggleStyle};
23
24use super::body::{Alias, Body, Index, Operand, Root, Step, element_type};
25use super::{List, Result, Shared, put_str};
26use crate::CodegenError;
27use crate::emit::{Blob, Emitter, Target};
28
29pub(super) struct Frame<'p> {
32 locals: &'p [Type],
33 extra: usize,
34}
35
36impl<'p> Frame<'p> {
37 pub(super) fn new(locals: &'p [Type]) -> Self {
38 Self { locals, extra: 0 }
39 }
40}
41
42impl Frame<'_> {
43 fn add_slot(&mut self) -> usize {
44 self.extra += 1;
45 self.locals.len() + self.extra - 1
46 }
47
48 fn types(&self) -> Vec<Type> {
50 let mut types = self.locals.to_vec();
51 types.extend(std::iter::repeat_n(Type::Int, self.extra));
52 types
53 }
54}
55
56pub(super) type Aliases = HashMap<LocalId, Alias>;
58
59struct Slot<'b> {
61 blob: &'b mut Blob,
62 at: usize,
63}
64
65impl Slot<'_> {
66 fn function(&mut self, field: usize, function: FuncId) {
67 self.blob
68 .put_pointer(self.at + field, Target::Function(function));
69 }
70}
71
72pub(super) struct Ui<'a, 'p, M: Module> {
73 pub(super) emitter: &'a mut Emitter<M>,
74 pub(super) shared: &'a mut Shared<'p>,
75}
76
77pub(super) fn windows<M: Module>(
78 emitter: &mut Emitter<M>,
79 shared: &mut Shared<'_>,
80) -> Result<List> {
81 let program = shared.program;
82 let mut ui = Ui { emitter, shared };
83 let size = size_of::<WindowDesc>();
84 let mut blob = Blob::zeroed(program.windows.len() * size);
85 for (index, window) in program.windows.iter().enumerate() {
86 let mut frame = Frame::new(&window.locals);
87 let children = ui.templates(&mut frame, &Aliases::new(), &window.children)?;
88 let locals = ui.frame_types(&frame)?;
89 let at = index * size;
90 put_str(
91 ui.emitter,
92 ui.shared,
93 &mut blob,
94 at + offset_of!(WindowDesc, title),
95 &window.title,
96 )?;
97 blob.put_f32(at + offset_of!(WindowDesc, width), window.size.width);
98 blob.put_f32(at + offset_of!(WindowDesc, height), window.size.height);
99 blob.put_u8(
100 at + offset_of!(WindowDesc, backdrop),
101 window.backdrop.code(),
102 );
103 blob.put_u8(
104 at + offset_of!(WindowDesc, starts_open),
105 u8::from(window.starts_open),
106 );
107 put_stack(&mut blob, at + offset_of!(WindowDesc, style), window.style);
108 children.put(&mut blob, at + offset_of!(WindowDesc, children));
109 locals.put(
110 &mut blob,
111 at + offset_of!(WindowDesc, frame) + offset_of!(FrameDesc, locals),
112 );
113 }
114 ui.list(blob, program.windows.len())
115}
116
117pub(super) fn views<M: Module>(emitter: &mut Emitter<M>, shared: &mut Shared<'_>) -> Result<List> {
118 let program = shared.program;
119 let mut ui = Ui { emitter, shared };
120 let size = size_of::<ViewDesc>();
121 let mut blob = Blob::zeroed(program.views.len() * size);
122 for (index, view) in program.views.iter().enumerate() {
123 let mut frame = Frame::new(&view.locals);
124 let body = ui.templates(&mut frame, &Aliases::new(), &view.body)?;
125 let locals = ui.frame_types(&frame)?;
126 let at = index * size;
127 body.put(&mut blob, at + offset_of!(ViewDesc, body));
128 locals.put(
129 &mut blob,
130 at + offset_of!(ViewDesc, frame) + offset_of!(FrameDesc, locals),
131 );
132 }
133 ui.list(blob, program.views.len())
134}
135
136impl<M: Module> Ui<'_, '_, M> {
137 pub(super) fn list(&mut self, blob: Blob, len: usize) -> Result<List> {
138 if len == 0 {
139 return Ok(List::EMPTY);
140 }
141 Ok(List {
142 data: Some(self.emitter.data(blob)?),
143 len,
144 })
145 }
146
147 pub(super) fn frame_types(&mut self, frame: &Frame<'_>) -> Result<List> {
148 let types = frame
149 .types()
150 .iter()
151 .map(|ty| {
152 self.shared
153 .types
154 .desc(self.emitter.module_mut(), &self.shared.runtime, ty)
155 })
156 .collect::<Result<Vec<_>>>()?;
157 List::emit(
158 self.emitter,
159 types.len(),
160 size_of::<&TypeDesc>(),
161 |blob, index, at| {
162 blob.put_pointer(at, Target::Data(types[index]));
163 Ok(())
164 },
165 )
166 }
167
168 fn templates(
170 &mut self,
171 frame: &mut Frame<'_>,
172 aliases: &Aliases,
173 nodes: &Nodes,
174 ) -> Result<List> {
175 let size = size_of::<TemplateDesc>();
176 let mut blob = Blob::zeroed(nodes.len() * size);
177 for (index, node) in nodes.iter().enumerate() {
178 let mut slot = Slot {
179 blob: &mut blob,
180 at: index * size,
181 };
182 let kind = self.template(frame, aliases, node, &mut slot)?;
183 blob.put_u8(index * size + offset_of!(TemplateDesc, kind), kind as u8);
184 }
185 self.list(blob, nodes.len())
186 }
187
188 fn template(
189 &mut self,
190 frame: &mut Frame<'_>,
191 aliases: &Aliases,
192 node: &Node,
193 slot: &mut Slot<'_>,
194 ) -> Result<TemplateKind> {
195 Ok(match node {
196 Node::Stack {
197 style,
198 children,
199 scrolls,
200 } => {
201 put_stack(slot.blob, slot.at + offset_of!(TemplateDesc, stack), *style);
202 let children = self.templates(frame, aliases, children)?;
203 children.put(slot.blob, slot.at + offset_of!(TemplateDesc, children));
204 if *scrolls {
205 TemplateKind::Scroll
206 } else {
207 TemplateKind::Stack
208 }
209 }
210 Node::If {
211 branches,
212 otherwise,
213 deps,
214 } => {
215 self.if_region(frame, aliases, branches, otherwise, slot)?;
216 self.deps(slot, deps)?;
217 TemplateKind::Region
218 }
219 Node::For { head, body, deps } => {
220 self.for_region(frame, aliases, head, body, slot)?;
221 self.deps(slot, deps)?;
222 TemplateKind::Region
223 }
224 Node::View { view, args, deps } => {
225 let expand = self.view(frame, aliases, *view, args)?;
226 self.region(slot, expand, &[])?;
227 self.deps(slot, deps)?;
228 TemplateKind::Region
229 }
230 control => self.control(frame, aliases, control, slot)?,
231 })
232 }
233
234 fn control(
236 &mut self,
237 frame: &mut Frame<'_>,
238 aliases: &Aliases,
239 node: &Node,
240 slot: &mut Slot<'_>,
241 ) -> Result<TemplateKind> {
242 match node {
243 Node::Label { .. }
244 | Node::Image { .. }
245 | Node::Progress { .. }
246 | Node::Spacer
247 | Node::Divider => self.display(frame, aliases, node, slot),
248 _ => self.input(frame, aliases, node, slot),
249 }
250 }
251
252 fn display(
254 &mut self,
255 frame: &mut Frame<'_>,
256 aliases: &Aliases,
257 node: &Node,
258 slot: &mut Slot<'_>,
259 ) -> Result<TemplateKind> {
260 Ok(match node {
261 Node::Label { text, style } => {
262 put_label(slot.blob, slot.at + offset_of!(TemplateDesc, label), *style);
263 self.shown(frame, aliases, text, slot, offset_of!(TemplateDesc, text))?;
264 self.deps(slot, &text.deps)?;
265 TemplateKind::Label
266 }
267 Node::Image { path, size } => {
268 put_image(slot.blob, slot.at + offset_of!(TemplateDesc, image), *size);
269 self.shown(frame, aliases, path, slot, offset_of!(TemplateDesc, text))?;
270 self.deps(slot, &path.deps)?;
271 TemplateKind::Image
272 }
273 Node::Progress { value } => {
274 if let Some(value) = value {
275 self.shown(frame, aliases, value, slot, offset_of!(TemplateDesc, value))?;
276 self.deps(slot, &value.deps)?;
277 }
278 TemplateKind::Progress
279 }
280 Node::Spacer => TemplateKind::Spacer,
281 Node::Divider => TemplateKind::Divider,
282 _ => return Err(CodegenError::new(format!("{node:?} isn't a display"))),
283 })
284 }
285
286 fn input(
288 &mut self,
289 frame: &mut Frame<'_>,
290 aliases: &Aliases,
291 node: &Node,
292 slot: &mut Slot<'_>,
293 ) -> Result<TemplateKind> {
294 Ok(match node {
295 Node::Button {
296 title,
297 style,
298 icon,
299 selected,
300 action,
301 } => {
302 slot.blob
303 .put_u8(slot.at + offset_of!(TemplateDesc, button), style.code());
304 slot.blob
305 .put_u8(slot.at + offset_of!(TemplateDesc, icon), icon.code());
306 self.button(frame, aliases, (title, selected.as_deref()), action, slot)?;
307 TemplateKind::Button
308 }
309 Node::TextField {
310 value,
311 placeholder,
312 lines,
313 action,
314 } => {
315 self.binding(frame, aliases, value, slot)?;
316 self.optional_action(frame, aliases, action.as_ref(), slot)?;
317 let at = slot.at + offset_of!(TemplateDesc, placeholder);
318 put_str(self.emitter, self.shared, slot.blob, at, placeholder)?;
319 slot.blob
320 .put_u32(slot.at + offset_of!(TemplateDesc, lines), *lines);
321 self.deps(slot, &value.deps)?;
322 TemplateKind::TextField
323 }
324 Node::Checkbox {
325 checked,
326 title,
327 style,
328 } => {
329 self.binding(frame, aliases, checked, slot)?;
330 let mut deps = checked.deps.clone();
331 if let Some(title) = title {
332 self.shown(frame, aliases, title, slot, offset_of!(TemplateDesc, text))?;
333 deps.extend(&title.deps);
334 }
335 self.deps(slot, &deps)?;
336 match style {
337 ToggleStyle::Checkbox => TemplateKind::Checkbox,
338 ToggleStyle::Switch => TemplateKind::Switch,
339 }
340 }
341 Node::Slider { value, min, max } => {
342 self.binding(frame, aliases, value, slot)?;
343 slot.blob
344 .put_i64(slot.at + offset_of!(TemplateDesc, min), *min);
345 slot.blob
346 .put_i64(slot.at + offset_of!(TemplateDesc, max), *max);
347 self.deps(slot, &value.deps)?;
348 TemplateKind::Slider
349 }
350 Node::Picker {
351 selection,
352 options,
353 deps,
354 } => {
355 self.binding(frame, aliases, selection, slot)?;
356 self.shown(
357 frame,
358 aliases,
359 options,
360 slot,
361 offset_of!(TemplateDesc, value),
362 )?;
363 self.deps(slot, deps)?;
364 TemplateKind::Picker
365 }
366 Node::NavItem(item) => {
367 self.nav_item(frame, aliases, item, slot)?;
368 TemplateKind::NavItem
369 }
370 Node::ContextMenu { entries } => {
371 let menu = self.menu_entries(frame, aliases, entries)?;
372 menu.put(slot.blob, slot.at + offset_of!(TemplateDesc, menu));
373 TemplateKind::ContextMenu
374 }
375 Node::DropTarget { dropped, action } => {
376 self.binding(frame, aliases, dropped, slot)?;
377 self.optional_action(frame, aliases, action.as_ref(), slot)?;
378 TemplateKind::DropTarget
379 }
380 _ => return Err(CodegenError::new(format!("{node:?} isn't an input"))),
381 })
382 }
383
384 fn for_region(
386 &mut self,
387 frame: &mut Frame<'_>,
388 aliases: &Aliases,
389 head: &Loop,
390 body: &Nodes,
391 slot: &mut Slot<'_>,
392 ) -> Result<()> {
393 let (expand, list) = match &head.iterable {
394 Iterable::Value(list) => {
395 let body = self.templates(frame, aliases, body)?;
396 (self.for_value(frame, aliases, head, list)?, body)
397 }
398 Iterable::Place(place) => self.for_place(frame, aliases, head, place, body)?,
399 Iterable::Range { start, end } => {
400 let body = self.templates(frame, aliases, body)?;
401 (self.for_range(frame, aliases, head.item, start, end)?, body)
402 }
403 };
404 self.region(slot, expand, &[list])
405 }
406
407 fn button(
409 &mut self,
410 frame: &mut Frame<'_>,
411 aliases: &Aliases,
412 (title, selected): (&Dynamic, Option<&Dynamic>),
413 action: &Stmts,
414 slot: &mut Slot<'_>,
415 ) -> Result<()> {
416 let title_fn = self.value(frame, aliases, title)?;
417 slot.function(offset_of!(TemplateDesc, text), title_fn);
418 let mut deps = title.deps.clone();
419 if let Some(selected) = selected {
420 let selected_fn = self.value(frame, aliases, selected)?;
421 slot.function(offset_of!(TemplateDesc, value), selected_fn);
422 deps.extend(&selected.deps);
423 }
424 let action_fn = self.action(frame, aliases, action)?;
425 slot.function(offset_of!(TemplateDesc, action), action_fn);
426 self.deps(slot, &deps)
427 }
428
429 fn nav_item(
430 &mut self,
431 frame: &mut Frame<'_>,
432 aliases: &Aliases,
433 item: &NavItem,
434 slot: &mut Slot<'_>,
435 ) -> Result<()> {
436 slot.blob
437 .put_u8(slot.at + offset_of!(TemplateDesc, icon), item.icon.code());
438 self.binding(frame, aliases, &item.selection, slot)?;
439 let title_fn = self.value(frame, aliases, &item.title)?;
440 slot.function(offset_of!(TemplateDesc, text), title_fn);
441 let value_fn = self.value(frame, aliases, &item.value)?;
442 slot.function(offset_of!(TemplateDesc, value), value_fn);
443 if let Some(badge) = &item.badge {
444 let badge_fn = self.value(frame, aliases, badge)?;
445 slot.function(offset_of!(TemplateDesc, badge), badge_fn);
446 }
447 self.deps(slot, &item.deps)
448 }
449
450 fn if_region(
453 &mut self,
454 frame: &mut Frame<'_>,
455 aliases: &Aliases,
456 branches: &[(std::rc::Rc<Expr>, Nodes)],
457 otherwise: &Nodes,
458 slot: &mut Slot<'_>,
459 ) -> Result<()> {
460 let mut lists = Vec::new();
461 for (_, body) in branches {
462 lists.push(self.templates(frame, aliases, body)?);
463 }
464 lists.push(self.templates(frame, aliases, otherwise)?);
465 let expand = self.expansion(frame, aliases, |body, sink| {
466 let show = body.shared.runtime.show_same;
467 for (index, (condition, _)) in branches.iter().enumerate() {
468 let holds = body.expr(condition)?.value;
469 let showing = body.b.create_block();
470 let next = body.b.create_block();
471 body.b.ins().brif(holds, showing, &[], next, &[]);
472 body.b.switch_to_block(showing);
473 let list = body.u32(index)?;
474 body.call(show, &[sink, list]);
475 body.succeed_here();
476 body.b.switch_to_block(next);
477 }
478 let otherwise = body.u32(branches.len())?;
479 body.call(show, &[sink, otherwise]);
480 Ok(())
481 })?;
482 self.region(slot, expand, &lists)
483 }
484
485 fn for_value(
488 &mut self,
489 frame: &Frame<'_>,
490 aliases: &Aliases,
491 head: &Loop,
492 list: &Expr,
493 ) -> Result<FuncId> {
494 let element = element_type(&list.ty)?;
495 self.expansion(frame, aliases, |body, sink| {
496 let operand = body.expr(list)?;
497 let list_owned = body.own(operand, &list.ty)?;
498 let len_fn = body.shared.runtime.list_len;
499 let len = body.call1(len_fn, &[list_owned]);
500 body.count_up(len, |body, index| {
501 let item = body.list_item(list_owned, index, list.span)?;
502 let item = body.own(Operand::borrowed(item), &element)?;
503 let locals = show_round(body, sink)?;
504 store_index(body, locals, head.index, index)?;
505 let slot = body.b.ins().iadd_imm(locals, slot_offset(head.item.0)?);
506 body.store(slot, item, &element)
507 })?;
508 body.release(list_owned, &list.ty)
509 })
510 }
511
512 fn for_range(
515 &mut self,
516 frame: &Frame<'_>,
517 aliases: &Aliases,
518 local: LocalId,
519 start: &Expr,
520 end: &Expr,
521 ) -> Result<FuncId> {
522 self.expansion(frame, aliases, |body, sink| {
523 let start = body.expr(start)?.value;
524 let end = body.expr(end)?.value;
525 body.count(start, end, |body, count| {
526 let locals = show_round(body, sink)?;
527 store_int(body, locals, local.0, count)
528 })
529 })
530 }
531
532 fn for_place(
535 &mut self,
536 frame: &mut Frame<'_>,
537 aliases: &Aliases,
538 head: &Loop,
539 place: &Place,
540 nodes: &Nodes,
541 ) -> Result<(FuncId, List)> {
542 let mut item = match place.root {
543 PlaceRoot::State(state) => Alias {
544 root: Root::State(state),
545 steps: Vec::new(),
546 },
547 PlaceRoot::Local(root) => aliases.get(&root).cloned().unwrap_or(Alias {
548 root: Root::Local(root.0),
549 steps: Vec::new(),
550 }),
551 };
552 let mut positions = Vec::new();
553 for step in &place.path {
554 item.steps.push(match step {
555 PlaceStep::Field(field) => Step::Field(*field),
556 PlaceStep::Index(_) => {
557 let slot = frame.add_slot();
558 positions.push(slot);
559 Step::Index(Index::Slot(slot))
560 }
561 });
562 }
563 let counter = frame.add_slot();
564 item.steps.push(Step::Index(Index::Slot(counter)));
565 let mut inner = aliases.clone();
566 inner.insert(head.item, item);
567 let list = self.templates(frame, &inner, nodes)?;
568 let expand = self.expansion(frame, aliases, |body, sink| {
569 let path = body.path(place)?;
570 let worked_out: Vec<Value> = path
571 .steps
572 .iter()
573 .filter_map(|step| match step {
574 Step::Index(Index::Value(value)) => Some(*value),
575 _ => None,
576 })
577 .collect();
578 let list_value = body.read(&path, place.span)?;
579 let len_fn = body.shared.runtime.list_len;
580 let len = body.call1(len_fn, &[list_value]);
581 body.count_up(len, |body, index| {
582 let locals = show_round(body, sink)?;
583 for (slot, value) in positions.iter().zip(&worked_out) {
584 store_int(body, locals, *slot, *value)?;
585 }
586 store_index(body, locals, head.index, index)?;
587 store_int(body, locals, counter, index)
588 })
589 })?;
590 Ok((expand, list))
591 }
592
593 fn view(
595 &mut self,
596 frame: &Frame<'_>,
597 aliases: &Aliases,
598 view: ViewId,
599 args: &[Expr],
600 ) -> Result<FuncId> {
601 self.expansion(frame, aliases, |body, sink| {
602 let id = body.u32(view.0)?;
603 let show = body.shared.runtime.show_view;
604 let locals = body.call1(show, &[sink, id]);
605 for (index, arg) in args.iter().enumerate() {
606 let operand = body.expr(arg)?;
607 let value = body.own(operand, &arg.ty)?;
608 let slot = body.b.ins().iadd_imm(locals, slot_offset(index)?);
609 body.store(slot, value, &arg.ty)?;
610 }
611 Ok(())
612 })
613 }
614
615 fn function(
618 &mut self,
619 frame: &Frame<'_>,
620 aliases: &Aliases,
621 extra: bool,
622 build: impl FnOnce(&mut Body<'_, '_, '_, M>, Value) -> Result<()>,
623 ) -> Result<FuncId> {
624 let params: &[_] = if extra { &[I64, I64, I64] } else { &[I64, I64] };
625 let signature = self.emitter.signature(params, &[I8]);
626 let (shared, locals) = (&mut *self.shared, frame.locals);
627 self.emitter.function(signature, |b, module| {
628 let entry = b
629 .current_block()
630 .ok_or_else(|| CodegenError::new("a function has no entry block"))?;
631 let params = b.block_params(entry).to_vec();
632 let mut body = Body::new(b, module, shared, params[0], params[1], locals);
633 body.aliases.clone_from(aliases);
634 build(&mut body, params[params.len() - 1])?;
635 body.finish();
636 Ok(())
637 })
638 }
639
640 fn expansion(
642 &mut self,
643 frame: &Frame<'_>,
644 aliases: &Aliases,
645 build: impl FnOnce(&mut Body<'_, '_, '_, M>, Value) -> Result<()>,
646 ) -> Result<FuncId> {
647 self.function(frame, aliases, true, build)
648 }
649
650 fn shown(
652 &mut self,
653 frame: &Frame<'_>,
654 aliases: &Aliases,
655 shown: &Dynamic,
656 slot: &mut Slot<'_>,
657 field: usize,
658 ) -> Result<()> {
659 let function = self.value(frame, aliases, shown)?;
660 slot.function(field, function);
661 Ok(())
662 }
663
664 fn value(&mut self, frame: &Frame<'_>, aliases: &Aliases, shown: &Dynamic) -> Result<FuncId> {
666 self.function(frame, aliases, true, |body, out| {
667 let operand = body.expr(&shown.expr)?;
668 let value = body.own(operand, &shown.expr.ty)?;
669 body.b.ins().store(MemFlags::trusted(), value, out, 0);
670 Ok(())
671 })
672 }
673
674 pub(super) fn action(
675 &mut self,
676 frame: &Frame<'_>,
677 aliases: &Aliases,
678 action: &Stmts,
679 ) -> Result<FuncId> {
680 self.function(frame, aliases, false, |body, _| body.block(action))
681 }
682
683 fn optional_action(
685 &mut self,
686 frame: &Frame<'_>,
687 aliases: &Aliases,
688 action: Option<&Stmts>,
689 slot: &mut Slot<'_>,
690 ) -> Result<()> {
691 if let Some(action) = action {
692 let action_fn = self.action(frame, aliases, action)?;
693 slot.function(offset_of!(TemplateDesc, action), action_fn);
694 }
695 Ok(())
696 }
697
698 fn binding(
700 &mut self,
701 frame: &Frame<'_>,
702 aliases: &Aliases,
703 binding: &Binding,
704 slot: &mut Slot<'_>,
705 ) -> Result<()> {
706 let place = &binding.place;
707 let read = self.function(frame, aliases, true, |body, out| {
708 let path = body.path(place)?;
709 let value = body.read(&path, place.span)?;
710 let value = body.own(Operand::borrowed(value), &place.ty)?;
711 body.b.ins().store(MemFlags::trusted(), value, out, 0);
712 Ok(())
713 })?;
714 let write = self.function(frame, aliases, true, |body, value| {
715 let path = body.path(place)?;
716 if !matches!(path.root, Root::State(_)) {
719 return body.discard(Operand::owned(value), &place.ty);
720 }
721 let pointer = body.pointer(&path, place.span)?;
722 body.store(pointer, value, &place.ty)
723 })?;
724 let binding_at = offset_of!(TemplateDesc, binding);
725 slot.function(binding_at + offset_of!(BindingDesc, read), read);
726 slot.function(binding_at + offset_of!(BindingDesc, write), write);
727 Ok(())
728 }
729
730 fn region(&mut self, slot: &mut Slot<'_>, expand: FuncId, lists: &[List]) -> Result<()> {
731 let region_at = offset_of!(TemplateDesc, region);
732 slot.function(region_at + offset_of!(RegionDesc, expand), expand);
733 let size = size_of::<Slice<TemplateDesc>>();
734 let lists = List::emit(self.emitter, lists.len(), size, |blob, index, at| {
735 lists[index].put(blob, at);
736 Ok(())
737 })?;
738 lists.put(
739 slot.blob,
740 slot.at + region_at + offset_of!(RegionDesc, lists),
741 );
742 Ok(())
743 }
744
745 fn deps(&mut self, slot: &mut Slot<'_>, states: &StateSet) -> Result<()> {
746 let ids = states
747 .iter()
748 .map(|state| {
749 u32::try_from(state.0)
750 .map_err(|_| CodegenError::new("the program has too many states"))
751 })
752 .collect::<Result<Vec<_>>>()?;
753 let list = List::emit(
754 self.emitter,
755 ids.len(),
756 size_of::<u32>(),
757 |blob, index, at| {
758 blob.put_u32(at, ids[index]);
759 Ok(())
760 },
761 )?;
762 list.put(slot.blob, slot.at + offset_of!(TemplateDesc, deps));
763 Ok(())
764 }
765}
766
767fn show_round<M: Module>(body: &mut Body<'_, '_, '_, M>, sink: Value) -> Result<Value> {
769 let show = body.shared.runtime.show_item;
770 let first = body.u32(0)?;
771 Ok(body.call1(show, &[sink, first]))
772}
773
774fn store_index<M: Module>(
776 body: &mut Body<'_, '_, '_, M>,
777 locals: Value,
778 index: Option<LocalId>,
779 position: Value,
780) -> Result<()> {
781 match index {
782 Some(index) => store_int(body, locals, index.0, position),
783 None => Ok(()),
784 }
785}
786
787fn store_int<M: Module>(
789 body: &mut Body<'_, '_, '_, M>,
790 locals: Value,
791 slot: usize,
792 value: Value,
793) -> Result<()> {
794 let at =
795 i32::try_from(slot_offset(slot)?).map_err(|_| CodegenError::new("a frame is too large"))?;
796 body.b.ins().store(MemFlags::trusted(), value, locals, at);
797 Ok(())
798}
799
800fn put_stack(blob: &mut Blob, at: usize, style: StackStyle) {
801 blob.put_u8(at + offset_of!(StackStyle, axis), style.axis.code());
802 blob.put_f32(at + offset_of!(StackStyle, spacing), style.spacing);
803 blob.put_f32(at + offset_of!(StackStyle, padding), style.padding);
804 blob.put_u8(at + offset_of!(StackStyle, align), style.align.code());
805 blob.put_u8(at + offset_of!(StackStyle, justify), style.justify.code());
806 blob.put_u8(at + offset_of!(StackStyle, surface), style.surface.code());
807 blob.put_u8(at + offset_of!(StackStyle, grow), u8::from(style.grow));
808 blob.put_f32(at + offset_of!(StackStyle, width), style.width);
809 blob.put_f32(at + offset_of!(StackStyle, max_width), style.max_width);
810}
811
812fn put_label(blob: &mut Blob, at: usize, style: LabelStyle) {
813 blob.put_u8(at + offset_of!(LabelStyle, font), style.font.code());
814 blob.put_u8(at + offset_of!(LabelStyle, color), style.color.code());
815 blob.put_u8(at + offset_of!(LabelStyle, align), style.align.code());
816 blob.put_u8(
817 at + offset_of!(LabelStyle, selectable),
818 u8::from(style.selectable),
819 );
820}
821
822fn put_image(blob: &mut Blob, at: usize, size: ImageSize) {
823 blob.put_f32(at + offset_of!(ImageSize, width), size.width);
824 blob.put_f32(at + offset_of!(ImageSize, height), size.height);
825}
826
827fn slot_offset(local: usize) -> Result<i64> {
828 i64::try_from(local)
829 .ok()
830 .and_then(|local| local.checked_mul(8))
831 .ok_or_else(|| CodegenError::new("a frame is too large"))
832}