use crate::{react_bindings, Persisted, PersistedOrigin};
use js_sys::Reflect;
use std::{fmt::Debug, marker::PhantomData};
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt, intern};
pub struct JsRefContainer<T>(JsValue, PhantomData<T>);
impl<T: JsCast> JsRefContainer<T> {
pub fn current(&self) -> Option<T> {
self.current_untyped().dyn_into::<T>().ok()
}
pub fn current_untyped(&self) -> JsValue {
Reflect::get(&self.0, &intern("current").into())
.expect_throw("cannot read from ref container")
}
pub fn set_current(&self, value: Option<&T>) {
Reflect::set(
&self.0,
&intern("current").into(),
value.map(|t| t.as_ref()).unwrap_or(&JsValue::null()),
)
.expect_throw("cannot write into ref container");
}
}
impl<T: 'static> Persisted for JsRefContainer<T> {
fn ptr(&self) -> PersistedOrigin {
PersistedOrigin
}
}
impl<T> Debug for JsRefContainer<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("JsRefContainer").field(&self.0).finish()
}
}
impl<T> Clone for JsRefContainer<T> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl<T> AsRef<JsValue> for JsRefContainer<T> {
fn as_ref(&self) -> &JsValue {
&self.0
}
}
impl<T> From<JsRefContainer<T>> for JsValue {
fn from(value: JsRefContainer<T>) -> Self {
value.0
}
}
impl<T> From<JsValue> for JsRefContainer<T> {
fn from(value: JsValue) -> Self {
Self(value, PhantomData)
}
}
pub fn use_js_ref<T: JsCast>(init: Option<T>) -> JsRefContainer<T> {
let ref_container = react_bindings::use_ref(
&init.map(|init| init.into()).unwrap_or(JsValue::null()),
);
JsRefContainer(ref_container, PhantomData)
}