sim/runtime/glasses/proofs/
halo.rs1use sim_kernel::{Error, Expr, Result};
2use sim_lib_scene::GlanceMetric;
3use sim_lib_stream_device::ModeledSource;
4use sim_lib_stream_halo::{LuaFrameBudget, diff_glance};
5use sim_lib_stream_xr::ModeledHaloMotionSource;
6use sim_lib_view::SurfaceCaps;
7use sim_lib_view_device::{
8 DeviceSurfaceCapsExt, EncodedScene, GlanceInput, GlanceState, LocalAdapter,
9};
10use sim_lib_view_spatial::{halo_glance_config, halo_glance_scene};
11use sim_value::{access, build};
12
13#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct HaloGlanceProof {
16 pub modeled_seq: u64,
18 pub glance_scene: bool,
20 pub delta_cells: usize,
22 pub delta_bytes: u32,
24 pub budget_bytes: u32,
26 pub small_delta: bool,
28 pub glyph_flash_ack: bool,
30}
31
32impl HaloGlanceProof {
33 pub fn to_expr(&self) -> Expr {
35 build::map(vec![
36 ("kind", build::qsym("glasses/sdk", "halo-glance-proof")),
37 ("modeled-seq", build::uint(self.modeled_seq)),
38 ("glance-scene", Expr::Bool(self.glance_scene)),
39 ("delta-cells", build::uint(self.delta_cells as u64)),
40 ("delta-bytes", build::uint(u64::from(self.delta_bytes))),
41 ("budget-bytes", build::uint(u64::from(self.budget_bytes))),
42 ("small-delta", Expr::Bool(self.small_delta)),
43 ("glyph-flash-ack", Expr::Bool(self.glyph_flash_ack)),
44 ])
45 }
46}
47
48pub fn prove_halo_glance() -> Result<HaloGlanceProof> {
50 let motion = ModeledHaloMotionSource.at(7);
51 let caps = SurfaceCaps::from_preset("glasses-hud", "sdk.halo")
52 .ok_or_else(|| Error::HostError("Halo surface preset missing".to_owned()))?;
53 let profile = caps.device_profile();
54 let previous = halo_glance_scene(&source_scene("21"), &profile)?;
55 let next = halo_glance_scene(&source_scene("22"), &profile)?;
56 let budget = LuaFrameBudget::new(96)?;
57 let delta = diff_glance(&previous, &next, &budget)?;
58 let acknowledged = halo_glance_config().adapt(
59 &EncodedScene::new(next.clone()),
60 &GlanceState::with_input(GlanceInput::Tap, 8),
61 &profile,
62 )?;
63
64 Ok(HaloGlanceProof {
65 modeled_seq: motion.seq(),
66 glance_scene: scene_kind(&next).as_deref() == Some("glance"),
67 delta_cells: delta.cells.len(),
68 delta_bytes: delta.bytes,
69 budget_bytes: budget.max_bytes_per_tick,
70 small_delta: delta.is_complete()
71 && delta.cells.len() <= 2
72 && delta.bytes < budget.max_bytes_per_tick,
73 glyph_flash_ack: access::field_sym(acknowledged.as_ref(), "ack-channel")
74 .is_some_and(|symbol| symbol.name.as_ref() == "glyph-flash"),
75 })
76}
77
78fn source_scene(value: &str) -> Expr {
79 sim_lib_scene::node(
80 "stack",
81 vec![
82 ("title", build::text(format!("Temperature {value}"))),
83 (
84 "metric",
85 sim_lib_scene::glance_card(
86 "Temperature",
87 Some(GlanceMetric::new("C", value)),
88 None,
89 "info",
90 1,
91 ),
92 ),
93 ("children", build::list(Vec::new())),
94 ],
95 )
96}
97
98fn scene_kind(expr: &Expr) -> Option<String> {
99 let kind = sim_lib_scene::node_kind(expr)?;
100 Some(kind.name.to_string())
101}