notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

host_fns.rs (5699B)


      1 use crate::commands::{button_key, UiCommand};
      2 use std::collections::HashMap;
      3 use wasmer::{FunctionEnv, FunctionEnvMut, Imports, Memory, MemoryView, Store};
      4 
      5 pub struct HostEnv {
      6     pub memory: Option<Memory>,
      7     pub commands: Vec<UiCommand>,
      8     pub button_events: HashMap<String, bool>,
      9     pub button_occ: HashMap<String, u32>,
     10     pub available_width: f32,
     11     pub available_height: f32,
     12 }
     13 
     14 impl HostEnv {
     15     pub fn new() -> Self {
     16         Self {
     17             memory: None,
     18             commands: Vec::new(),
     19             button_events: HashMap::new(),
     20             button_occ: HashMap::new(),
     21             available_width: 0.0,
     22             available_height: 0.0,
     23         }
     24     }
     25 }
     26 
     27 /// Read a UTF-8 string from WASM linear memory.
     28 fn read_wasm_str(view: &MemoryView, ptr: i32, len: i32) -> Option<String> {
     29     let ptr = ptr as u64;
     30     let len = len as usize;
     31     let mut buf = vec![0u8; len];
     32     view.read(ptr, &mut buf).ok()?;
     33     String::from_utf8(buf).ok()
     34 }
     35 
     36 /// Register all host imports into the given store.
     37 pub fn create_imports(store: &mut Store, env: &FunctionEnv<HostEnv>) -> Imports {
     38     use wasmer::Function;
     39 
     40     // --- Widgets ---
     41 
     42     fn nd_label(mut env: FunctionEnvMut<HostEnv>, ptr: i32, len: i32) {
     43         let (data, store) = env.data_and_store_mut();
     44         let memory = data.memory.as_ref().expect("memory not set");
     45         let view = memory.view(&store);
     46         if let Some(text) = read_wasm_str(&view, ptr, len) {
     47             data.commands.push(UiCommand::Label(text));
     48         }
     49     }
     50 
     51     fn nd_heading(mut env: FunctionEnvMut<HostEnv>, ptr: i32, len: i32) {
     52         let (data, store) = env.data_and_store_mut();
     53         let memory = data.memory.as_ref().expect("memory not set");
     54         let view = memory.view(&store);
     55         if let Some(text) = read_wasm_str(&view, ptr, len) {
     56             data.commands.push(UiCommand::Heading(text));
     57         }
     58     }
     59 
     60     fn nd_button(mut env: FunctionEnvMut<HostEnv>, ptr: i32, len: i32) -> i32 {
     61         let (data, store) = env.data_and_store_mut();
     62         let memory = data.memory.as_ref().expect("memory not set");
     63         let view = memory.view(&store);
     64         if let Some(text) = read_wasm_str(&view, ptr, len) {
     65             let occ = data.button_occ.entry(text.clone()).or_insert(0);
     66             let key = button_key(&text, *occ);
     67             *occ += 1;
     68             let clicked = data.button_events.get(&key).copied().unwrap_or(false);
     69             data.commands.push(UiCommand::Button(text));
     70             if clicked {
     71                 1
     72             } else {
     73                 0
     74             }
     75         } else {
     76             0
     77         }
     78     }
     79 
     80     fn nd_add_space(mut env: FunctionEnvMut<HostEnv>, pixels: f32) {
     81         let (data, _store) = env.data_and_store_mut();
     82         data.commands.push(UiCommand::AddSpace(pixels));
     83     }
     84 
     85     // --- Layout queries ---
     86 
     87     fn nd_available_width(env: FunctionEnvMut<HostEnv>) -> f32 {
     88         env.data().available_width
     89     }
     90 
     91     fn nd_available_height(env: FunctionEnvMut<HostEnv>) -> f32 {
     92         env.data().available_height
     93     }
     94 
     95     // --- Drawing primitives (coordinates relative to app rect) ---
     96 
     97     fn nd_draw_rect(mut env: FunctionEnvMut<HostEnv>, x: f32, y: f32, w: f32, h: f32, color: i32) {
     98         let (data, _store) = env.data_and_store_mut();
     99         data.commands.push(UiCommand::DrawRect {
    100             x,
    101             y,
    102             w,
    103             h,
    104             color: color as u32,
    105         });
    106     }
    107 
    108     fn nd_draw_circle(mut env: FunctionEnvMut<HostEnv>, cx: f32, cy: f32, r: f32, color: i32) {
    109         let (data, _store) = env.data_and_store_mut();
    110         data.commands.push(UiCommand::DrawCircle {
    111             cx,
    112             cy,
    113             r,
    114             color: color as u32,
    115         });
    116     }
    117 
    118     fn nd_draw_line(
    119         mut env: FunctionEnvMut<HostEnv>,
    120         x1: f32,
    121         y1: f32,
    122         x2: f32,
    123         y2: f32,
    124         width: f32,
    125         color: i32,
    126     ) {
    127         let (data, _store) = env.data_and_store_mut();
    128         data.commands.push(UiCommand::DrawLine {
    129             x1,
    130             y1,
    131             x2,
    132             y2,
    133             width,
    134             color: color as u32,
    135         });
    136     }
    137 
    138     fn nd_draw_text(
    139         mut env: FunctionEnvMut<HostEnv>,
    140         x: f32,
    141         y: f32,
    142         ptr: i32,
    143         len: i32,
    144         size: f32,
    145         color: i32,
    146     ) {
    147         let (data, store) = env.data_and_store_mut();
    148         let memory = data.memory.as_ref().expect("memory not set");
    149         let view = memory.view(&store);
    150         if let Some(text) = read_wasm_str(&view, ptr, len) {
    151             data.commands.push(UiCommand::DrawText {
    152                 x,
    153                 y,
    154                 text,
    155                 size,
    156                 color: color as u32,
    157             });
    158         }
    159     }
    160 
    161     wasmer::imports! {
    162         "env" => {
    163             "nd_label" => Function::new_typed_with_env(store, env, nd_label),
    164             "nd_heading" => Function::new_typed_with_env(store, env, nd_heading),
    165             "nd_button" => Function::new_typed_with_env(store, env, nd_button),
    166             "nd_add_space" => Function::new_typed_with_env(store, env, nd_add_space),
    167             "nd_available_width" => Function::new_typed_with_env(store, env, nd_available_width),
    168             "nd_available_height" => Function::new_typed_with_env(store, env, nd_available_height),
    169             "nd_draw_rect" => Function::new_typed_with_env(store, env, nd_draw_rect),
    170             "nd_draw_circle" => Function::new_typed_with_env(store, env, nd_draw_circle),
    171             "nd_draw_line" => Function::new_typed_with_env(store, env, nd_draw_line),
    172             "nd_draw_text" => Function::new_typed_with_env(store, env, nd_draw_text),
    173         }
    174     }
    175 }