mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +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)]
|
||||
pub mod bindings;
|
||||
pub mod ptr;
|
||||
|
||||
// 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
|
||||
|
|
|
@ -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;
|
||||
mod ns_t_array;
|
||||
pub mod ownership;
|
||||
pub mod refptr;
|
||||
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 error_reporting::ParseErrorReporter;
|
||||
#[cfg(feature = "gecko")]
|
||||
use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||
use selector_impl::TheSelectorImpl;
|
||||
use selectors::parser::ParserContext as SelectorParserContext;
|
||||
use stylesheets::Origin;
|
||||
|
|
|
@ -896,9 +896,9 @@ fn static_assert() {
|
|||
Gecko_SetMozBinding(&mut self.gecko,
|
||||
url.as_str().as_ptr(),
|
||||
url.as_str().len() as u32,
|
||||
extra_data.base.as_raw(),
|
||||
extra_data.referrer.as_raw(),
|
||||
extra_data.principal.as_raw());
|
||||
extra_data.base.get(),
|
||||
extra_data.referrer.get(),
|
||||
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
|
||||
<%helpers:longhand name="-moz-binding" products="gecko" animatable="False" disable_when_testing="True">
|
||||
use cssparser::{CssStringWriter, ToCss};
|
||||
use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||
use std::fmt::{self, Write};
|
||||
use url::Url;
|
||||
use values::specified::UrlExtraData;
|
||||
|
|
|
@ -6,7 +6,7 @@ use app_units::Au;
|
|||
use cssparser::{self, Parser, ToCss, Token};
|
||||
use euclid::size::Size2D;
|
||||
#[cfg(feature = "gecko")]
|
||||
use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||
use parser::{Parse, ParserContext};
|
||||
#[cfg(feature = "gecko")]
|
||||
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::{nsHTMLCSSStyleSheet, ServoComputedValuesBorrowedOrNull};
|
||||
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::ServoElementSnapshot;
|
||||
use style::gecko_bindings::structs::nsRestyleHint;
|
||||
use style::gecko_bindings::structs::nsString;
|
||||
use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI};
|
||||
use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong};
|
||||
use style::gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||
use style::parallel;
|
||||
use style::parser::{ParserContext, ParserContextExtraData};
|
||||
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 url = Url::parse(base_str).unwrap();
|
||||
let extra_data = ParserContextExtraData {
|
||||
let extra_data = unsafe { ParserContextExtraData {
|
||||
base: Some(GeckoArcURI::new(base)),
|
||||
referrer: Some(GeckoArcURI::new(referrer)),
|
||||
principal: Some(GeckoArcPrincipal::new(principal)),
|
||||
};
|
||||
}};
|
||||
let sheet = Arc::new(Stylesheet::from_str(input, url, origin, Box::new(StdoutErrorReporter),
|
||||
extra_data));
|
||||
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,
|
||||
base_length as usize)) };
|
||||
let base_url = Url::parse(base_str).unwrap();
|
||||
let extra_data = ParserContextExtraData {
|
||||
let extra_data = unsafe { ParserContextExtraData {
|
||||
base: Some(GeckoArcURI::new(base)),
|
||||
referrer: Some(GeckoArcURI::new(referrer)),
|
||||
principal: Some(GeckoArcPrincipal::new(principal)),
|
||||
};
|
||||
}};
|
||||
|
||||
let context = ParserContext::new_with_extra_data(Origin::Author, &base_url,
|
||||
Box::new(StdoutErrorReporter),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue