Skip to main content

sim/runtime/glasses/proofs/
halo.rs

1use 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/// Result of the modeled Halo glance-diff and local-ack proof.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct HaloGlanceProof {
16    /// Sequence from the modeled Halo motion source.
17    pub modeled_seq: u64,
18    /// Whether the source reduced to `scene/glance`.
19    pub glance_scene: bool,
20    /// Changed Lua cells emitted for the small update.
21    pub delta_cells: usize,
22    /// Encoded Lua bytes emitted for the small update.
23    pub delta_bytes: u32,
24    /// Per-tick Lua byte ceiling.
25    pub budget_bytes: u32,
26    /// Whether the small content change remained a small delta.
27    pub small_delta: bool,
28    /// Whether tap acknowledgement uses `GlyphFlash`.
29    pub glyph_flash_ack: bool,
30}
31
32impl HaloGlanceProof {
33    /// Encodes the proof as expression data for cookbook recipes.
34    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
48/// Reduces modeled Halo content, diffs one glyph, and acknowledges a tap locally.
49pub 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}