use std::{cell::RefCell, sync::atomic::AtomicU64};
use serde::{Deserializer, Serialize, Serializer};
use wasm_bindgen::JsValue;
use super::{transferable_types::TransferableType, WorkerMsg, WorkerMsgType};
struct SerStore {
store: Vec<JsValue>,
store_id: u64,
}
impl Default for SerStore {
fn default() -> Self {
Self {
store: vec![],
store_id: unique_id(),
}
}
}
thread_local! {
static TRANSFER_STORE_SERIALIZATION: RefCell<SerStore> = RefCell::new(SerStore::default());
}
pub(crate) fn serialize_to_worker_msg(msg_type: WorkerMsgType, data: impl Serialize) -> WorkerMsg {
let new_store = SerStore::default();
let new_store_id = new_store.store_id;
TRANSFER_STORE_SERIALIZATION.replace(new_store);
let serialized =
serde_wasm_bindgen::to_value(&data).expect("Failed to serialize message data.");
let store = TRANSFER_STORE_SERIALIZATION.take();
assert_eq!(
store.store_id, new_store_id,
"Transfer store id mismatch. leptos_workers is internally broken."
);
let underlying_transferables = js_sys::Array::new();
for underlying_transferable in store.store {
underlying_transferables.push(&underlying_transferable);
}
WorkerMsg::construct(serialized, underlying_transferables, msg_type)
}
pub fn serialize<T: TransferableType, S>(data: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
TRANSFER_STORE_SERIALIZATION.with_borrow_mut(|store| {
store.store.extend(data.underlying_transfer_objects());
});
serde_wasm_bindgen::preserve::serialize(&data.to_js_value(), serializer)
}
pub fn deserialize<'de, T: TransferableType, D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
let js_value = serde_wasm_bindgen::preserve::deserialize::<D, JsValue>(deserializer)?;
Ok(T::from_js_value(js_value))
}
fn unique_id() -> u64 {
static COUNTER: AtomicU64 = AtomicU64::new(0);
COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
}