sim_lib_web_bridge/
device_peer.rs1use sim_kernel::Symbol;
4use sim_lib_view_device::{DeviceProfile, EdgeId};
5
6use crate::{SurfaceHub, SurfaceRole};
7
8pub fn register_device_peer(
15 hub: &mut SurfaceHub,
16 session: &EdgeId,
17 profile: &DeviceProfile,
18) -> Symbol {
19 register_device_peer_with_role(hub, session, profile, SurfaceRole::Peer)
20}
21
22pub fn register_device_peer_with_role(
24 hub: &mut SurfaceHub,
25 session: &EdgeId,
26 profile: &DeviceProfile,
27 role: SurfaceRole,
28) -> Symbol {
29 let surface = device_peer_surface(session);
30 hub.register_surface_with_role(
31 surface.clone(),
32 profile.to_surface_caps(session.as_symbol().as_qualified_str()),
33 role,
34 );
35 surface
36}
37
38pub fn device_peer_surface(session: &EdgeId) -> Symbol {
40 Symbol::qualified("device/peer", session.as_symbol().as_qualified_str())
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 use sim_kernel::{Expr, NumberLiteral};
48 use sim_lib_intent::{Origin, intent};
49 use sim_lib_view::surface;
50 use sim_lib_view_device::{ConsentReceipt, DeviceProfile};
51 use sim_value::build;
52
53 fn number(value: &str) -> Expr {
54 Expr::Number(NumberLiteral {
55 domain: build::keyword("i64"),
56 canonical: value.to_owned(),
57 })
58 }
59
60 fn doc() -> Expr {
61 Expr::Map(vec![
62 (Expr::Symbol(build::keyword("a")), number("1")),
63 (Expr::Symbol(build::keyword("b")), number("2")),
64 (Expr::Symbol(build::keyword("c")), number("3")),
65 ])
66 }
67
68 fn edit(field: &str, value: Expr) -> Expr {
69 intent(
70 "edit-field",
71 Origin::human(1),
72 vec![
73 ("target", doc()),
74 (
75 "path",
76 Expr::List(vec![Expr::Vector(vec![
77 Expr::Symbol(build::keyword("k")),
78 Expr::Symbol(build::keyword(field)),
79 ])]),
80 ),
81 ("value", value),
82 ],
83 )
84 }
85
86 #[test]
87 fn device_peer_receives_committed_edits_projected_by_profile() {
88 let session = EdgeId::named("watch-route");
89 let receipt = ConsentReceipt::new(Vec::new(), 60_000, Vec::new(), session.clone(), 3);
90 assert_eq!(receipt.session, session);
91
92 let watch_caps = surface::preset("watch").unwrap();
93 let profile = DeviceProfile::from_surface_caps(&watch_caps);
94 let mut hub = SurfaceHub::new();
95 let device_surface = register_device_peer(&mut hub, &session, &profile);
96 hub.register_surface(
97 build::keyword("desktop"),
98 surface::preset("desktop").unwrap(),
99 );
100 hub.seed(build::keyword("doc"), doc());
101
102 let device_scene = hub
103 .open(
104 &device_surface,
105 build::keyword("pane"),
106 build::keyword("doc"),
107 )
108 .unwrap();
109 let desktop_scene = hub
110 .open(
111 &build::keyword("desktop"),
112 build::keyword("pane"),
113 build::keyword("doc"),
114 )
115 .unwrap();
116 assert_ne!(
117 device_scene, desktop_scene,
118 "device profile projection should differ from a dense desktop peer"
119 );
120
121 let broadcasts = hub
122 .submit(
123 &build::keyword("desktop"),
124 &build::keyword("pane"),
125 &edit("a", number("9")),
126 )
127 .unwrap();
128
129 assert!(broadcasts.iter().any(|item| item.surface == device_surface));
130 assert!(
131 broadcasts
132 .iter()
133 .any(|item| item.surface == build::keyword("desktop"))
134 );
135
136 let broadcasts = hub
137 .submit(
138 &device_surface,
139 &build::keyword("pane"),
140 &edit("b", number("8")),
141 )
142 .unwrap();
143
144 assert!(broadcasts.iter().any(|item| item.surface == device_surface));
145 assert!(
146 broadcasts
147 .iter()
148 .any(|item| item.surface == build::keyword("desktop"))
149 );
150 }
151}