1use std::collections::{HashMap};
2use wasm_bindgen::prelude::*;
3use std::cell::RefCell;
4use std::mem::transmute;
5use std::hash::{Hash};
6
7thread_local!(
8 static FLOAT_CACHE: Cacher<BitwiseFloat> = Cacher::new();
9 static STRING_CACHE: Cacher<&'static str> = Cacher::new();
10 static BOOL_CACHE: Cacher<bool> = Cacher::new(); );
13
14#[doc(hidden)]
15pub trait CacheJsIntern__ {
17 fn cache_js_intern__(self) -> *mut JsValue;
18}
19
20impl CacheJsIntern__ for f64 {
21 fn cache_js_intern__(self) -> *mut JsValue {
22 FLOAT_CACHE.with(|c| {
23 c.cache(self.into())
24 })
25 }
26}
27
28impl CacheJsIntern__ for &'static str {
29 fn cache_js_intern__(self) -> *mut JsValue {
30 STRING_CACHE.with(|c| {
31 c.cache(self)
32 })
33 }
34}
35
36impl CacheJsIntern__ for bool {
37 fn cache_js_intern__(self) -> *mut JsValue {
38 BOOL_CACHE.with(|c| {
39 c.cache(self)
40 })
41 }
42}
43
44macro_rules! CacheForT64 {
45 ($t:ty) => {
46 impl CacheJsIntern__ for $t {
47 fn cache_js_intern__(self) -> *mut JsValue {
48 (self as f64).cache_js_intern__()
49 }
50 }
51 };
52}
53
54CacheForT64!(i8);
55CacheForT64!(i16);
56CacheForT64!(i32);
57CacheForT64!(u8);
58CacheForT64!(u16);
59CacheForT64!(u32);
60CacheForT64!(f32);
61
62struct Cacher<T: Eq + Hash> {
63 inner: RefCell<HashMap<T, *mut JsValue>>
64}
65
66impl<T: Eq + Hash> Cacher<T> {
67 fn new() -> Cacher<T> {
68 Cacher {
69 inner: RefCell::default()
70 }
71 }
72}
73
74impl<T: Eq + Hash> Drop for Cacher<T> {
78 fn drop(&mut self) {
79 for (_key, value) in self.inner.borrow_mut().drain() {
82 unsafe { Box::from_raw(value); }
83 }
84 }
85}
86
87impl<T: Into<JsValue> + Eq + Hash + Copy> Cacher<T> {
88 fn cache(&self, value: T) -> *mut JsValue {
89 let mut map = self.inner.borrow_mut();
90 *map.entry(value).or_insert_with(move || {
96 let js_value: JsValue = value.into();
97 Box::into_raw(Box::new(js_value))
98 })
99 }
100}
101
102
103#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
107#[repr(transparent)]
108struct BitwiseFloat(u64);
109
110impl From<BitwiseFloat> for JsValue {
111 fn from(value: BitwiseFloat) -> JsValue {
112 JsValue::from_f64(value.into())
113 }
114}
115
116impl From<f64> for BitwiseFloat {
117 fn from(value: f64) -> Self {
118 unsafe { transmute(value) }
119 }
120}
121
122impl From<BitwiseFloat> for f64 {
123 fn from(value: BitwiseFloat) -> Self {
124 unsafe { transmute(value) }
125 }
126}
127
128#[macro_export]
143macro_rules! js_intern {
144 ($value:expr) => {
145 {
146 use wasm_bindgen::JsValue;
147 use $crate::CacheJsIntern__;
148 thread_local!(
149 static INTERN: *mut JsValue = $value.cache_js_intern__();
150 );
151
152 unsafe { &*INTERN.with(|i| i.clone()) }
158 }
159 };
160}