1use wasm_bindgen::prelude::wasm_bindgen;
2use std::vec;
3
4#[allow(unused_imports)]
5use wasm_bindgen::JsValue;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum JSNIKind {
9 I8,
10 I16,
11 I32,
12 I64,
13 U8,
14 U16,
15 U32,
16 U64,
17 F32,
18 F64,
19 Bool,
20 Char,
21 String,
22 VecU8,
23 Null,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub struct JSNIValue {
28 pub kind: JSNIKind,
29 pub value: u64,
30}
31
32macro_rules! impl_from_primitive {
33 ($ty:ty, $kind:expr) => {
34 impl From<$ty> for JSNIValue {
35 fn from(value: $ty) -> Self {
36 JSNIValue {
37 kind: $kind,
38 value: value as u64,
39 }
40 }
41 }
42 };
43}
44
45impl_from_primitive!(i8, JSNIKind::I8);
46impl_from_primitive!(i16, JSNIKind::I16);
47impl_from_primitive!(i32, JSNIKind::I32);
48impl_from_primitive!(i64, JSNIKind::I64);
49impl_from_primitive!(u8, JSNIKind::U8);
50impl_from_primitive!(u16, JSNIKind::U16);
51impl_from_primitive!(u32, JSNIKind::U32);
52impl_from_primitive!(u64, JSNIKind::U64);
53impl_from_primitive!(bool, JSNIKind::Bool);
54impl_from_primitive!(char, JSNIKind::Char);
55
56impl From<f32> for JSNIValue {
57 fn from(value: f32) -> Self {
58 let bytes = value.to_le_bytes();
59 JSNIValue {
60 kind: JSNIKind::F32,
61 value: ((bytes[0] as u64) << 0)
62 | ((bytes[1] as u64) << 8)
63 | ((bytes[2] as u64) << 16)
64 | ((bytes[3] as u64) << 24),
65 }
66 }
67}
68
69impl From<f64> for JSNIValue {
70 fn from(value: f64) -> Self {
71 let bytes = value.to_le_bytes();
72 JSNIValue {
73 kind: JSNIKind::F64,
74 value: ((bytes[0] as u64) << 0)
75 | ((bytes[1] as u64) << 8)
76 | ((bytes[2] as u64) << 16)
77 | ((bytes[3] as u64) << 24)
78 | ((bytes[4] as u64) << 32)
79 | ((bytes[5] as u64) << 40)
80 | ((bytes[6] as u64) << 48)
81 | ((bytes[7] as u64) << 56),
82 }
83 }
84}
85
86impl From<Vec<u8>> for JSNIValue {
87 fn from(value: Vec<u8>) -> Self {
88 let len = value.len();
89 let ptr = value.as_ptr() as *mut u8;
90 std::mem::forget(value); JSNIValue {
92 kind: JSNIKind::VecU8,
93 value: (len as u64) << 32 | ptr as u64,
95 }
96 }
97}
98
99impl From<String> for JSNIValue {
100 fn from(value: String) -> Self {
101 let len = value.len();
102 let bytes = value.into_bytes();
103 let ptr = bytes.as_ptr() as *mut u8;
104 std::mem::forget(bytes); JSNIValue {
106 kind: JSNIKind::String,
107 value: (len as u64) << 32 | ptr as u64,
108 }
109 }
110}
111
112impl JSNIValue {
113 pub fn null() -> Self {
114 JSNIValue {
115 kind: JSNIKind::Null,
116 value: 0,
117 }
118 }
119
120 pub fn to_vec(&self) ->Vec<u8> {
121 if self.kind != JSNIKind::VecU8 {
122 panic!("JSNIValue is not a Vec<u8>");
123 }
124 let ptr = self.value & 0xFFFFFFFF;
125 unsafe { *Box::from_raw(ptr as *mut Vec<u8>) }
126 }
127
128 pub fn to_string(&self) -> String {
129 if self.kind != JSNIKind::String {
130 panic!("JSNIValue is not a String");
131 }
132 let ptr = self.value & 0xFFFFFFFF;
133 let vec = unsafe { *Box::from_raw(ptr as *mut Vec<u8>) };
134 String::from_utf8(vec).unwrap()
135 }
136}
137
138pub struct JavaScriptNativeInterface {
139}
140
141#[wasm_bindgen]
142extern "C" {
143 async fn jsni_call(js_func_name: *const u8, args: *const u8, args_count: usize) -> JsValue;
144}
145
146fn vec_onto_box<T>(vec: Vec<T>) -> *mut Vec<T> {
147 Box::into_raw(Box::new(vec))
148}
149
150#[wasm_bindgen]
152pub fn alloc_jsni_value(size: usize) -> u64 {
153 let mut vec = vec![JSNIValue::null(); size];
154 let ptr = vec.as_mut_ptr() as *mut u8;
155 let vec_ptr = vec_onto_box(vec);
156 (vec_ptr as u64) << 32 | ptr as u64
157}
158
159#[wasm_bindgen]
161pub fn alloc(size: usize) -> u64 {
162 let mut vec = vec![0u8; size];
163 let ptr = vec.as_mut_ptr() as *mut u8;
164 let vec_ptr = vec_onto_box(vec);
165 (vec_ptr as u64) << 32 | ptr as u64
166}
167
168impl JavaScriptNativeInterface {
169 pub fn new() -> Self {
170 JavaScriptNativeInterface {}
171 }
172
173 fn free_args(&self, args: Vec<JSNIValue>) {
174 for arg in args {
175 match arg.kind {
176 JSNIKind::VecU8 => {
177 let len = (arg.value >> 32) as usize;
178 let ptr = (arg.value & 0xFFFFFFFF) as *mut u8;
179 unsafe { Vec::from_raw_parts(ptr, len, len) };
180 }
181 JSNIKind::String => {
182 let len = (arg.value >> 32) as usize;
183 let ptr = (arg.value & 0xFFFFFFFF) as *mut u8;
184 unsafe { String::from_raw_parts(ptr, len, len) };
185 }
186 _ => {}
187 }
188 }
189 }
190
191 pub async fn call(&mut self, js_func_name: String, args: Vec<JSNIValue>) -> Vec<JSNIValue> {
196 let js_func_name = JSNIValue::from(js_func_name);
197 let js_func_name_ptr = &js_func_name as *const JSNIValue as *const u8;
198
199 let return_values_ptr_raw = jsni_call(js_func_name_ptr, args.as_ptr() as *mut u8, args.len()).await.as_f64().unwrap();
200 self.free_args(args);
201
202 if return_values_ptr_raw < 0.0 {
203 return Vec::new();
205 }
206
207 let return_values = unsafe { Box::from_raw(return_values_ptr_raw as u64 as *mut Vec<JSNIValue>) };
208 *return_values
209 }
210}