mirror of
https://github.com/servo/servo.git
synced 2025-08-01 19:50:30 +01:00
Add safer bindings for RefPtr
This commit is contained in:
parent
dc5dc5e614
commit
2bde9462b1
9 changed files with 249 additions and 76 deletions
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#[allow(dead_code, improper_ctypes, non_camel_case_types)]
|
#[allow(dead_code, improper_ctypes, non_camel_case_types)]
|
||||||
pub mod bindings;
|
pub mod bindings;
|
||||||
pub mod ptr;
|
|
||||||
|
|
||||||
// FIXME: We allow `improper_ctypes` (for now), because the lint doesn't allow
|
// FIXME: We allow `improper_ctypes` (for now), because the lint doesn't allow
|
||||||
// foreign structs to have `PhantomData`. We should remove this once the lint
|
// foreign structs to have `PhantomData`. We should remove this once the lint
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
/* 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 http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
use gecko_bindings::bindings::*;
|
|
||||||
use heapsize::HeapSizeOf;
|
|
||||||
use std::fmt::{self, Debug};
|
|
||||||
|
|
||||||
// Defines an Arc-like type that manages a refcounted Gecko object stored
|
|
||||||
// in a ThreadSafeFooHolder smart pointer (for those Gecko classes that
|
|
||||||
// do not have thread-safe refcounting support) or as raw pointers (for
|
|
||||||
// those that do have thread-safe refcounting support). Used in tandem
|
|
||||||
// with the NS_DECL_(HOLDER|THREADSAFE)_FFI_REFCOUNTING-defined types and
|
|
||||||
// functions in Gecko.
|
|
||||||
macro_rules! define_arc {
|
|
||||||
($arc_type:ident, $name:ident, $gecko_type:ident, $addref: ident, $release: ident) => (
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
pub struct $arc_type {
|
|
||||||
ptr: *mut $gecko_type,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $arc_type {
|
|
||||||
pub fn new(data: *mut $gecko_type) -> $arc_type {
|
|
||||||
debug_assert!(!data.is_null());
|
|
||||||
unsafe { $addref(data); }
|
|
||||||
$arc_type {
|
|
||||||
ptr: data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_raw(&self) -> *mut $gecko_type { self.ptr }
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for $arc_type {}
|
|
||||||
unsafe impl Sync for $arc_type {}
|
|
||||||
|
|
||||||
impl Clone for $arc_type {
|
|
||||||
fn clone(&self) -> $arc_type {
|
|
||||||
$arc_type::new(self.ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for $arc_type {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe { $release(self.ptr); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeapSizeOf for $arc_type {
|
|
||||||
fn heap_size_of_children(&self) -> usize { 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for $arc_type {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, stringify!($name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
define_arc!(GeckoArcPrincipal, Principal, ThreadSafePrincipalHolder,
|
|
||||||
Gecko_AddRefPrincipalArbitraryThread, Gecko_ReleasePrincipalArbitraryThread);
|
|
||||||
define_arc!(GeckoArcURI, URI, ThreadSafeURIHolder,
|
|
||||||
Gecko_AddRefURIArbitraryThread, Gecko_ReleaseURIArbitraryThread);
|
|
|
@ -8,4 +8,5 @@ mod ns_style_auto_array;
|
||||||
pub mod ns_style_coord;
|
pub mod ns_style_coord;
|
||||||
mod ns_t_array;
|
mod ns_t_array;
|
||||||
pub mod ownership;
|
pub mod ownership;
|
||||||
|
pub mod refptr;
|
||||||
mod style_complex_color;
|
mod style_complex_color;
|
||||||
|
|
237
components/style/gecko_bindings/sugar/refptr.rs
Normal file
237
components/style/gecko_bindings/sugar/refptr.rs
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use gecko_bindings::structs;
|
||||||
|
use heapsize::HeapSizeOf;
|
||||||
|
use std::{mem, ptr};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
/// Trait for all objects that have Addref() and Release
|
||||||
|
/// methods and can be placed inside RefPtr<T>
|
||||||
|
pub unsafe trait RefCounted {
|
||||||
|
fn addref(&self);
|
||||||
|
unsafe fn release(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for types which can be shared across threads in RefPtr
|
||||||
|
pub unsafe trait ThreadSafeRefCounted: RefCounted {}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RefPtr<T: RefCounted> {
|
||||||
|
ptr: *mut T,
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A RefPtr that we know is uniquely owned
|
||||||
|
///
|
||||||
|
/// This is basically Box<T>, with the additional
|
||||||
|
/// guarantee that the box can be safely interpreted
|
||||||
|
/// as a RefPtr<T> (with refcount 1)
|
||||||
|
///
|
||||||
|
/// This is useful when you wish to create a refptr
|
||||||
|
/// and mutate it temporarily, while it is still
|
||||||
|
/// uniquely owned.
|
||||||
|
pub struct UniqueRefPtr<T: RefCounted>(RefPtr<T>);
|
||||||
|
|
||||||
|
// There is no safe conversion from &T to RefPtr<T> (like Gecko has)
|
||||||
|
// because this lets you break UniqueRefPtr's guarantee
|
||||||
|
|
||||||
|
impl<T: RefCounted> RefPtr<T> {
|
||||||
|
/// Create a new RefPtr from an already addrefed
|
||||||
|
/// pointer obtained from FFI. Pointer
|
||||||
|
/// must be valid, non-null and have been addrefed
|
||||||
|
pub unsafe fn from_addrefed(ptr: *mut T) -> Self {
|
||||||
|
debug_assert!(!ptr.is_null());
|
||||||
|
RefPtr {
|
||||||
|
ptr: ptr,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new RefPtr from a pointer obtained
|
||||||
|
/// from FFI. Pointer must be valid and non null.
|
||||||
|
/// This method calls addref() internally
|
||||||
|
pub unsafe fn new(ptr: *mut T) -> Self {
|
||||||
|
debug_assert!(!ptr.is_null());
|
||||||
|
let ret = RefPtr {
|
||||||
|
ptr: ptr,
|
||||||
|
_marker: PhantomData,
|
||||||
|
};
|
||||||
|
ret.addref();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Produces an FFI-compatible RefPtr that can be stored in
|
||||||
|
/// style structs.
|
||||||
|
///
|
||||||
|
/// structs::RefPtr does not have a destructor, so this may leak
|
||||||
|
pub fn forget(self) -> structs::RefPtr<T> {
|
||||||
|
let ret = structs::RefPtr {
|
||||||
|
mRawPtr: self.ptr,
|
||||||
|
};
|
||||||
|
mem::forget(self);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the raw inner pointer
|
||||||
|
/// to be fed back into FFI
|
||||||
|
pub fn get(&self) -> *mut T {
|
||||||
|
self.ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Addref the inner data
|
||||||
|
///
|
||||||
|
/// Leaky on its own
|
||||||
|
pub fn addref(&self) {
|
||||||
|
unsafe { (*self.ptr).addref(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Release the inner data
|
||||||
|
///
|
||||||
|
/// Call only when the data actuall needs releasing
|
||||||
|
pub unsafe fn release(&self) {
|
||||||
|
(*self.ptr).release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RefCounted> UniqueRefPtr<T> {
|
||||||
|
/// Create a unique refptr from an already addrefed
|
||||||
|
/// pointer obtained from FFI. The refcount must be one.
|
||||||
|
/// The pointer must be valid and non null
|
||||||
|
pub unsafe fn from_addrefed(ptr: *mut T) -> Self {
|
||||||
|
UniqueRefPtr(RefPtr::from_addrefed(ptr))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert to a RefPtr so that it can be used
|
||||||
|
pub fn get(self) -> RefPtr<T> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RefCounted> Deref for RefPtr<T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
unsafe { &*self.ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RefCounted> Deref for UniqueRefPtr<T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
unsafe { &*self.0.ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RefCounted> DerefMut for UniqueRefPtr<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
|
unsafe { &mut *self.0.ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RefCounted> structs::RefPtr<T> {
|
||||||
|
/// Produces a Rust-side RefPtr from an FFI RefPtr, bumping the refcount
|
||||||
|
///
|
||||||
|
/// Must be called on a valid, non-null structs::RefPtr<T>
|
||||||
|
pub unsafe fn to_safe(&self) -> RefPtr<T> {
|
||||||
|
debug_assert!(!self.mRawPtr.is_null());
|
||||||
|
let r = RefPtr {
|
||||||
|
ptr: self.mRawPtr,
|
||||||
|
_marker: PhantomData,
|
||||||
|
};
|
||||||
|
r.addref();
|
||||||
|
r
|
||||||
|
}
|
||||||
|
/// Produces a Rust-side RefPtr, consuming the existing one (and not bumping the refcount)
|
||||||
|
pub unsafe fn into_safe(self) -> RefPtr<T> {
|
||||||
|
debug_assert!(!self.mRawPtr.is_null());
|
||||||
|
RefPtr {
|
||||||
|
ptr: self.mRawPtr,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace a structs::RefPtr<T> with a different one, appropriately addref/releasing
|
||||||
|
///
|
||||||
|
/// Both `self` and `other` must be valid, but can be null
|
||||||
|
pub unsafe fn set(&mut self, other: &Self) {
|
||||||
|
if !self.mRawPtr.is_null() {
|
||||||
|
(*self.mRawPtr).release();
|
||||||
|
self.mRawPtr = ptr::null_mut();
|
||||||
|
}
|
||||||
|
if !other.mRawPtr.is_null() {
|
||||||
|
*self = other.to_safe().forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace a `structs::RefPtr<T>` with a `RefPtr<T>`,
|
||||||
|
/// consuming the `RefPtr<T>`, and releasing the old
|
||||||
|
/// value in `self` if necessary.
|
||||||
|
///
|
||||||
|
/// `self` must be valid, possibly null
|
||||||
|
pub fn set_move(&mut self, other: RefPtr<T>) {
|
||||||
|
if !self.mRawPtr.is_null() {
|
||||||
|
unsafe { (*self.mRawPtr).release(); }
|
||||||
|
}
|
||||||
|
*self = other.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RefCounted> Drop for RefPtr<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { self.release() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RefCounted> Clone for RefPtr<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
self.addref();
|
||||||
|
RefPtr {
|
||||||
|
ptr: self.ptr,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RefCounted> HeapSizeOf for RefPtr<T> {
|
||||||
|
fn heap_size_of_children(&self) -> usize { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RefCounted> PartialEq for RefPtr<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.ptr == other.ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: ThreadSafeRefCounted> Send for RefPtr<T> {}
|
||||||
|
unsafe impl<T: ThreadSafeRefCounted> Sync for RefPtr<T> {}
|
||||||
|
|
||||||
|
// Companion of NS_DECL_THREADSAFE_FFI_REFCOUNTING
|
||||||
|
//
|
||||||
|
// Gets you a free RefCounted impl
|
||||||
|
macro_rules! impl_threadsafe_refcount {
|
||||||
|
($t:ty, $addref:ident, $release:ident) => (
|
||||||
|
unsafe impl RefCounted for $t {
|
||||||
|
fn addref(&self) {
|
||||||
|
unsafe { ::gecko_bindings::bindings::$addref(self as *const _ as *mut _) }
|
||||||
|
}
|
||||||
|
unsafe fn release(&self) {
|
||||||
|
::gecko_bindings::bindings::$release(self as *const _ as *mut _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe impl ThreadSafeRefCounted for $t {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_threadsafe_refcount!(::gecko_bindings::bindings::ThreadSafePrincipalHolder,
|
||||||
|
Gecko_AddRefPrincipalArbitraryThread,
|
||||||
|
Gecko_ReleasePrincipalArbitraryThread);
|
||||||
|
impl_threadsafe_refcount!(::gecko_bindings::bindings::ThreadSafeURIHolder,
|
||||||
|
Gecko_AddRefURIArbitraryThread,
|
||||||
|
Gecko_ReleaseURIArbitraryThread);
|
||||||
|
impl_threadsafe_refcount!(::gecko_bindings::structs::nsStyleQuoteValues,
|
||||||
|
Gecko_AddRefQuoteValuesArbitraryThread,
|
||||||
|
Gecko_ReleaseQuoteValuesArbitraryThread);
|
||||||
|
pub type GeckoArcPrincipal = RefPtr<::gecko_bindings::bindings::ThreadSafePrincipalHolder>;
|
||||||
|
pub type GeckoArcURI = RefPtr<::gecko_bindings::bindings::ThreadSafeURIHolder>;
|
|
@ -7,7 +7,7 @@
|
||||||
use cssparser::{Parser, SourcePosition};
|
use cssparser::{Parser, SourcePosition};
|
||||||
use error_reporting::ParseErrorReporter;
|
use error_reporting::ParseErrorReporter;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
|
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||||
use selector_impl::TheSelectorImpl;
|
use selector_impl::TheSelectorImpl;
|
||||||
use selectors::parser::ParserContext as SelectorParserContext;
|
use selectors::parser::ParserContext as SelectorParserContext;
|
||||||
use stylesheets::Origin;
|
use stylesheets::Origin;
|
||||||
|
|
|
@ -896,9 +896,9 @@ fn static_assert() {
|
||||||
Gecko_SetMozBinding(&mut self.gecko,
|
Gecko_SetMozBinding(&mut self.gecko,
|
||||||
url.as_str().as_ptr(),
|
url.as_str().as_ptr(),
|
||||||
url.as_str().len() as u32,
|
url.as_str().len() as u32,
|
||||||
extra_data.base.as_raw(),
|
extra_data.base.get(),
|
||||||
extra_data.referrer.as_raw(),
|
extra_data.referrer.get(),
|
||||||
extra_data.principal.as_raw());
|
extra_data.principal.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -922,7 +922,7 @@ ${helpers.single_keyword("-moz-appearance",
|
||||||
// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding
|
// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding
|
||||||
<%helpers:longhand name="-moz-binding" products="gecko" animatable="False" disable_when_testing="True">
|
<%helpers:longhand name="-moz-binding" products="gecko" animatable="False" disable_when_testing="True">
|
||||||
use cssparser::{CssStringWriter, ToCss};
|
use cssparser::{CssStringWriter, ToCss};
|
||||||
use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
|
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use values::specified::UrlExtraData;
|
use values::specified::UrlExtraData;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use app_units::Au;
|
||||||
use cssparser::{self, Parser, ToCss, Token};
|
use cssparser::{self, Parser, ToCss, Token};
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
|
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use parser::ParserContextExtraData;
|
use parser::ParserContextExtraData;
|
||||||
|
|
|
@ -31,13 +31,13 @@ use style::gecko_bindings::bindings::{ServoDeclarationBlockBorrowed, ServoDeclar
|
||||||
use style::gecko_bindings::bindings::{ThreadSafePrincipalHolder, ThreadSafeURIHolder};
|
use style::gecko_bindings::bindings::{ThreadSafePrincipalHolder, ThreadSafeURIHolder};
|
||||||
use style::gecko_bindings::bindings::{nsHTMLCSSStyleSheet, ServoComputedValuesBorrowedOrNull};
|
use style::gecko_bindings::bindings::{nsHTMLCSSStyleSheet, ServoComputedValuesBorrowedOrNull};
|
||||||
use style::gecko_bindings::bindings::Gecko_Utf8SliceToString;
|
use style::gecko_bindings::bindings::Gecko_Utf8SliceToString;
|
||||||
use style::gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
|
|
||||||
use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom};
|
use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom};
|
||||||
use style::gecko_bindings::structs::ServoElementSnapshot;
|
use style::gecko_bindings::structs::ServoElementSnapshot;
|
||||||
use style::gecko_bindings::structs::nsRestyleHint;
|
use style::gecko_bindings::structs::nsRestyleHint;
|
||||||
use style::gecko_bindings::structs::nsString;
|
use style::gecko_bindings::structs::nsString;
|
||||||
use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI};
|
use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI};
|
||||||
use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong};
|
use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong};
|
||||||
|
use style::gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||||
use style::parallel;
|
use style::parallel;
|
||||||
use style::parser::{ParserContext, ParserContextExtraData};
|
use style::parser::{ParserContext, ParserContextExtraData};
|
||||||
use style::properties::{ComputedValues, Importance, PropertyDeclaration};
|
use style::properties::{ComputedValues, Importance, PropertyDeclaration};
|
||||||
|
@ -186,11 +186,11 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(bytes: *const u8,
|
||||||
|
|
||||||
let base_str = unsafe { from_utf8_unchecked(slice::from_raw_parts(base_bytes, base_length as usize)) };
|
let base_str = unsafe { from_utf8_unchecked(slice::from_raw_parts(base_bytes, base_length as usize)) };
|
||||||
let url = Url::parse(base_str).unwrap();
|
let url = Url::parse(base_str).unwrap();
|
||||||
let extra_data = ParserContextExtraData {
|
let extra_data = unsafe { ParserContextExtraData {
|
||||||
base: Some(GeckoArcURI::new(base)),
|
base: Some(GeckoArcURI::new(base)),
|
||||||
referrer: Some(GeckoArcURI::new(referrer)),
|
referrer: Some(GeckoArcURI::new(referrer)),
|
||||||
principal: Some(GeckoArcPrincipal::new(principal)),
|
principal: Some(GeckoArcPrincipal::new(principal)),
|
||||||
};
|
}};
|
||||||
let sheet = Arc::new(Stylesheet::from_str(input, url, origin, Box::new(StdoutErrorReporter),
|
let sheet = Arc::new(Stylesheet::from_str(input, url, origin, Box::new(StdoutErrorReporter),
|
||||||
extra_data));
|
extra_data));
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -390,11 +390,11 @@ pub extern "C" fn Servo_ParseProperty(property_bytes: *const u8,
|
||||||
let base_str = unsafe { from_utf8_unchecked(slice::from_raw_parts(base_bytes,
|
let base_str = unsafe { from_utf8_unchecked(slice::from_raw_parts(base_bytes,
|
||||||
base_length as usize)) };
|
base_length as usize)) };
|
||||||
let base_url = Url::parse(base_str).unwrap();
|
let base_url = Url::parse(base_str).unwrap();
|
||||||
let extra_data = ParserContextExtraData {
|
let extra_data = unsafe { ParserContextExtraData {
|
||||||
base: Some(GeckoArcURI::new(base)),
|
base: Some(GeckoArcURI::new(base)),
|
||||||
referrer: Some(GeckoArcURI::new(referrer)),
|
referrer: Some(GeckoArcURI::new(referrer)),
|
||||||
principal: Some(GeckoArcPrincipal::new(principal)),
|
principal: Some(GeckoArcPrincipal::new(principal)),
|
||||||
};
|
}};
|
||||||
|
|
||||||
let context = ParserContext::new_with_extra_data(Origin::Author, &base_url,
|
let context = ParserContext::new_with_extra_data(Origin::Author, &base_url,
|
||||||
Box::new(StdoutErrorReporter),
|
Box::new(StdoutErrorReporter),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue