1 pub use helper::*; 2 3 pub trait TypescriptResult: From<WasmResult> { 4 type RustType; 5 } 6 7 macro_rules! result_type { 8 ($ty:ty, $name:ident, $stringified:literal) => { 9 #[wasm_bindgen] 10 extern "C" { 11 #[wasm_bindgen(typescript_type = $stringified)] 12 pub type $name; 13 } 14 impl From<$crate::wasm_result::WasmResult> for $name { 15 fn from(other: $crate::wasm_result::WasmResult) -> Self { 16 let jsv: JsValue = other.into(); 17 $name::from(jsv) 18 } 19 } 20 impl TypescriptResult for $name { 21 type RustType = $ty; 22 } 23 }; 24 } 25 26 #[allow(dead_code)] 27 mod helper { 28 use wasm_bindgen::prelude::*; 29 use js_sys::Error as JsError; 30 use serde::Serialize; 31 use super::TypescriptResult; 32 use crate::{DriverError, CiteprocRsDriverError, CiteprocRsError, CslStyleError}; 33 use csl::StyleError; 34 35 crate::js_import_class_constructor! { 36 pub type WasmResult; 37 #[wasm_bindgen(constructor)] 38 fn new(value: JsValue) -> WasmResult; 39 } 40 js_value_err<V, E, F>(f: F) -> WasmResult where V: Into<JsValue>, E: std::error::Error, F: FnOnce() -> Result<V, E>,41 pub fn js_value_err<V, E, F>(f: F) -> WasmResult 42 where 43 V: Into<JsValue>, 44 E: std::error::Error, 45 F: FnOnce() -> Result<V, E>, 46 { 47 let res = f(); 48 let out = match res { 49 Ok(ok) => { 50 WasmResult::new(ok.into()) 51 } 52 Err(e) => { 53 WasmResult::new(JsError::new(&e.to_string()).into()) 54 } 55 }; 56 out 57 } 58 style_error_to_js_err(se: &StyleError) -> JsValue59 fn style_error_to_js_err(se: &StyleError) -> JsValue { 60 let mut string = se.to_string(); 61 let data = JsValue::from_serde(&se); 62 match data { 63 Ok(data) => CslStyleError::new(string.into(), data).into(), 64 Err(conv_err) => { 65 string.push_str(" (could not convert error data: "); 66 string.push_str(&conv_err.to_string()); 67 string.push_str(") "); 68 CiteprocRsError::new(string.into()).into() 69 }, 70 } 71 } 72 73 impl DriverError { to_js_error(&self) -> JsValue74 fn to_js_error(&self) -> JsValue { 75 match self { 76 DriverError::StyleError(se) => return style_error_to_js_err(se), 77 _ => {} 78 } 79 let mut string = self.to_string(); 80 let data = JsValue::from_serde(&self); 81 match data { 82 Ok(data) => CiteprocRsDriverError::new(string.into(), data).into(), 83 Err(conv_err) => { 84 string.push_str(" (could not convert error data: "); 85 string.push_str(&conv_err.to_string()); 86 string.push_str(") "); 87 CiteprocRsError::new(string.into()).into() 88 }, 89 } 90 } 91 } 92 93 impl From<Result<JsValue, DriverError>> for WasmResult { from(res: Result<JsValue, DriverError>) -> Self94 fn from(res: Result<JsValue, DriverError>) -> Self { 95 match res { 96 Ok(ok) => { 97 WasmResult::new(ok.into()) 98 } 99 Err(e) => { 100 WasmResult::new(e.to_js_error()) 101 } 102 } 103 } 104 } 105 js_driver_error<V, F>(f: F) -> WasmResult where V: Into<JsValue>, F: FnOnce() -> Result<V, DriverError>,106 pub fn js_driver_error<V, F>(f: F) -> WasmResult 107 where 108 V: Into<JsValue>, 109 F: FnOnce() -> Result<V, DriverError>, 110 { 111 f().map(|x| x.into()).into() 112 } 113 typescript_serde_result<R, F>(f: F) -> R where R: TypescriptResult, R::RustType: Serialize, F: FnOnce() -> Result<R::RustType, DriverError>,114 pub fn typescript_serde_result<R, F>(f: F) -> R 115 where 116 R: TypescriptResult, 117 R::RustType: Serialize, 118 F: FnOnce() -> Result<R::RustType, DriverError>, 119 { 120 let res = f() 121 .and_then(|rust| { 122 JsValue::from_serde(&rust) 123 .map_err(DriverError::from) 124 }); 125 let out: WasmResult = res.into(); 126 out.into() 127 } 128 129 } 130 131 #[allow(dead_code)] 132 mod raw { 133 //! Alternative impl with no Javascript dependency but no methods available 134 //! on the returned objects. 135 136 use wasm_bindgen::prelude::*; 137 use js_sys::Error as JsError; 138 use serde::Serialize; 139 140 pub type WasmResult = JsValue; 141 142 // From serde_wasm_bindgen 143 /// Custom bindings to avoid using fallible `Reflect` for plain objects. 144 #[wasm_bindgen] 145 extern "C" { 146 pub type Object; 147 148 #[wasm_bindgen(constructor)] new() -> Object149 pub fn new() -> Object; 150 151 #[wasm_bindgen(method, indexing_setter)] set(this: &Object, key: JsValue, value: JsValue)152 pub fn set(this: &Object, key: JsValue, value: JsValue); 153 } 154 155 thread_local! { 156 pub static OK_FIELD: JsValue = JsValue::from_str("Ok"); 157 pub static ERR_FIELD: JsValue = JsValue::from_str("Err"); 158 } 159 js_value_err<E, F>(f: F) -> JsValue where E: std::error::Error, F: FnOnce() -> Result<JsValue, E>,160 pub fn js_value_err<E, F>(f: F) -> JsValue 161 where 162 E: std::error::Error, 163 F: FnOnce() -> Result<JsValue, E>, 164 { 165 let res = f(); 166 let out = Object::new(); 167 match res { 168 Ok(ok) => { 169 out.set(OK_FIELD.with(|f| f.clone()), ok); 170 } 171 Err(e) => { 172 out.set( 173 ERR_FIELD.with(|f| f.clone()), 174 JsError::new(&e.to_string()).into(), 175 ); 176 } 177 } 178 out.into() 179 } 180 js_serde_err<T, E, F>(f: F) -> JsValue where T: Serialize, E: std::error::Error, F: FnOnce() -> Result<T, E>,181 pub fn js_serde_err<T, E, F>(f: F) -> JsValue 182 where 183 T: Serialize, 184 E: std::error::Error, 185 F: FnOnce() -> Result<T, E>, 186 { 187 let res = f(); 188 let out = Object::new(); 189 match res { 190 Ok(ok) => { 191 let value = JsValue::from_serde(&ok) 192 .expect("citeproc-wasm failed to serialize return value to JsValue"); 193 out.set(OK_FIELD.with(|f| f.clone()), value); 194 } 195 Err(e) => { 196 out.set( 197 ERR_FIELD.with(|f| f.clone()), 198 JsError::new(&e.to_string()).into(), 199 ); 200 } 201 } 202 out.into() 203 } 204 } 205 206