1use serde::Serialize;
9use std::cell::RefCell;
10use treemaker_core::{Tree, TreeError};
11use wasm_bindgen::prelude::*;
12
13thread_local! {
14 static TREES: RefCell<Vec<Option<Tree>>> = const { RefCell::new(Vec::new()) };
15}
16
17#[wasm_bindgen]
18pub fn load_tmd(text: &str) -> std::result::Result<u32, JsValue> {
19 let tree = Tree::from_tmd_str(text).map_err(to_js_error)?;
20 TREES.with(|trees| {
21 let mut trees = trees.borrow_mut();
22 if let Some((idx, slot)) = trees
23 .iter_mut()
24 .enumerate()
25 .find(|(_, slot)| slot.is_none())
26 {
27 *slot = Some(tree);
28 Ok(idx as u32)
29 } else {
30 trees.push(Some(tree));
31 Ok((trees.len() - 1) as u32)
32 }
33 })
34}
35
36#[wasm_bindgen]
37pub fn tree_summary(handle: u32) -> std::result::Result<JsValue, JsValue> {
38 with_tree(handle, |tree| {
39 serde_wasm_bindgen::to_value(&tree.summary()).map_err(to_js_value)
40 })
41}
42
43#[wasm_bindgen]
44pub fn check(handle: u32) -> std::result::Result<JsValue, JsValue> {
45 tree_summary(handle)
46}
47
48#[wasm_bindgen]
49pub fn cp_status_report(handle: u32) -> std::result::Result<JsValue, JsValue> {
50 with_tree(handle, |tree| {
51 serde_wasm_bindgen::to_value(&tree.cp_status_report()).map_err(to_js_value)
52 })
53}
54
55#[wasm_bindgen]
56pub fn optimize_scale(handle: u32) -> std::result::Result<JsValue, JsValue> {
57 with_tree_mut(handle, |tree| {
58 let report = tree.optimize_scale().map_err(to_js_error)?;
59 serde_wasm_bindgen::to_value(&report).map_err(to_js_value)
60 })
61}
62
63#[wasm_bindgen]
64pub fn optimize_edges(handle: u32) -> std::result::Result<JsValue, JsValue> {
65 with_tree_mut(handle, |tree| {
66 let report = tree.optimize_edges().map_err(to_js_error)?;
67 serde_wasm_bindgen::to_value(&report).map_err(to_js_value)
68 })
69}
70
71#[wasm_bindgen]
72pub fn optimize_strain(handle: u32) -> std::result::Result<JsValue, JsValue> {
73 with_tree_mut(handle, |tree| {
74 let report = tree.optimize_strain().map_err(to_js_error)?;
75 serde_wasm_bindgen::to_value(&report).map_err(to_js_value)
76 })
77}
78
79#[wasm_bindgen]
80pub fn build_crease_pattern(handle: u32) -> std::result::Result<JsValue, JsValue> {
81 with_tree_mut(handle, |tree| {
82 tree.build_polys_and_crease_pattern().map_err(to_js_error)?;
83 serde_wasm_bindgen::to_value(&tree.summary()).map_err(to_js_value)
84 })
85}
86
87#[wasm_bindgen]
88pub fn save_tmd5(handle: u32) -> std::result::Result<String, JsValue> {
89 with_tree(handle, |tree| Ok(tree.to_tmd5_string()))
90}
91
92#[wasm_bindgen]
93pub fn free_tree(handle: u32) -> std::result::Result<(), JsValue> {
94 TREES.with(|trees| {
95 let mut trees = trees.borrow_mut();
96 let slot = trees
97 .get_mut(handle as usize)
98 .ok_or_else(|| js_error("invalid_handle", "invalid TreeHandle"))?;
99 *slot = None;
100 Ok(())
101 })
102}
103
104fn with_tree<T>(
105 handle: u32,
106 f: impl FnOnce(&Tree) -> std::result::Result<T, JsValue>,
107) -> std::result::Result<T, JsValue> {
108 TREES.with(|trees| {
109 let trees = trees.borrow();
110 let tree = trees
111 .get(handle as usize)
112 .and_then(Option::as_ref)
113 .ok_or_else(|| js_error("invalid_handle", "invalid TreeHandle"))?;
114 f(tree)
115 })
116}
117
118fn with_tree_mut<T>(
119 handle: u32,
120 f: impl FnOnce(&mut Tree) -> std::result::Result<T, JsValue>,
121) -> std::result::Result<T, JsValue> {
122 TREES.with(|trees| {
123 let mut trees = trees.borrow_mut();
124 let tree = trees
125 .get_mut(handle as usize)
126 .and_then(Option::as_mut)
127 .ok_or_else(|| js_error("invalid_handle", "invalid TreeHandle"))?;
128 f(tree)
129 })
130}
131
132#[derive(Serialize)]
133struct JsErrorEnvelope {
134 code: &'static str,
135 message: String,
136}
137
138fn to_js_error(error: TreeError) -> JsValue {
139 js_error(error.code(), error.to_string())
140}
141
142fn to_js_value(error: impl std::fmt::Display) -> JsValue {
143 js_error("js_value", error.to_string())
144}
145
146fn js_error(code: &'static str, message: impl Into<String>) -> JsValue {
147 serde_wasm_bindgen::to_value(&JsErrorEnvelope {
148 code,
149 message: message.into(),
150 })
151 .unwrap_or_else(|_| JsValue::from_str(code))
152}