use std::collections::{HashMap};
use wasm_bindgen::prelude::*;
use std::cell::RefCell;
use std::mem::transmute;
use std::hash::{Hash};
thread_local!(
static FLOAT_CACHE: Cacher<BitwiseFloat> = Cacher::new();
static STRING_CACHE: Cacher<&'static str> = Cacher::new();
static BOOL_CACHE: Cacher<bool> = Cacher::new(); );
#[doc(hidden)]
pub trait CacheJsIntern__ {
fn cache_js_intern__(self) -> *mut JsValue;
}
impl CacheJsIntern__ for f64 {
fn cache_js_intern__(self) -> *mut JsValue {
FLOAT_CACHE.with(|c| {
c.cache(self.into())
})
}
}
impl CacheJsIntern__ for &'static str {
fn cache_js_intern__(self) -> *mut JsValue {
STRING_CACHE.with(|c| {
c.cache(self)
})
}
}
impl CacheJsIntern__ for bool {
fn cache_js_intern__(self) -> *mut JsValue {
BOOL_CACHE.with(|c| {
c.cache(self)
})
}
}
macro_rules! CacheForT64 {
($t:ty) => {
impl CacheJsIntern__ for $t {
fn cache_js_intern__(self) -> *mut JsValue {
(self as f64).cache_js_intern__()
}
}
};
}
CacheForT64!(i8);
CacheForT64!(i16);
CacheForT64!(i32);
CacheForT64!(u8);
CacheForT64!(u16);
CacheForT64!(u32);
CacheForT64!(f32);
struct Cacher<T: Eq + Hash> {
inner: RefCell<HashMap<T, *mut JsValue>>
}
impl<T: Eq + Hash> Cacher<T> {
fn new() -> Cacher<T> {
Cacher {
inner: RefCell::default()
}
}
}
impl<T: Eq + Hash> Drop for Cacher<T> {
fn drop(&mut self) {
for (_key, value) in self.inner.borrow_mut().drain() {
unsafe { Box::from_raw(value); }
}
}
}
impl<T: Into<JsValue> + Eq + Hash + Copy> Cacher<T> {
fn cache(&self, value: T) -> *mut JsValue {
let mut map = self.inner.borrow_mut();
*map.entry(value).or_insert_with(move || {
let js_value: JsValue = value.into();
Box::into_raw(Box::new(js_value))
})
}
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
#[repr(transparent)]
struct BitwiseFloat(u64);
impl From<BitwiseFloat> for JsValue {
fn from(value: BitwiseFloat) -> JsValue {
JsValue::from_f64(value.into())
}
}
impl From<f64> for BitwiseFloat {
fn from(value: f64) -> Self {
unsafe { transmute(value) }
}
}
impl From<BitwiseFloat> for f64 {
fn from(value: BitwiseFloat) -> Self {
unsafe { transmute(value) }
}
}
#[macro_export]
macro_rules! js_intern {
($value:expr) => {
{
use wasm_bindgen::JsValue;
use $crate::CacheJsIntern__;
thread_local!(
static INTERN: *mut JsValue = $value.cache_js_intern__();
);
unsafe { &*INTERN.with(|i| i.clone()) }
}
};
}