1use sim_kernel::{Error, Expr, Result, Symbol};
10use sim_lib_intent::{field, intent_kind_of};
11
12pub fn empty_pane_lenses() -> Expr {
14 Expr::Map(Vec::new())
15}
16
17pub fn active_lens(state: &Expr, pane: &str) -> Option<Symbol> {
19 let Expr::Map(entries) = state else {
20 return None;
21 };
22 entries.iter().find_map(|(key, value)| {
23 let matches = matches!(key, Expr::Symbol(symbol) if &*symbol.name == pane);
24 match value {
25 Expr::Symbol(lens) if matches => Some(lens.clone()),
26 _ => None,
27 }
28 })
29}
30
31pub fn apply_set_lens(state: &Expr, intent: &Expr) -> Result<Expr> {
34 match intent_kind_of(intent) {
35 Some(kind) if &*kind.name == "set-lens" => {}
36 _ => {
37 return Err(Error::HostError(
38 "apply_set_lens expects an intent/set-lens".to_owned(),
39 ));
40 }
41 }
42 let pane = match field(intent, "pane") {
43 Some(Expr::Symbol(symbol)) => symbol.clone(),
44 _ => {
45 return Err(Error::HostError(
46 "intent/set-lens 'pane' must be a symbol".to_owned(),
47 ));
48 }
49 };
50 let lens = match field(intent, "lens") {
51 Some(Expr::Symbol(symbol)) => symbol.clone(),
52 _ => {
53 return Err(Error::HostError(
54 "intent/set-lens 'lens' must be a symbol".to_owned(),
55 ));
56 }
57 };
58 let mut entries = match state {
59 Expr::Map(entries) => entries.clone(),
60 _ => Vec::new(),
61 };
62 let key_matches = |key: &Expr| matches!(key, Expr::Symbol(symbol) if symbol == &pane);
63 if let Some(slot) = entries.iter_mut().find(|(key, _)| key_matches(key)) {
64 slot.1 = Expr::Symbol(lens);
65 } else {
66 entries.push((Expr::Symbol(pane), Expr::Symbol(lens)));
67 }
68 Ok(Expr::Map(entries))
69}