mirror of
https://github.com/servo/servo.git
synced 2025-07-26 00:30:22 +01:00
Move more bindings types to script_bindings (#35620)
* Move weak references implementation to script_bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Move maplike/setlike definitions to script_bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Move base error types to script_bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Formatting. Signed-off-by: Josh Matthews <josh@joshmatthews.net> --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
0383ba9a5b
commit
381e168877
21 changed files with 435 additions and 391 deletions
|
@ -16,6 +16,7 @@ use js::jsval::UndefinedValue;
|
||||||
use js::rust::wrappers::{JS_ErrorFromException, JS_GetPendingException, JS_SetPendingException};
|
use js::rust::wrappers::{JS_ErrorFromException, JS_GetPendingException, JS_SetPendingException};
|
||||||
use js::rust::{HandleObject, HandleValue, MutableHandleValue};
|
use js::rust::{HandleObject, HandleValue, MutableHandleValue};
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
|
pub(crate) use script_bindings::error::*;
|
||||||
|
|
||||||
#[cfg(feature = "js_backtrace")]
|
#[cfg(feature = "js_backtrace")]
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
|
@ -36,74 +37,6 @@ thread_local! {
|
||||||
static LAST_EXCEPTION_BACKTRACE: DomRefCell<Option<(Option<String>, String)>> = DomRefCell::new(None);
|
static LAST_EXCEPTION_BACKTRACE: DomRefCell<Option<(Option<String>, String)>> = DomRefCell::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DOM exceptions that can be thrown by a native DOM method.
|
|
||||||
#[derive(Clone, Debug, MallocSizeOf)]
|
|
||||||
pub(crate) enum Error {
|
|
||||||
/// IndexSizeError DOMException
|
|
||||||
IndexSize,
|
|
||||||
/// NotFoundError DOMException
|
|
||||||
NotFound,
|
|
||||||
/// HierarchyRequestError DOMException
|
|
||||||
HierarchyRequest,
|
|
||||||
/// WrongDocumentError DOMException
|
|
||||||
WrongDocument,
|
|
||||||
/// InvalidCharacterError DOMException
|
|
||||||
InvalidCharacter,
|
|
||||||
/// NotSupportedError DOMException
|
|
||||||
NotSupported,
|
|
||||||
/// InUseAttributeError DOMException
|
|
||||||
InUseAttribute,
|
|
||||||
/// InvalidStateError DOMException
|
|
||||||
InvalidState,
|
|
||||||
/// SyntaxError DOMException
|
|
||||||
Syntax,
|
|
||||||
/// NamespaceError DOMException
|
|
||||||
Namespace,
|
|
||||||
/// InvalidAccessError DOMException
|
|
||||||
InvalidAccess,
|
|
||||||
/// SecurityError DOMException
|
|
||||||
Security,
|
|
||||||
/// NetworkError DOMException
|
|
||||||
Network,
|
|
||||||
/// AbortError DOMException
|
|
||||||
Abort,
|
|
||||||
/// TimeoutError DOMException
|
|
||||||
Timeout,
|
|
||||||
/// InvalidNodeTypeError DOMException
|
|
||||||
InvalidNodeType,
|
|
||||||
/// DataCloneError DOMException
|
|
||||||
DataClone,
|
|
||||||
/// NoModificationAllowedError DOMException
|
|
||||||
NoModificationAllowed,
|
|
||||||
/// QuotaExceededError DOMException
|
|
||||||
QuotaExceeded,
|
|
||||||
/// TypeMismatchError DOMException
|
|
||||||
TypeMismatch,
|
|
||||||
/// InvalidModificationError DOMException
|
|
||||||
InvalidModification,
|
|
||||||
/// NotReadableError DOMException
|
|
||||||
NotReadable,
|
|
||||||
/// DataError DOMException
|
|
||||||
Data,
|
|
||||||
/// OperationError DOMException
|
|
||||||
Operation,
|
|
||||||
|
|
||||||
/// TypeError JavaScript Error
|
|
||||||
Type(String),
|
|
||||||
/// RangeError JavaScript Error
|
|
||||||
Range(String),
|
|
||||||
|
|
||||||
/// A JavaScript exception is already pending.
|
|
||||||
JSFailed,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The return type for IDL operations that can throw DOM exceptions.
|
|
||||||
pub(crate) type Fallible<T> = Result<T, Error>;
|
|
||||||
|
|
||||||
/// The return type for IDL operations that can throw DOM exceptions and
|
|
||||||
/// return `()`.
|
|
||||||
pub(crate) type ErrorResult = Fallible<()>;
|
|
||||||
|
|
||||||
/// Set a pending exception for the given `result` on `cx`.
|
/// Set a pending exception for the given `result` on `cx`.
|
||||||
pub(crate) fn throw_dom_exception(
|
pub(crate) fn throw_dom_exception(
|
||||||
cx: SafeJSContext,
|
cx: SafeJSContext,
|
||||||
|
@ -341,15 +274,14 @@ pub(crate) fn throw_constructor_without_new(cx: SafeJSContext, name: &str) {
|
||||||
unsafe { throw_type_error(*cx, &error) };
|
unsafe { throw_type_error(*cx, &error) };
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
pub(crate) trait ErrorToJsval {
|
||||||
|
fn to_jsval(self, cx: SafeJSContext, global: &GlobalScope, rval: MutableHandleValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorToJsval for Error {
|
||||||
/// Convert this error value to a JS value, consuming it in the process.
|
/// Convert this error value to a JS value, consuming it in the process.
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
pub(crate) fn to_jsval(
|
fn to_jsval(self, cx: SafeJSContext, global: &GlobalScope, rval: MutableHandleValue) {
|
||||||
self,
|
|
||||||
cx: SafeJSContext,
|
|
||||||
global: &GlobalScope,
|
|
||||||
rval: MutableHandleValue,
|
|
||||||
) {
|
|
||||||
match self {
|
match self {
|
||||||
Error::JSFailed => (),
|
Error::JSFailed => (),
|
||||||
_ => unsafe { assert!(!JS_IsExceptionPending(*cx)) },
|
_ => unsafe { assert!(!JS_IsExceptionPending(*cx)) },
|
||||||
|
|
|
@ -17,6 +17,7 @@ use js::jsapi::{Heap, JSObject};
|
||||||
use js::jsval::UndefinedValue;
|
use js::jsval::UndefinedValue;
|
||||||
use js::rust::{HandleObject, HandleValue, MutableHandleObject};
|
use js::rust::{HandleObject, HandleValue, MutableHandleObject};
|
||||||
use script_bindings::conversions::IDLInterface;
|
use script_bindings::conversions::IDLInterface;
|
||||||
|
pub(crate) use script_bindings::iterable::*;
|
||||||
use script_bindings::utils::DOMClass;
|
use script_bindings::utils::DOMClass;
|
||||||
|
|
||||||
use crate::dom::bindings::codegen::Bindings::IterableIteratorBinding::{
|
use crate::dom::bindings::codegen::Bindings::IterableIteratorBinding::{
|
||||||
|
@ -31,31 +32,6 @@ use crate::dom::bindings::trace::{JSTraceable, NoTrace, RootedTraceableBox};
|
||||||
use crate::script_runtime::{CanGc, JSContext};
|
use crate::script_runtime::{CanGc, JSContext};
|
||||||
use crate::DomTypes;
|
use crate::DomTypes;
|
||||||
|
|
||||||
/// The values that an iterator will iterate over.
|
|
||||||
#[derive(JSTraceable, MallocSizeOf)]
|
|
||||||
pub(crate) enum IteratorType {
|
|
||||||
/// The keys of the iterable object.
|
|
||||||
Keys,
|
|
||||||
/// The values of the iterable object.
|
|
||||||
Values,
|
|
||||||
/// The keys and values of the iterable object combined.
|
|
||||||
Entries,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A DOM object that can be iterated over using a pair value iterator.
|
|
||||||
pub(crate) trait Iterable {
|
|
||||||
/// The type of the key of the iterator pair.
|
|
||||||
type Key: ToJSValConvertible;
|
|
||||||
/// The type of the value of the iterator pair.
|
|
||||||
type Value: ToJSValConvertible;
|
|
||||||
/// Return the number of entries that can be iterated over.
|
|
||||||
fn get_iterable_length(&self) -> u32;
|
|
||||||
/// Return the value at the provided index.
|
|
||||||
fn get_value_at_index(&self, index: u32) -> Self::Value;
|
|
||||||
/// Return the key at the provided index.
|
|
||||||
fn get_key_at_index(&self, index: u32) -> Self::Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator over the iterable entries of a given DOM interface.
|
/// An iterator over the iterable entries of a given DOM interface.
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub(crate) struct IterableIterator<
|
pub(crate) struct IterableIterator<
|
||||||
|
@ -162,14 +138,6 @@ impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlob
|
||||||
) -> Root<Dom<Self>> = T::ITER_WRAP;
|
) -> Root<Dom<Self>> = T::ITER_WRAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A version of the [IDLInterface] trait that is specific to types that have
|
|
||||||
/// iterators defined for them. This allows the `script` crate to define the
|
|
||||||
/// derives check for the concrete interface type, while the [IteratableIterator]
|
|
||||||
/// type defined in this module can be parameterized over an unknown generic.
|
|
||||||
pub trait IteratorDerives {
|
|
||||||
fn derives(class: &'static DOMClass) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dict_return(
|
fn dict_return(
|
||||||
cx: JSContext,
|
cx: JSContext,
|
||||||
mut result: MutableHandleObject,
|
mut result: MutableHandleObject,
|
||||||
|
|
|
@ -11,67 +11,10 @@ use std::hash::Hash;
|
||||||
|
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
use js::conversions::ToJSValConvertible;
|
use js::conversions::ToJSValConvertible;
|
||||||
|
pub(crate) use script_bindings::like::*;
|
||||||
|
|
||||||
use super::iterable::Iterable;
|
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
|
|
||||||
/// Every Setlike dom_struct must implement this to provide access to underlying storage
|
|
||||||
/// so codegen can automatically generate all setlike methods
|
|
||||||
///
|
|
||||||
/// In case you use a type that implements Setlike as underlying storage it's recommended to use `setlike` macro.
|
|
||||||
// In webidl: `setlike<Key>`
|
|
||||||
pub(crate) trait Setlike {
|
|
||||||
/// The type of the key of the set.
|
|
||||||
type Key: ToJSValConvertible + Clone; // clone is for impl<T: Setlike> Maplike for T
|
|
||||||
|
|
||||||
fn get_index(&self, index: u32) -> Option<Self::Key>;
|
|
||||||
|
|
||||||
fn size(&self) -> u32;
|
|
||||||
fn add(&self, key: Self::Key);
|
|
||||||
fn has(&self, key: Self::Key) -> bool;
|
|
||||||
fn clear(&self);
|
|
||||||
fn delete(&self, key: Self::Key) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we can only have one iterable for T
|
|
||||||
// so we have impl<T: Maplike> Iterable for T
|
|
||||||
// and minimal:
|
|
||||||
impl<T: Setlike> Maplike for T {
|
|
||||||
type Key = <T as Setlike>::Key;
|
|
||||||
|
|
||||||
type Value = <T as Setlike>::Key;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_index(&self, index: u32) -> Option<(Self::Key, Self::Value)> {
|
|
||||||
self.get_index(index).map(|k| (k.clone(), k))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, _key: Self::Key) -> Option<Self::Value> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn size(&self) -> u32 {
|
|
||||||
self.size()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&self, _key: Self::Key, _value: Self::Value) {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has(&self, _key: Self::Key) -> bool {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(&self) {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete(&self, _key: Self::Key) -> bool {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K> Setlike for DomRefCell<IndexSet<K>>
|
impl<K> Setlike for DomRefCell<IndexSet<K>>
|
||||||
where
|
where
|
||||||
K: ToJSValConvertible + Eq + PartialEq + Hash + Clone,
|
K: ToJSValConvertible + Eq + PartialEq + Hash + Clone,
|
||||||
|
@ -155,51 +98,6 @@ macro_rules! setlike {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Every Maplike dom_struct must implement this
|
|
||||||
/// to provide access to underlying storage
|
|
||||||
/// so codegen can automatically generate all maplike methods
|
|
||||||
///
|
|
||||||
/// In case you use a type that implements Maplike as underlying storage it's recommended to use `maplike` macro.
|
|
||||||
// In webidl: `maplike<Key, Value>`
|
|
||||||
pub(crate) trait Maplike {
|
|
||||||
/// The type of the key of the map.
|
|
||||||
type Key: ToJSValConvertible;
|
|
||||||
/// The type of the value of the map.
|
|
||||||
type Value: ToJSValConvertible;
|
|
||||||
|
|
||||||
fn get_index(&self, index: u32) -> Option<(Self::Key, Self::Value)>;
|
|
||||||
|
|
||||||
fn get(&self, key: Self::Key) -> Option<Self::Value>;
|
|
||||||
fn size(&self) -> u32;
|
|
||||||
fn set(&self, key: Self::Key, value: Self::Value);
|
|
||||||
fn has(&self, key: Self::Key) -> bool;
|
|
||||||
fn clear(&self);
|
|
||||||
fn delete(&self, key: Self::Key) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Maplike> Iterable for T {
|
|
||||||
type Key = T::Key;
|
|
||||||
|
|
||||||
type Value = T::Value;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_iterable_length(&self) -> u32 {
|
|
||||||
self.size()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_value_at_index(&self, index: u32) -> Self::Value {
|
|
||||||
// SAFETY: we are checking bounds manually
|
|
||||||
self.get_index(index).unwrap().1
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_key_at_index(&self, index: u32) -> Self::Key {
|
|
||||||
// SAFETY: we are checking bounds manually
|
|
||||||
self.get_index(index).unwrap().0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K, V> Maplike for DomRefCell<IndexMap<K, V>>
|
impl<K, V> Maplike for DomRefCell<IndexMap<K, V>>
|
||||||
where
|
where
|
||||||
K: ToJSValConvertible + Eq + PartialEq + Hash + Clone,
|
K: ToJSValConvertible + Eq + PartialEq + Hash + Clone,
|
||||||
|
|
|
@ -60,7 +60,6 @@ use tendril::TendrilSink;
|
||||||
use webxr_api::{Finger, Hand};
|
use webxr_api::{Finger, Hand};
|
||||||
|
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::error::Error;
|
|
||||||
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||||
use crate::dom::bindings::reflector::DomObject;
|
use crate::dom::bindings::reflector::DomObject;
|
||||||
use crate::dom::htmlimageelement::SourceSet;
|
use crate::dom::htmlimageelement::SourceSet;
|
||||||
|
@ -352,7 +351,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_no_jsmanaged_fields!(Error);
|
|
||||||
unsafe_no_jsmanaged_fields!(TrustedPromise);
|
unsafe_no_jsmanaged_fields!(TrustedPromise);
|
||||||
|
|
||||||
unsafe_no_jsmanaged_fields!(WindowProxyHandler);
|
unsafe_no_jsmanaged_fields!(WindowProxyHandler);
|
||||||
|
|
|
@ -2,169 +2,18 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
//! Weak-referenceable JS-managed DOM objects.
|
use std::cell::UnsafeCell;
|
||||||
//!
|
use std::mem;
|
||||||
//! IDL interfaces marked as `weakReferenceable` in `Bindings.conf`
|
|
||||||
//! automatically implement the `WeakReferenceable` trait in codegen.
|
|
||||||
//! The instance object is responsible for setting `None` in its own
|
|
||||||
//! own `WeakBox` when it is collected, through the `DOM_WEAK_SLOT`
|
|
||||||
//! slot. When all associated `WeakRef` values are dropped, the
|
|
||||||
//! `WeakBox` itself is dropped too.
|
|
||||||
|
|
||||||
use std::cell::{Cell, UnsafeCell};
|
|
||||||
use std::ops::{Deref, DerefMut, Drop};
|
use std::ops::{Deref, DerefMut, Drop};
|
||||||
use std::{mem, ptr};
|
|
||||||
|
|
||||||
use js::glue::JS_GetReservedSlot;
|
use js::jsapi::JSTracer;
|
||||||
use js::jsapi::{JSTracer, JS_SetReservedSlot};
|
|
||||||
use js::jsval::{PrivateValue, UndefinedValue};
|
|
||||||
use libc::c_void;
|
|
||||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||||
|
pub use script_bindings::weakref::*;
|
||||||
|
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::reflector::DomObject;
|
|
||||||
use crate::dom::bindings::root::DomRoot;
|
use crate::dom::bindings::root::DomRoot;
|
||||||
use crate::dom::bindings::trace::JSTraceable;
|
use crate::dom::bindings::trace::JSTraceable;
|
||||||
|
|
||||||
/// The index of the slot wherein a pointer to the weak holder cell is
|
|
||||||
/// stored for weak-referenceable bindings. We use slot 1 for holding it,
|
|
||||||
/// this is unsafe for globals, we disallow weak-referenceable globals
|
|
||||||
/// directly in codegen.
|
|
||||||
pub(crate) const DOM_WEAK_SLOT: u32 = 1;
|
|
||||||
|
|
||||||
/// A weak reference to a JS-managed DOM object.
|
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
|
|
||||||
pub(crate) struct WeakRef<T: WeakReferenceable> {
|
|
||||||
ptr: ptr::NonNull<WeakBox<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The inner box of weak references, public for the finalization in codegen.
|
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
|
||||||
pub(crate) struct WeakBox<T: WeakReferenceable> {
|
|
||||||
/// The reference count. When it reaches zero, the `value` field should
|
|
||||||
/// have already been set to `None`. The pointee contributes one to the count.
|
|
||||||
pub(crate) count: Cell<usize>,
|
|
||||||
/// The pointer to the JS-managed object, set to None when it is collected.
|
|
||||||
pub(crate) value: Cell<Option<ptr::NonNull<T>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait implemented by weak-referenceable interfaces.
|
|
||||||
pub(crate) trait WeakReferenceable: DomObject + Sized {
|
|
||||||
/// Downgrade a DOM object reference to a weak one.
|
|
||||||
fn downgrade(&self) -> WeakRef<Self> {
|
|
||||||
unsafe {
|
|
||||||
let object = self.reflector().get_jsobject().get();
|
|
||||||
let mut slot = UndefinedValue();
|
|
||||||
JS_GetReservedSlot(object, DOM_WEAK_SLOT, &mut slot);
|
|
||||||
let mut ptr = slot.to_private() as *mut WeakBox<Self>;
|
|
||||||
if ptr.is_null() {
|
|
||||||
trace!("Creating new WeakBox holder for {:p}.", self);
|
|
||||||
ptr = Box::into_raw(Box::new(WeakBox {
|
|
||||||
count: Cell::new(1),
|
|
||||||
value: Cell::new(Some(ptr::NonNull::from(self))),
|
|
||||||
}));
|
|
||||||
let val = PrivateValue(ptr as *const c_void);
|
|
||||||
JS_SetReservedSlot(object, DOM_WEAK_SLOT, &val);
|
|
||||||
}
|
|
||||||
let box_ = &*ptr;
|
|
||||||
assert!(box_.value.get().is_some());
|
|
||||||
let new_count = box_.count.get() + 1;
|
|
||||||
trace!(
|
|
||||||
"Incrementing WeakBox refcount for {:p} to {}.",
|
|
||||||
self,
|
|
||||||
new_count
|
|
||||||
);
|
|
||||||
box_.count.set(new_count);
|
|
||||||
WeakRef {
|
|
||||||
ptr: ptr::NonNull::new_unchecked(ptr),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WeakReferenceable> WeakRef<T> {
|
|
||||||
/// Create a new weak reference from a `WeakReferenceable` interface instance.
|
|
||||||
/// This is just a convenience wrapper around `<T as WeakReferenceable>::downgrade`
|
|
||||||
/// to not have to import `WeakReferenceable`.
|
|
||||||
pub(crate) fn new(value: &T) -> Self {
|
|
||||||
value.downgrade()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// DomRoot a weak reference. Returns `None` if the object was already collected.
|
|
||||||
pub(crate) fn root(&self) -> Option<DomRoot<T>> {
|
|
||||||
unsafe { &*self.ptr.as_ptr() }
|
|
||||||
.value
|
|
||||||
.get()
|
|
||||||
.map(|ptr| unsafe { DomRoot::from_ref(&*ptr.as_ptr()) })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return whether the weakly-referenced object is still alive.
|
|
||||||
pub(crate) fn is_alive(&self) -> bool {
|
|
||||||
unsafe { &*self.ptr.as_ptr() }.value.get().is_some()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WeakReferenceable> Clone for WeakRef<T> {
|
|
||||||
fn clone(&self) -> WeakRef<T> {
|
|
||||||
unsafe {
|
|
||||||
let box_ = &*self.ptr.as_ptr();
|
|
||||||
let new_count = box_.count.get() + 1;
|
|
||||||
box_.count.set(new_count);
|
|
||||||
WeakRef { ptr: self.ptr }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WeakReferenceable> MallocSizeOf for WeakRef<T> {
|
|
||||||
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WeakReferenceable> PartialEq for WeakRef<T> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
unsafe {
|
|
||||||
(*self.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) ==
|
|
||||||
(*other.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WeakReferenceable> PartialEq<T> for WeakRef<T> {
|
|
||||||
fn eq(&self, other: &T) -> bool {
|
|
||||||
unsafe {
|
|
||||||
match self.ptr.as_ref().value.get() {
|
|
||||||
Some(ptr) => ptr::eq(ptr.as_ptr(), other),
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: WeakReferenceable> JSTraceable for WeakRef<T> {
|
|
||||||
unsafe fn trace(&self, _: *mut JSTracer) {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WeakReferenceable> Drop for WeakRef<T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
let (count, value) = {
|
|
||||||
let weak_box = &*self.ptr.as_ptr();
|
|
||||||
assert!(weak_box.count.get() > 0);
|
|
||||||
let count = weak_box.count.get() - 1;
|
|
||||||
weak_box.count.set(count);
|
|
||||||
(count, weak_box.value.get())
|
|
||||||
};
|
|
||||||
if count == 0 {
|
|
||||||
assert!(value.is_none());
|
|
||||||
mem::drop(Box::from_raw(self.ptr.as_ptr()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A mutable weak reference to a JS-managed DOM object. On tracing,
|
/// A mutable weak reference to a JS-managed DOM object. On tracing,
|
||||||
/// the contained weak reference is dropped if the pointee was already
|
/// the contained weak reference is dropped if the pointee was already
|
||||||
/// collected.
|
/// collected.
|
||||||
|
|
|
@ -12,6 +12,7 @@ use style::stylesheets::{
|
||||||
RulesMutateError, StylesheetLoader as StyleStylesheetLoader,
|
RulesMutateError, StylesheetLoader as StyleStylesheetLoader,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::conversions::Convert;
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::codegen::Bindings::CSSRuleListBinding::CSSRuleListMethods;
|
use crate::dom::bindings::codegen::Bindings::CSSRuleListBinding::CSSRuleListMethods;
|
||||||
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
|
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||||
|
@ -27,9 +28,9 @@ use crate::stylesheet_loader::StylesheetLoader;
|
||||||
|
|
||||||
unsafe_no_jsmanaged_fields!(RulesSource);
|
unsafe_no_jsmanaged_fields!(RulesSource);
|
||||||
|
|
||||||
impl From<RulesMutateError> for Error {
|
impl Convert<Error> for RulesMutateError {
|
||||||
fn from(other: RulesMutateError) -> Self {
|
fn convert(self) -> Error {
|
||||||
match other {
|
match self {
|
||||||
RulesMutateError::Syntax => Error::Syntax,
|
RulesMutateError::Syntax => Error::Syntax,
|
||||||
RulesMutateError::IndexSize => Error::IndexSize,
|
RulesMutateError::IndexSize => Error::IndexSize,
|
||||||
RulesMutateError::HierarchyRequest => Error::HierarchyRequest,
|
RulesMutateError::HierarchyRequest => Error::HierarchyRequest,
|
||||||
|
@ -124,16 +125,18 @@ impl CSSRuleList {
|
||||||
let loader = owner
|
let loader = owner
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|element| StylesheetLoader::for_element(element));
|
.map(|element| StylesheetLoader::for_element(element));
|
||||||
let new_rule = css_rules.insert_rule(
|
let new_rule = css_rules
|
||||||
&parent_stylesheet.shared_lock,
|
.insert_rule(
|
||||||
rule,
|
&parent_stylesheet.shared_lock,
|
||||||
&parent_stylesheet.contents,
|
rule,
|
||||||
index,
|
&parent_stylesheet.contents,
|
||||||
containing_rule_types,
|
index,
|
||||||
parse_relative_rule_type,
|
containing_rule_types,
|
||||||
loader.as_ref().map(|l| l as &dyn StyleStylesheetLoader),
|
parse_relative_rule_type,
|
||||||
AllowImportRules::Yes,
|
loader.as_ref().map(|l| l as &dyn StyleStylesheetLoader),
|
||||||
)?;
|
AllowImportRules::Yes,
|
||||||
|
)
|
||||||
|
.map_err(Convert::convert)?;
|
||||||
|
|
||||||
let parent_stylesheet = &*self.parent_stylesheet;
|
let parent_stylesheet = &*self.parent_stylesheet;
|
||||||
let dom_rule = CSSRule::new_specific(window, parent_stylesheet, new_rule, can_gc);
|
let dom_rule = CSSRule::new_specific(window, parent_stylesheet, new_rule, can_gc);
|
||||||
|
@ -150,7 +153,10 @@ impl CSSRuleList {
|
||||||
|
|
||||||
match self.rules {
|
match self.rules {
|
||||||
RulesSource::Rules(ref css_rules) => {
|
RulesSource::Rules(ref css_rules) => {
|
||||||
css_rules.write_with(&mut guard).remove_rule(index)?;
|
css_rules
|
||||||
|
.write_with(&mut guard)
|
||||||
|
.remove_rule(index)
|
||||||
|
.map_err(Convert::convert)?;
|
||||||
let mut dom_rules = self.dom_rules.borrow_mut();
|
let mut dom_rules = self.dom_rules.borrow_mut();
|
||||||
if let Some(r) = dom_rules[index].get() {
|
if let Some(r) = dom_rules[index].get() {
|
||||||
r.detach()
|
r.detach()
|
||||||
|
|
|
@ -31,7 +31,7 @@ use js::rust::wrappers::{
|
||||||
use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
|
use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
|
||||||
|
|
||||||
use crate::dom::bindings::conversions::root_from_object;
|
use crate::dom::bindings::conversions::root_from_object;
|
||||||
use crate::dom::bindings::error::Error;
|
use crate::dom::bindings::error::{Error, ErrorToJsval};
|
||||||
use crate::dom::bindings::reflector::{DomGlobal, DomObject, MutDomObject, Reflector};
|
use crate::dom::bindings::reflector::{DomGlobal, DomObject, MutDomObject, Reflector};
|
||||||
use crate::dom::bindings::settings_stack::AutoEntryScript;
|
use crate::dom::bindings::settings_stack::AutoEntryScript;
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
|
|
@ -24,7 +24,7 @@ use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultReaderBinding:
|
||||||
use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultControllerBinding::ReadableStreamDefaultController_Binding::ReadableStreamDefaultControllerMethods;
|
use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultControllerBinding::ReadableStreamDefaultController_Binding::ReadableStreamDefaultControllerMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::UnderlyingSourceBinding::UnderlyingSource as JsUnderlyingSource;
|
use crate::dom::bindings::codegen::Bindings::UnderlyingSourceBinding::UnderlyingSource as JsUnderlyingSource;
|
||||||
use crate::dom::bindings::conversions::{ConversionBehavior, ConversionResult};
|
use crate::dom::bindings::conversions::{ConversionBehavior, ConversionResult};
|
||||||
use crate::dom::bindings::error::Error;
|
use crate::dom::bindings::error::{Error, ErrorToJsval};
|
||||||
use crate::dom::bindings::import::module::Fallible;
|
use crate::dom::bindings::import::module::Fallible;
|
||||||
use crate::dom::bindings::codegen::UnionTypes::ReadableStreamDefaultReaderOrReadableStreamBYOBReader as ReadableStreamReader;
|
use crate::dom::bindings::codegen::UnionTypes::ReadableStreamDefaultReaderOrReadableStreamBYOBReader as ReadableStreamReader;
|
||||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
|
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
|
||||||
|
|
|
@ -21,7 +21,7 @@ use super::bindings::reflector::reflect_dom_object;
|
||||||
use super::readablestreamgenericreader::ReadableStreamGenericReader;
|
use super::readablestreamgenericreader::ReadableStreamGenericReader;
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::codegen::Bindings::ReadableStreamBYOBReaderBinding::ReadableStreamBYOBReaderMethods;
|
use crate::dom::bindings::codegen::Bindings::ReadableStreamBYOBReaderBinding::ReadableStreamBYOBReaderMethods;
|
||||||
use crate::dom::bindings::error::Error;
|
use crate::dom::bindings::error::{Error, ErrorToJsval};
|
||||||
use crate::dom::bindings::import::module::Fallible;
|
use crate::dom::bindings::import::module::Fallible;
|
||||||
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector};
|
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector};
|
||||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::dom::bindings::buffer_source::create_buffer_source;
|
||||||
use crate::dom::bindings::callback::ExceptionHandling;
|
use crate::dom::bindings::callback::ExceptionHandling;
|
||||||
use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultControllerBinding::ReadableStreamDefaultControllerMethods;
|
use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultControllerBinding::ReadableStreamDefaultControllerMethods;
|
||||||
use crate::dom::bindings::codegen::UnionTypes::ReadableStreamDefaultControllerOrReadableByteStreamController as Controller;
|
use crate::dom::bindings::codegen::UnionTypes::ReadableStreamDefaultControllerOrReadableByteStreamController as Controller;
|
||||||
use crate::dom::bindings::import::module::{throw_dom_exception, Error, Fallible};
|
use crate::dom::bindings::error::{throw_dom_exception, Error, ErrorToJsval, Fallible};
|
||||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomGlobal, Reflector};
|
use crate::dom::bindings::reflector::{reflect_dom_object, DomGlobal, Reflector};
|
||||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||||
use crate::dom::bindings::trace::RootedTraceableBox;
|
use crate::dom::bindings::trace::RootedTraceableBox;
|
||||||
|
|
|
@ -19,7 +19,7 @@ use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultReaderBinding::{
|
use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultReaderBinding::{
|
||||||
ReadableStreamDefaultReaderMethods, ReadableStreamReadResult,
|
ReadableStreamDefaultReaderMethods, ReadableStreamReadResult,
|
||||||
};
|
};
|
||||||
use crate::dom::bindings::error::Error;
|
use crate::dom::bindings::error::{Error, ErrorToJsval};
|
||||||
use crate::dom::bindings::import::module::Fallible;
|
use crate::dom::bindings::import::module::Fallible;
|
||||||
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector};
|
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector};
|
||||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||||
|
|
|
@ -9,7 +9,7 @@ use js::rust::HandleValue as SafeHandleValue;
|
||||||
|
|
||||||
use super::readablestream::ReaderType;
|
use super::readablestream::ReaderType;
|
||||||
use super::types::ReadableStream;
|
use super::types::ReadableStream;
|
||||||
use crate::dom::bindings::error::Error;
|
use crate::dom::bindings::error::{Error, ErrorToJsval};
|
||||||
use crate::dom::bindings::import::module::Fallible;
|
use crate::dom::bindings::import::module::Fallible;
|
||||||
use crate::dom::bindings::reflector::DomGlobal;
|
use crate::dom::bindings::reflector::DomGlobal;
|
||||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::dom::bindings::codegen::Bindings::UnderlyingSinkBinding::{
|
||||||
UnderlyingSinkStartCallback, UnderlyingSinkWriteCallback,
|
UnderlyingSinkStartCallback, UnderlyingSinkWriteCallback,
|
||||||
};
|
};
|
||||||
use crate::dom::bindings::codegen::Bindings::WritableStreamDefaultControllerBinding::WritableStreamDefaultControllerMethods;
|
use crate::dom::bindings::codegen::Bindings::WritableStreamDefaultControllerBinding::WritableStreamDefaultControllerMethods;
|
||||||
use crate::dom::bindings::error::Error;
|
use crate::dom::bindings::error::{Error, ErrorToJsval};
|
||||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||||
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
|
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
|
|
@ -10,7 +10,7 @@ use js::jsval::UndefinedValue;
|
||||||
use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue};
|
use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue};
|
||||||
|
|
||||||
use crate::dom::bindings::codegen::Bindings::WritableStreamDefaultWriterBinding::WritableStreamDefaultWriterMethods;
|
use crate::dom::bindings::codegen::Bindings::WritableStreamDefaultWriterBinding::WritableStreamDefaultWriterMethods;
|
||||||
use crate::dom::bindings::error::Error;
|
use crate::dom::bindings::error::{Error, ErrorToJsval};
|
||||||
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector};
|
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector};
|
||||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
|
|
@ -50,7 +50,7 @@ use crate::document_loader::LoadType;
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
|
use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
|
||||||
use crate::dom::bindings::conversions::jsstring_to_str;
|
use crate::dom::bindings::conversions::jsstring_to_str;
|
||||||
use crate::dom::bindings::error::{report_pending_exception, Error};
|
use crate::dom::bindings::error::{report_pending_exception, Error, ErrorToJsval};
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::refcounted::Trusted;
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
use crate::dom::bindings::reflector::{DomGlobal, DomObject};
|
use crate::dom::bindings::reflector::{DomGlobal, DomObject};
|
||||||
|
|
71
components/script_bindings/error.rs
Normal file
71
components/script_bindings/error.rs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/// DOM exceptions that can be thrown by a native DOM method.
|
||||||
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
|
pub enum Error {
|
||||||
|
/// IndexSizeError DOMException
|
||||||
|
IndexSize,
|
||||||
|
/// NotFoundError DOMException
|
||||||
|
NotFound,
|
||||||
|
/// HierarchyRequestError DOMException
|
||||||
|
HierarchyRequest,
|
||||||
|
/// WrongDocumentError DOMException
|
||||||
|
WrongDocument,
|
||||||
|
/// InvalidCharacterError DOMException
|
||||||
|
InvalidCharacter,
|
||||||
|
/// NotSupportedError DOMException
|
||||||
|
NotSupported,
|
||||||
|
/// InUseAttributeError DOMException
|
||||||
|
InUseAttribute,
|
||||||
|
/// InvalidStateError DOMException
|
||||||
|
InvalidState,
|
||||||
|
/// SyntaxError DOMException
|
||||||
|
Syntax,
|
||||||
|
/// NamespaceError DOMException
|
||||||
|
Namespace,
|
||||||
|
/// InvalidAccessError DOMException
|
||||||
|
InvalidAccess,
|
||||||
|
/// SecurityError DOMException
|
||||||
|
Security,
|
||||||
|
/// NetworkError DOMException
|
||||||
|
Network,
|
||||||
|
/// AbortError DOMException
|
||||||
|
Abort,
|
||||||
|
/// TimeoutError DOMException
|
||||||
|
Timeout,
|
||||||
|
/// InvalidNodeTypeError DOMException
|
||||||
|
InvalidNodeType,
|
||||||
|
/// DataCloneError DOMException
|
||||||
|
DataClone,
|
||||||
|
/// NoModificationAllowedError DOMException
|
||||||
|
NoModificationAllowed,
|
||||||
|
/// QuotaExceededError DOMException
|
||||||
|
QuotaExceeded,
|
||||||
|
/// TypeMismatchError DOMException
|
||||||
|
TypeMismatch,
|
||||||
|
/// InvalidModificationError DOMException
|
||||||
|
InvalidModification,
|
||||||
|
/// NotReadableError DOMException
|
||||||
|
NotReadable,
|
||||||
|
/// DataError DOMException
|
||||||
|
Data,
|
||||||
|
/// OperationError DOMException
|
||||||
|
Operation,
|
||||||
|
|
||||||
|
/// TypeError JavaScript Error
|
||||||
|
Type(String),
|
||||||
|
/// RangeError JavaScript Error
|
||||||
|
Range(String),
|
||||||
|
|
||||||
|
/// A JavaScript exception is already pending.
|
||||||
|
JSFailed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The return type for IDL operations that can throw DOM exceptions.
|
||||||
|
pub type Fallible<T> = Result<T, Error>;
|
||||||
|
|
||||||
|
/// The return type for IDL operations that can throw DOM exceptions and
|
||||||
|
/// return `()`.
|
||||||
|
pub type ErrorResult = Fallible<()>;
|
40
components/script_bindings/iterable.rs
Normal file
40
components/script_bindings/iterable.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use js::conversions::ToJSValConvertible;
|
||||||
|
|
||||||
|
use crate::utils::DOMClass;
|
||||||
|
|
||||||
|
/// The values that an iterator will iterate over.
|
||||||
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
|
pub enum IteratorType {
|
||||||
|
/// The keys of the iterable object.
|
||||||
|
Keys,
|
||||||
|
/// The values of the iterable object.
|
||||||
|
Values,
|
||||||
|
/// The keys and values of the iterable object combined.
|
||||||
|
Entries,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A DOM object that can be iterated over using a pair value iterator.
|
||||||
|
pub trait Iterable {
|
||||||
|
/// The type of the key of the iterator pair.
|
||||||
|
type Key: ToJSValConvertible;
|
||||||
|
/// The type of the value of the iterator pair.
|
||||||
|
type Value: ToJSValConvertible;
|
||||||
|
/// Return the number of entries that can be iterated over.
|
||||||
|
fn get_iterable_length(&self) -> u32;
|
||||||
|
/// Return the value at the provided index.
|
||||||
|
fn get_value_at_index(&self, index: u32) -> Self::Value;
|
||||||
|
/// Return the key at the provided index.
|
||||||
|
fn get_key_at_index(&self, index: u32) -> Self::Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A version of the [IDLInterface] trait that is specific to types that have
|
||||||
|
/// iterators defined for them. This allows the `script` crate to define the
|
||||||
|
/// derives check for the concrete interface type, while the [IteratableIterator]
|
||||||
|
/// type defined in this module can be parameterized over an unknown generic.
|
||||||
|
pub trait IteratorDerives {
|
||||||
|
fn derives(class: &'static DOMClass) -> bool;
|
||||||
|
}
|
|
@ -20,13 +20,17 @@ extern crate malloc_size_of_derive;
|
||||||
pub mod callback;
|
pub mod callback;
|
||||||
pub mod constant;
|
pub mod constant;
|
||||||
pub mod conversions;
|
pub mod conversions;
|
||||||
|
pub mod error;
|
||||||
pub mod inheritance;
|
pub mod inheritance;
|
||||||
|
pub mod iterable;
|
||||||
|
pub mod like;
|
||||||
pub mod reflector;
|
pub mod reflector;
|
||||||
pub mod root;
|
pub mod root;
|
||||||
pub mod script_runtime;
|
pub mod script_runtime;
|
||||||
pub mod str;
|
pub mod str;
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod weakref;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub mod codegen {
|
pub mod codegen {
|
||||||
|
|
111
components/script_bindings/like.rs
Normal file
111
components/script_bindings/like.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Implementation of `setlike<...>` and `maplike<..., ...>` WebIDL declarations.
|
||||||
|
|
||||||
|
use js::conversions::ToJSValConvertible;
|
||||||
|
|
||||||
|
use crate::iterable::Iterable;
|
||||||
|
|
||||||
|
/// Every Setlike dom_struct must implement this to provide access to underlying storage
|
||||||
|
/// so codegen can automatically generate all setlike methods
|
||||||
|
///
|
||||||
|
/// In case you use a type that implements Setlike as underlying storage it's recommended to use `setlike` macro.
|
||||||
|
// In webidl: `setlike<Key>`
|
||||||
|
pub trait Setlike {
|
||||||
|
/// The type of the key of the set.
|
||||||
|
type Key: ToJSValConvertible + Clone; // clone is for impl<T: Setlike> Maplike for T
|
||||||
|
|
||||||
|
fn get_index(&self, index: u32) -> Option<Self::Key>;
|
||||||
|
|
||||||
|
fn size(&self) -> u32;
|
||||||
|
fn add(&self, key: Self::Key);
|
||||||
|
fn has(&self, key: Self::Key) -> bool;
|
||||||
|
fn clear(&self);
|
||||||
|
fn delete(&self, key: Self::Key) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can only have one iterable for T
|
||||||
|
// so we have impl<T: Maplike> Iterable for T
|
||||||
|
// and minimal:
|
||||||
|
impl<T: Setlike> Maplike for T {
|
||||||
|
type Key = <T as Setlike>::Key;
|
||||||
|
|
||||||
|
type Value = <T as Setlike>::Key;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_index(&self, index: u32) -> Option<(Self::Key, Self::Value)> {
|
||||||
|
self.get_index(index).map(|k| (k.clone(), k))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, _key: Self::Key) -> Option<Self::Value> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size(&self) -> u32 {
|
||||||
|
self.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&self, _key: Self::Key, _value: Self::Value) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has(&self, _key: Self::Key) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete(&self, _key: Self::Key) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Every Maplike dom_struct must implement this
|
||||||
|
/// to provide access to underlying storage
|
||||||
|
/// so codegen can automatically generate all maplike methods
|
||||||
|
///
|
||||||
|
/// In case you use a type that implements Maplike as underlying storage it's recommended to use `maplike` macro.
|
||||||
|
// In webidl: `maplike<Key, Value>`
|
||||||
|
pub trait Maplike {
|
||||||
|
/// The type of the key of the map.
|
||||||
|
type Key: ToJSValConvertible;
|
||||||
|
/// The type of the value of the map.
|
||||||
|
type Value: ToJSValConvertible;
|
||||||
|
|
||||||
|
fn get_index(&self, index: u32) -> Option<(Self::Key, Self::Value)>;
|
||||||
|
|
||||||
|
fn get(&self, key: Self::Key) -> Option<Self::Value>;
|
||||||
|
fn size(&self) -> u32;
|
||||||
|
fn set(&self, key: Self::Key, value: Self::Value);
|
||||||
|
fn has(&self, key: Self::Key) -> bool;
|
||||||
|
fn clear(&self);
|
||||||
|
fn delete(&self, key: Self::Key) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Maplike> Iterable for T {
|
||||||
|
type Key = T::Key;
|
||||||
|
|
||||||
|
type Value = T::Value;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_iterable_length(&self) -> u32 {
|
||||||
|
self.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_value_at_index(&self, index: u32) -> <T as Maplike>::Value {
|
||||||
|
// SAFETY: we are checking bounds manually
|
||||||
|
self.get_index(index).unwrap().1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_key_at_index(&self, index: u32) -> <T as Maplike>::Key {
|
||||||
|
// SAFETY: we are checking bounds manually
|
||||||
|
self.get_index(index).unwrap().0
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
use js::glue::CallObjectTracer;
|
use js::glue::CallObjectTracer;
|
||||||
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind};
|
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind};
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
use crate::reflector::Reflector;
|
use crate::reflector::Reflector;
|
||||||
use crate::str::{DOMString, USVString};
|
use crate::str::{DOMString, USVString};
|
||||||
|
|
||||||
|
@ -51,3 +52,4 @@ macro_rules! unsafe_no_jsmanaged_fields(
|
||||||
|
|
||||||
unsafe_no_jsmanaged_fields!(DOMString);
|
unsafe_no_jsmanaged_fields!(DOMString);
|
||||||
unsafe_no_jsmanaged_fields!(USVString);
|
unsafe_no_jsmanaged_fields!(USVString);
|
||||||
|
unsafe_no_jsmanaged_fields!(Error);
|
||||||
|
|
165
components/script_bindings/weakref.rs
Normal file
165
components/script_bindings/weakref.rs
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Weak-referenceable JS-managed DOM objects.
|
||||||
|
//!
|
||||||
|
//! IDL interfaces marked as `weakReferenceable` in `Bindings.conf`
|
||||||
|
//! automatically implement the `WeakReferenceable` trait in codegen.
|
||||||
|
//! The instance object is responsible for setting `None` in its own
|
||||||
|
//! own `WeakBox` when it is collected, through the `DOM_WEAK_SLOT`
|
||||||
|
//! slot. When all associated `WeakRef` values are dropped, the
|
||||||
|
//! `WeakBox` itself is dropped too.
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::ops::Drop;
|
||||||
|
use std::{mem, ptr};
|
||||||
|
|
||||||
|
use js::glue::JS_GetReservedSlot;
|
||||||
|
use js::jsapi::{JSTracer, JS_SetReservedSlot};
|
||||||
|
use js::jsval::{PrivateValue, UndefinedValue};
|
||||||
|
use libc::c_void;
|
||||||
|
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||||
|
|
||||||
|
use crate::reflector::DomObject;
|
||||||
|
use crate::root::DomRoot;
|
||||||
|
use crate::JSTraceable;
|
||||||
|
|
||||||
|
/// The index of the slot wherein a pointer to the weak holder cell is
|
||||||
|
/// stored for weak-referenceable bindings. We use slot 1 for holding it,
|
||||||
|
/// this is unsafe for globals, we disallow weak-referenceable globals
|
||||||
|
/// directly in codegen.
|
||||||
|
pub const DOM_WEAK_SLOT: u32 = 1;
|
||||||
|
|
||||||
|
/// A weak reference to a JS-managed DOM object.
|
||||||
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
|
||||||
|
pub struct WeakRef<T: WeakReferenceable> {
|
||||||
|
ptr: ptr::NonNull<WeakBox<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The inner box of weak references, public for the finalization in codegen.
|
||||||
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||||
|
pub struct WeakBox<T: WeakReferenceable> {
|
||||||
|
/// The reference count. When it reaches zero, the `value` field should
|
||||||
|
/// have already been set to `None`. The pointee contributes one to the count.
|
||||||
|
pub count: Cell<usize>,
|
||||||
|
/// The pointer to the JS-managed object, set to None when it is collected.
|
||||||
|
pub value: Cell<Option<ptr::NonNull<T>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait implemented by weak-referenceable interfaces.
|
||||||
|
pub trait WeakReferenceable: DomObject + Sized {
|
||||||
|
/// Downgrade a DOM object reference to a weak one.
|
||||||
|
fn downgrade(&self) -> WeakRef<Self> {
|
||||||
|
unsafe {
|
||||||
|
let object = self.reflector().get_jsobject().get();
|
||||||
|
let mut slot = UndefinedValue();
|
||||||
|
JS_GetReservedSlot(object, DOM_WEAK_SLOT, &mut slot);
|
||||||
|
let mut ptr = slot.to_private() as *mut WeakBox<Self>;
|
||||||
|
if ptr.is_null() {
|
||||||
|
trace!("Creating new WeakBox holder for {:p}.", self);
|
||||||
|
ptr = Box::into_raw(Box::new(WeakBox {
|
||||||
|
count: Cell::new(1),
|
||||||
|
value: Cell::new(Some(ptr::NonNull::from(self))),
|
||||||
|
}));
|
||||||
|
let val = PrivateValue(ptr as *const c_void);
|
||||||
|
JS_SetReservedSlot(object, DOM_WEAK_SLOT, &val);
|
||||||
|
}
|
||||||
|
let box_ = &*ptr;
|
||||||
|
assert!(box_.value.get().is_some());
|
||||||
|
let new_count = box_.count.get() + 1;
|
||||||
|
trace!(
|
||||||
|
"Incrementing WeakBox refcount for {:p} to {}.",
|
||||||
|
self,
|
||||||
|
new_count
|
||||||
|
);
|
||||||
|
box_.count.set(new_count);
|
||||||
|
WeakRef {
|
||||||
|
ptr: ptr::NonNull::new_unchecked(ptr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WeakReferenceable> WeakRef<T> {
|
||||||
|
/// Create a new weak reference from a `WeakReferenceable` interface instance.
|
||||||
|
/// This is just a convenience wrapper around `<T as WeakReferenceable>::downgrade`
|
||||||
|
/// to not have to import `WeakReferenceable`.
|
||||||
|
pub fn new(value: &T) -> Self {
|
||||||
|
value.downgrade()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DomRoot a weak reference. Returns `None` if the object was already collected.
|
||||||
|
pub fn root(&self) -> Option<DomRoot<T>> {
|
||||||
|
unsafe { &*self.ptr.as_ptr() }
|
||||||
|
.value
|
||||||
|
.get()
|
||||||
|
.map(|ptr| unsafe { DomRoot::from_ref(&*ptr.as_ptr()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return whether the weakly-referenced object is still alive.
|
||||||
|
pub fn is_alive(&self) -> bool {
|
||||||
|
unsafe { &*self.ptr.as_ptr() }.value.get().is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WeakReferenceable> Clone for WeakRef<T> {
|
||||||
|
fn clone(&self) -> WeakRef<T> {
|
||||||
|
unsafe {
|
||||||
|
let box_ = &*self.ptr.as_ptr();
|
||||||
|
let new_count = box_.count.get() + 1;
|
||||||
|
box_.count.set(new_count);
|
||||||
|
WeakRef { ptr: self.ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WeakReferenceable> MallocSizeOf for WeakRef<T> {
|
||||||
|
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WeakReferenceable> PartialEq for WeakRef<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
unsafe {
|
||||||
|
(*self.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) ==
|
||||||
|
(*other.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WeakReferenceable> PartialEq<T> for WeakRef<T> {
|
||||||
|
fn eq(&self, other: &T) -> bool {
|
||||||
|
unsafe {
|
||||||
|
match self.ptr.as_ref().value.get() {
|
||||||
|
Some(ptr) => ptr::eq(ptr.as_ptr(), other),
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: WeakReferenceable> JSTraceable for WeakRef<T> {
|
||||||
|
unsafe fn trace(&self, _: *mut JSTracer) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WeakReferenceable> Drop for WeakRef<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let (count, value) = {
|
||||||
|
let weak_box = &*self.ptr.as_ptr();
|
||||||
|
assert!(weak_box.count.get() > 0);
|
||||||
|
let count = weak_box.count.get() - 1;
|
||||||
|
weak_box.count.set(count);
|
||||||
|
(count, weak_box.value.get())
|
||||||
|
};
|
||||||
|
if count == 0 {
|
||||||
|
assert!(value.is_none());
|
||||||
|
mem::drop(Box::from_raw(self.ptr.as_ptr()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue