use std::cell::OnceCell;
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::mem;
use js::jsapi::{Heap, JSObject, JSTracer, Value};
use js::rust::HandleValue;
use layout_api::TrustedNodeAddress;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use script_bindings::assert::{assert_in_layout, assert_in_script};
pub(crate) use script_bindings::dom::*;
use script_bindings::reflector::DomObject;
pub(crate) use script_bindings::root::*;
use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::trace::JSTraceable;
use crate::dom::node::Node;
#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
#[repr(transparent)]
pub struct LayoutDom<'dom, T> {
value: &'dom T,
}
impl LayoutDom<'_, Node> {
pub(crate) unsafe fn from_trusted_node_address(inner: TrustedNodeAddress) -> Self {
assert_in_layout();
let TrustedNodeAddress(addr) = inner;
LayoutDom {
value: unsafe { &*(addr as *const Node) },
}
}
}
unsafe impl<'dom, T: DomObject> LayoutFromRaw<'dom, T> for LayoutDom<'dom, T> {
fn from_raw(d: &'dom T) -> Self {
LayoutDom { value: d }
}
}
impl<'dom, T> LayoutDom<'dom, T>
where
T: 'dom + DomObject,
{
pub fn unsafe_get(self) -> &'dom T {
assert_in_layout();
self.value
}
pub(crate) unsafe fn to_layout_slice(slice: &'dom [Dom<T>]) -> &'dom [LayoutDom<'dom, T>] {
let _ = mem::transmute::<Dom<T>, LayoutDom<T>>;
unsafe { &*(slice as *const [Dom<T>] as *const [LayoutDom<T>]) }
}
}
impl<'dom, T> LayoutDom<'dom, T>
where
T: Castable,
{
pub(crate) fn upcast<U>(&self) -> LayoutDom<'dom, U>
where
U: Castable,
T: DerivedFrom<U>,
{
assert_in_layout();
LayoutDom {
value: self.value.upcast::<U>(),
}
}
pub(crate) fn downcast<U>(&self) -> Option<LayoutDom<'dom, U>>
where
U: DerivedFrom<T>,
{
assert_in_layout();
self.value.downcast::<U>().map(|value| LayoutDom { value })
}
pub(crate) fn is<U>(&self) -> bool
where
U: DerivedFrom<T>,
{
assert_in_layout();
self.value.is::<U>()
}
pub(crate) unsafe fn as_ref(self) -> &'dom T {
self.value
}
}
impl<T> LayoutDom<'_, T>
where
T: DomObject,
{
pub(crate) unsafe fn get_jsobject(&self) -> *mut JSObject {
assert_in_layout();
self.value.reflector().get_jsobject().get()
}
}
impl<T> Copy for LayoutDom<'_, T> {}
impl<T> PartialEq for LayoutDom<'_, T> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.value, other.value)
}
}
impl<T> Eq for LayoutDom<'_, T> {}
impl<T> Hash for LayoutDom<'_, T> {
fn hash<H: Hasher>(&self, state: &mut H) {
(self.value as *const T).hash(state)
}
}
#[expect(clippy::non_canonical_clone_impl)]
impl<T> Clone for LayoutDom<'_, T> {
#[inline]
fn clone(&self) -> Self {
assert_in_layout();
*self
}
}
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
pub(crate) struct DomOnceCell<T: DomObject> {
ptr: OnceCell<Dom<T>>,
}
impl<T> DomOnceCell<T>
where
T: DomObject,
{
pub(crate) fn init_once<F>(&self, cb: F) -> &T
where
F: FnOnce() -> DomRoot<T>,
{
assert_in_script();
self.ptr.get_or_init(|| Dom::from_ref(&cb()))
}
}
impl<T: DomObject> Default for DomOnceCell<T> {
fn default() -> DomOnceCell<T> {
assert_in_script();
DomOnceCell {
ptr: OnceCell::new(),
}
}
}
impl<T: DomObject> MallocSizeOf for DomOnceCell<T> {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0
}
}
unsafe impl<T: DomObject> JSTraceable for DomOnceCell<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
if let Some(ptr) = self.ptr.get() {
unsafe { ptr.trace(trc) };
}
}
}
pub trait AsHandleValue<'a> {
fn as_handle_value(&'a self) -> HandleValue<'a>;
}
impl<'a> AsHandleValue<'a> for Heap<Value> {
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
fn as_handle_value(&'a self) -> HandleValue<'a> {
unsafe { HandleValue::from_marked_location(self.ptr.get() as *const _) }
}
}