mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
Move CustomTraceable to script_bindings. (#35988)
* script: Move CustomTraceable to script_bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Move record binding support to script_bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Address clippy warnings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
d35da38a2f
commit
c8d8787959
15 changed files with 340 additions and 277 deletions
|
@ -22,8 +22,10 @@ serde_json = { workspace = true }
|
|||
|
||||
[dependencies]
|
||||
bitflags = { workspace = true }
|
||||
crossbeam-channel = { workspace = true }
|
||||
cssparser = { workspace = true }
|
||||
html5ever = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
js = { workspace = true }
|
||||
jstraceable_derive = { path = "../jstraceable_derive" }
|
||||
libc = { workspace = true }
|
||||
|
@ -31,15 +33,21 @@ log = { workspace = true }
|
|||
malloc_size_of = { workspace = true }
|
||||
malloc_size_of_derive = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
servo_arc = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
stylo_atoms = { workspace = true }
|
||||
servo_config = { path = "../config" }
|
||||
style = { workspace = true }
|
||||
tendril = { version = "0.4.1", features = ["encoding_rs"] }
|
||||
webxr-api = { workspace = true, optional = true }
|
||||
xml5ever = { workspace = true }
|
||||
|
||||
[features]
|
||||
bluetooth = []
|
||||
webgpu = []
|
||||
webxr = []
|
||||
webxr = ["webxr-api"]
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(crown)'] }
|
||||
|
|
|
@ -2287,7 +2287,7 @@ class CGImports(CGWrapper):
|
|||
extras += [descriptor.path, descriptor.bindingPath]
|
||||
parentName = descriptor.getParentName()
|
||||
elif t.isType() and t.isRecord():
|
||||
extras += ['crate::dom::bindings::record::Record']
|
||||
extras += ['script_bindings::record::Record']
|
||||
elif isinstance(t, IDLPromiseType):
|
||||
extras += ['crate::dom::promise::Promise']
|
||||
else:
|
||||
|
@ -2643,7 +2643,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
|
|||
'crate::dom::bindings::import::base::*',
|
||||
'crate::dom::bindings::codegen::DomTypes::DomTypes',
|
||||
'crate::dom::bindings::conversions::windowproxy_from_handlevalue',
|
||||
'crate::dom::bindings::record::Record',
|
||||
'script_bindings::record::Record',
|
||||
'crate::dom::types::*',
|
||||
'crate::dom::windowproxy::WindowProxy',
|
||||
'js::typedarray',
|
||||
|
|
|
@ -18,8 +18,8 @@ use js::jsapi::{
|
|||
};
|
||||
use js::jsval::{ObjectValue, StringValue, UndefinedValue};
|
||||
use js::rust::{
|
||||
HandleValue, MutableHandleValue, ToString, get_object_class, is_dom_class, is_dom_object,
|
||||
maybe_wrap_value,
|
||||
HandleId, HandleValue, MutableHandleValue, ToString, get_object_class, is_dom_class,
|
||||
is_dom_object, maybe_wrap_value,
|
||||
};
|
||||
|
||||
use crate::inheritance::Castable;
|
||||
|
@ -387,3 +387,24 @@ where
|
|||
}
|
||||
root_from_object(v.get().to_object(), cx)
|
||||
}
|
||||
|
||||
/// Convert `id` to a `DOMString`. Returns `None` if `id` is not a string or
|
||||
/// integer.
|
||||
///
|
||||
/// Handling of invalid UTF-16 in strings depends on the relevant option.
|
||||
///
|
||||
/// # Safety
|
||||
/// - cx must point to a non-null, valid JSContext instance.
|
||||
pub unsafe fn jsid_to_string(cx: *mut JSContext, id: HandleId) -> Option<DOMString> {
|
||||
let id_raw = *id;
|
||||
if id_raw.is_string() {
|
||||
let jsstr = std::ptr::NonNull::new(id_raw.to_string()).unwrap();
|
||||
return Some(jsstring_to_str(cx, jsstr));
|
||||
}
|
||||
|
||||
if id_raw.is_int() {
|
||||
return Some(id_raw.to_int().to_string().into());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ pub mod error;
|
|||
pub mod inheritance;
|
||||
pub mod iterable;
|
||||
pub mod like;
|
||||
pub mod record;
|
||||
pub mod reflector;
|
||||
pub mod root;
|
||||
pub mod script_runtime;
|
||||
|
@ -51,3 +52,5 @@ pub mod codegen {
|
|||
// Since they are used in derive macros,
|
||||
// it is useful that they are accessible at the root of the crate.
|
||||
pub(crate) use js::gc::Traceable as JSTraceable;
|
||||
|
||||
pub(crate) use crate::trace::CustomTraceable;
|
||||
|
|
209
components/script_bindings/record.rs
Normal file
209
components/script_bindings/record.rs
Normal file
|
@ -0,0 +1,209 @@
|
|||
/* 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/. */
|
||||
|
||||
//! The `Record` (open-ended dictionary) type.
|
||||
|
||||
use std::cmp::Eq;
|
||||
use std::hash::Hash;
|
||||
use std::marker::Sized;
|
||||
use std::ops::Deref;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use js::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible};
|
||||
use js::jsapi::glue::JS_GetOwnPropertyDescriptorById;
|
||||
use js::jsapi::{
|
||||
HandleId as RawHandleId, JS_NewPlainObject, JSContext, JSITER_HIDDEN, JSITER_OWNONLY,
|
||||
JSITER_SYMBOLS, JSPROP_ENUMERATE, PropertyDescriptor,
|
||||
};
|
||||
use js::jsval::{ObjectValue, UndefinedValue};
|
||||
use js::rooted;
|
||||
use js::rust::wrappers::{GetPropertyKeys, JS_DefineUCProperty2, JS_GetPropertyById, JS_IdToValue};
|
||||
use js::rust::{HandleId, HandleValue, IdVector, MutableHandleValue};
|
||||
|
||||
use crate::conversions::jsid_to_string;
|
||||
use crate::str::{ByteString, DOMString, USVString};
|
||||
|
||||
pub trait RecordKey: Eq + Hash + Sized {
|
||||
fn to_utf16_vec(&self) -> Vec<u16>;
|
||||
|
||||
/// Attempt to extract a key from a JS id.
|
||||
/// # Safety
|
||||
/// - cx must point to a non-null, valid JSContext.
|
||||
#[allow(clippy::result_unit_err)]
|
||||
unsafe fn from_id(cx: *mut JSContext, id: HandleId) -> Result<ConversionResult<Self>, ()>;
|
||||
}
|
||||
|
||||
impl RecordKey for DOMString {
|
||||
fn to_utf16_vec(&self) -> Vec<u16> {
|
||||
self.encode_utf16().collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
unsafe fn from_id(cx: *mut JSContext, id: HandleId) -> Result<ConversionResult<Self>, ()> {
|
||||
match jsid_to_string(cx, id) {
|
||||
Some(s) => Ok(ConversionResult::Success(s)),
|
||||
None => Ok(ConversionResult::Failure("Failed to get DOMString".into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RecordKey for USVString {
|
||||
fn to_utf16_vec(&self) -> Vec<u16> {
|
||||
self.0.encode_utf16().collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
unsafe fn from_id(cx: *mut JSContext, id: HandleId) -> Result<ConversionResult<Self>, ()> {
|
||||
rooted!(in(cx) let mut jsid_value = UndefinedValue());
|
||||
let raw_id: RawHandleId = id.into();
|
||||
JS_IdToValue(cx, *raw_id.ptr, jsid_value.handle_mut());
|
||||
|
||||
USVString::from_jsval(cx, jsid_value.handle(), ())
|
||||
}
|
||||
}
|
||||
|
||||
impl RecordKey for ByteString {
|
||||
fn to_utf16_vec(&self) -> Vec<u16> {
|
||||
self.iter().map(|&x| x as u16).collect::<Vec<u16>>()
|
||||
}
|
||||
|
||||
unsafe fn from_id(cx: *mut JSContext, id: HandleId) -> Result<ConversionResult<Self>, ()> {
|
||||
rooted!(in(cx) let mut jsid_value = UndefinedValue());
|
||||
let raw_id: RawHandleId = id.into();
|
||||
JS_IdToValue(cx, *raw_id.ptr, jsid_value.handle_mut());
|
||||
|
||||
ByteString::from_jsval(cx, jsid_value.handle(), ())
|
||||
}
|
||||
}
|
||||
|
||||
/// The `Record` (open-ended dictionary) type.
|
||||
#[derive(Clone, JSTraceable)]
|
||||
pub struct Record<K: RecordKey, V> {
|
||||
#[custom_trace]
|
||||
map: IndexMap<K, V>,
|
||||
}
|
||||
|
||||
impl<K: RecordKey, V> Record<K, V> {
|
||||
/// Create an empty `Record`.
|
||||
pub fn new() -> Self {
|
||||
Record {
|
||||
map: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: RecordKey, V> Deref for Record<K, V> {
|
||||
type Target = IndexMap<K, V>;
|
||||
|
||||
fn deref(&self) -> &IndexMap<K, V> {
|
||||
&self.map
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, C> FromJSValConvertible for Record<K, V>
|
||||
where
|
||||
K: RecordKey,
|
||||
V: FromJSValConvertible<Config = C>,
|
||||
C: Clone,
|
||||
{
|
||||
type Config = C;
|
||||
unsafe fn from_jsval(
|
||||
cx: *mut JSContext,
|
||||
value: HandleValue,
|
||||
config: C,
|
||||
) -> Result<ConversionResult<Self>, ()> {
|
||||
if !value.is_object() {
|
||||
return Ok(ConversionResult::Failure(
|
||||
"Record value was not an object".into(),
|
||||
));
|
||||
}
|
||||
|
||||
rooted!(in(cx) let object = value.to_object());
|
||||
let mut ids = IdVector::new(cx);
|
||||
if !GetPropertyKeys(
|
||||
cx,
|
||||
object.handle(),
|
||||
JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
|
||||
ids.handle_mut(),
|
||||
) {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let mut map = IndexMap::new();
|
||||
for id in &*ids {
|
||||
rooted!(in(cx) let id = *id);
|
||||
rooted!(in(cx) let mut desc = PropertyDescriptor::default());
|
||||
|
||||
let mut is_none = false;
|
||||
if !JS_GetOwnPropertyDescriptorById(
|
||||
cx,
|
||||
object.handle().into(),
|
||||
id.handle().into(),
|
||||
desc.handle_mut().into(),
|
||||
&mut is_none,
|
||||
) {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if !desc.enumerable_() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let key = match K::from_id(cx, id.handle())? {
|
||||
ConversionResult::Success(key) => key,
|
||||
ConversionResult::Failure(message) => {
|
||||
return Ok(ConversionResult::Failure(message));
|
||||
},
|
||||
};
|
||||
|
||||
rooted!(in(cx) let mut property = UndefinedValue());
|
||||
if !JS_GetPropertyById(cx, object.handle(), id.handle(), property.handle_mut()) {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let property = match V::from_jsval(cx, property.handle(), config.clone())? {
|
||||
ConversionResult::Success(property) => property,
|
||||
ConversionResult::Failure(message) => {
|
||||
return Ok(ConversionResult::Failure(message));
|
||||
},
|
||||
};
|
||||
map.insert(key, property);
|
||||
}
|
||||
|
||||
Ok(ConversionResult::Success(Record { map }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> ToJSValConvertible for Record<K, V>
|
||||
where
|
||||
K: RecordKey,
|
||||
V: ToJSValConvertible,
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
|
||||
rooted!(in(cx) let js_object = JS_NewPlainObject(cx));
|
||||
assert!(!js_object.handle().is_null());
|
||||
|
||||
rooted!(in(cx) let mut js_value = UndefinedValue());
|
||||
for (key, value) in &self.map {
|
||||
let key = key.to_utf16_vec();
|
||||
value.to_jsval(cx, js_value.handle_mut());
|
||||
|
||||
assert!(JS_DefineUCProperty2(
|
||||
cx,
|
||||
js_object.handle(),
|
||||
key.as_ptr(),
|
||||
key.len(),
|
||||
js_value.handle(),
|
||||
JSPROP_ENUMERATE as u32
|
||||
));
|
||||
}
|
||||
|
||||
rval.set(ObjectValue(js_object.handle().get()));
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: RecordKey, V> Default for Record<K, V> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
|
@ -2,9 +2,32 @@
|
|||
* 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 std::cell::OnceCell;
|
||||
use std::hash::{BuildHasher, Hash};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crossbeam_channel::Sender;
|
||||
use html5ever::interface::{Tracer as HtmlTracer, TreeSink};
|
||||
use html5ever::tokenizer::{TokenSink, Tokenizer};
|
||||
use html5ever::tree_builder::TreeBuilder;
|
||||
use indexmap::IndexMap;
|
||||
use js::glue::CallObjectTracer;
|
||||
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind};
|
||||
use parking_lot::RwLock;
|
||||
use servo_arc::Arc as ServoArc;
|
||||
use smallvec::SmallVec;
|
||||
use style::author_styles::AuthorStyles;
|
||||
use style::stylesheet_set::{AuthorStylesheetSet, DocumentStylesheetSet};
|
||||
use tendril::TendrilSink;
|
||||
use tendril::fmt::UTF8;
|
||||
use tendril::stream::LossyDecoder;
|
||||
#[cfg(feature = "webxr")]
|
||||
use webxr_api::{Finger, Hand};
|
||||
use xml5ever::interface::TreeSink as XmlTreeSink;
|
||||
use xml5ever::tokenizer::XmlTokenizer;
|
||||
use xml5ever::tree_builder::{Tracer as XmlTracer, XmlTreeBuilder};
|
||||
|
||||
use crate::JSTraceable;
|
||||
use crate::error::Error;
|
||||
use crate::reflector::Reflector;
|
||||
use crate::str::{DOMString, USVString};
|
||||
|
@ -53,3 +76,235 @@ macro_rules! unsafe_no_jsmanaged_fields(
|
|||
unsafe_no_jsmanaged_fields!(DOMString);
|
||||
unsafe_no_jsmanaged_fields!(USVString);
|
||||
unsafe_no_jsmanaged_fields!(Error);
|
||||
|
||||
/// A trait to allow tracing only DOM sub-objects.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This trait is unsafe; if it is implemented incorrectly, the GC may end up collecting objects
|
||||
/// that are still reachable.
|
||||
pub unsafe trait CustomTraceable {
|
||||
/// Trace `self`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `JSTracer` argument must point to a valid `JSTracer` in memory. In addition,
|
||||
/// implementors of this method must ensure that all active objects are properly traced
|
||||
/// or else the garbage collector may end up collecting objects that are still reachable.
|
||||
unsafe fn trace(&self, trc: *mut JSTracer);
|
||||
}
|
||||
|
||||
unsafe impl<T: CustomTraceable> CustomTraceable for Box<T> {
|
||||
#[inline]
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
(**self).trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: JSTraceable> CustomTraceable for OnceCell<T> {
|
||||
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
||||
if let Some(value) = self.get() {
|
||||
value.trace(tracer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> CustomTraceable for Sender<T> {
|
||||
unsafe fn trace(&self, _: *mut JSTracer) {}
|
||||
}
|
||||
|
||||
unsafe impl<T: JSTraceable> CustomTraceable for ServoArc<T> {
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
(**self).trace(trc)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: JSTraceable> CustomTraceable for RwLock<T> {
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
self.read().trace(trc)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: JSTraceable + Eq + Hash> CustomTraceable for indexmap::IndexSet<T> {
|
||||
#[inline]
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
for e in self.iter() {
|
||||
e.trace(trc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXXManishearth Check if the following three are optimized to no-ops
|
||||
// if e.trace() is a no-op (e.g it is an unsafe_no_jsmanaged_fields type)
|
||||
unsafe impl<T: JSTraceable + 'static> CustomTraceable for SmallVec<[T; 1]> {
|
||||
#[inline]
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
for e in self.iter() {
|
||||
e.trace(trc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<K, V, S> CustomTraceable for IndexMap<K, V, S>
|
||||
where
|
||||
K: Hash + Eq + JSTraceable,
|
||||
V: JSTraceable,
|
||||
S: BuildHasher,
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
for (k, v) in self {
|
||||
k.trace(trc);
|
||||
v.trace(trc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<S> CustomTraceable for DocumentStylesheetSet<S>
|
||||
where
|
||||
S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
|
||||
{
|
||||
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
||||
for (s, _origin) in self.iter() {
|
||||
s.trace(tracer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<S> CustomTraceable for AuthorStylesheetSet<S>
|
||||
where
|
||||
S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
|
||||
{
|
||||
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
||||
for s in self.iter() {
|
||||
s.trace(tracer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<S> CustomTraceable for AuthorStyles<S>
|
||||
where
|
||||
S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
|
||||
{
|
||||
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
||||
self.stylesheets.trace(tracer)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Sink> CustomTraceable for LossyDecoder<Sink>
|
||||
where
|
||||
Sink: JSTraceable + TendrilSink<UTF8>,
|
||||
{
|
||||
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
||||
self.inner_sink().trace(tracer);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "webxr")]
|
||||
unsafe impl<J> CustomTraceable for Hand<J>
|
||||
where
|
||||
J: JSTraceable,
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
// exhaustive match so we don't miss new fields
|
||||
let Hand {
|
||||
ref wrist,
|
||||
ref thumb_metacarpal,
|
||||
ref thumb_phalanx_proximal,
|
||||
ref thumb_phalanx_distal,
|
||||
ref thumb_phalanx_tip,
|
||||
ref index,
|
||||
ref middle,
|
||||
ref ring,
|
||||
ref little,
|
||||
} = *self;
|
||||
wrist.trace(trc);
|
||||
thumb_metacarpal.trace(trc);
|
||||
thumb_phalanx_proximal.trace(trc);
|
||||
thumb_phalanx_distal.trace(trc);
|
||||
thumb_phalanx_tip.trace(trc);
|
||||
index.trace(trc);
|
||||
middle.trace(trc);
|
||||
ring.trace(trc);
|
||||
little.trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "webxr")]
|
||||
unsafe impl<J> CustomTraceable for Finger<J>
|
||||
where
|
||||
J: JSTraceable,
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
// exhaustive match so we don't miss new fields
|
||||
let Finger {
|
||||
ref metacarpal,
|
||||
ref phalanx_proximal,
|
||||
ref phalanx_intermediate,
|
||||
ref phalanx_distal,
|
||||
ref phalanx_tip,
|
||||
} = *self;
|
||||
metacarpal.trace(trc);
|
||||
phalanx_proximal.trace(trc);
|
||||
phalanx_intermediate.trace(trc);
|
||||
phalanx_distal.trace(trc);
|
||||
phalanx_tip.trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Handle: JSTraceable + Clone, Sink: TreeSink<Handle = Handle> + JSTraceable>
|
||||
CustomTraceable for TreeBuilder<Handle, Sink>
|
||||
{
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
struct Tracer<Handle>(*mut JSTracer, PhantomData<Handle>);
|
||||
let tracer = Tracer::<Handle>(trc, PhantomData);
|
||||
|
||||
impl<Handle: JSTraceable> HtmlTracer for Tracer<Handle> {
|
||||
type Handle = Handle;
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
fn trace_handle(&self, node: &Handle) {
|
||||
unsafe {
|
||||
node.trace(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.trace_handles(&tracer);
|
||||
self.sink.trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl<Handle: JSTraceable + Clone, Sink: TokenSink<Handle = Handle> + CustomTraceable>
|
||||
CustomTraceable for Tokenizer<Sink>
|
||||
{
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
self.sink.trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl<Handle: JSTraceable + Clone, Sink: JSTraceable + XmlTreeSink<Handle = Handle>>
|
||||
CustomTraceable for XmlTokenizer<XmlTreeBuilder<Handle, Sink>>
|
||||
{
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
struct Tracer<Handle>(*mut JSTracer, PhantomData<Handle>);
|
||||
let tracer = Tracer(trc, PhantomData);
|
||||
|
||||
impl<Handle: JSTraceable> XmlTracer for Tracer<Handle> {
|
||||
type Handle = Handle;
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
fn trace_handle(&self, node: &Handle) {
|
||||
unsafe {
|
||||
node.trace(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let tree_builder = &self.sink;
|
||||
tree_builder.trace_handles(&tracer);
|
||||
tree_builder.sink.trace(trc);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue