Move gecko_bindings and gecko_string_cache into the style crate

This commit is contained in:
Manish Goregaokar 2016-09-22 14:58:23 +05:30
parent 0dd005eacc
commit c6787458d9
33 changed files with 2629 additions and 2688 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,18 @@
/* 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/. */
#[allow(dead_code, non_camel_case_types)]
pub mod bindings;
pub mod ptr;
#[cfg(debug_assertions)]
#[allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)]
pub mod structs {
include!("structs_debug.rs");
}
#[cfg(not(debug_assertions))]
#[allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)]
pub mod structs {
include!("structs_release.rs");
}
pub mod sugar;

View file

@ -0,0 +1,64 @@
/* 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);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
/* 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/. */
mod ns_css_shadow_array;
mod ns_style_auto_array;
pub mod ns_style_coord;
mod ns_t_array;
pub mod ownership;

View file

@ -0,0 +1,65 @@
/* 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::Gecko_AddRefCSSShadowArrayArbitraryThread;
use gecko_bindings::bindings::Gecko_NewCSSShadowArray;
use gecko_bindings::bindings::Gecko_ReleaseCSSShadowArrayArbitraryThread;
use std::{ptr, slice};
use std::ops::{Deref, DerefMut};
use gecko_bindings::structs::{RefPtr, nsCSSShadowArray, nsCSSShadowItem};
impl RefPtr<nsCSSShadowArray> {
pub fn replace_with_new(&mut self, len: u32) {
unsafe {
if !self.mRawPtr.is_null() {
Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr);
}
self.mRawPtr = if len == 0 {
ptr::null_mut()
} else {
Gecko_NewCSSShadowArray(len)
}
}
}
pub fn copy_from(&mut self, other: &Self) {
unsafe {
if !self.mRawPtr.is_null() {
Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr);
}
if !other.mRawPtr.is_null() {
Gecko_AddRefCSSShadowArrayArbitraryThread(other.mRawPtr);
}
self.mRawPtr = other.mRawPtr;
}
}
}
impl Deref for RefPtr<nsCSSShadowArray> {
type Target = [nsCSSShadowItem];
fn deref(&self) -> &[nsCSSShadowItem] {
if self.mRawPtr.is_null() {
&[]
} else {
unsafe {
slice::from_raw_parts((*self.mRawPtr).mArray.as_ptr(),
(*self.mRawPtr).mLength as usize)
}
}
}
}
impl DerefMut for RefPtr<nsCSSShadowArray> {
fn deref_mut(&mut self) -> &mut [nsCSSShadowItem] {
if self.mRawPtr.is_null() {
&mut []
} else {
unsafe {
slice::from_raw_parts_mut((*self.mRawPtr).mArray.as_mut_ptr(),
(*self.mRawPtr).mLength as usize)
}
}
}
}

View file

@ -0,0 +1,31 @@
/* 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 std::iter::{once, Chain, Once, IntoIterator};
use std::slice::{Iter, IterMut};
use gecko_bindings::structs::nsStyleAutoArray;
impl<T> nsStyleAutoArray<T> {
pub fn iter_mut(&mut self) -> Chain<Once<&mut T>, IterMut<T>> {
once(&mut self.mFirstElement).chain(self.mOtherElements.iter_mut())
}
pub fn iter(&self) -> Chain<Once<&T>, Iter<T>> {
once(&self.mFirstElement).chain(self.mOtherElements.iter())
}
// Note that often structs containing autoarrays will have
// additional member fields that contain the length, which must be kept
// in sync
pub fn len(&self) -> usize {
1 + self.mOtherElements.len()
}
}
impl<'a, T> IntoIterator for &'a mut nsStyleAutoArray<T> {
type Item = &'a mut T;
type IntoIter = Chain<Once<&'a mut T>, IterMut<'a, T>>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}

View file

@ -0,0 +1,397 @@
/* 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::{Gecko_ResetStyleCoord, Gecko_SetStyleCoordCalcValue, Gecko_AddRefCalcArbitraryThread};
use std::mem;
use gecko_bindings::structs::{nsStyleCoord_Calc, nsStyleUnit, nsStyleUnion, nsStyleCoord, nsStyleSides, nsStyleCorners};
use gecko_bindings::structs::{nsStyleCoord_CalcValue, nscoord};
impl nsStyleCoord {
#[inline]
pub fn null() -> Self {
// Can't construct directly because it has private fields
let mut coord: Self = unsafe { mem::zeroed() };
coord.leaky_set_null();
coord
}
}
impl CoordData for nsStyleCoord {
#[inline]
fn unit(&self) -> nsStyleUnit {
unsafe {
*self.get_mUnit()
}
}
#[inline]
fn union(&self) -> nsStyleUnion {
unsafe {
*self.get_mValue()
}
}
}
impl CoordDataMut for nsStyleCoord {
unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) {
let unit = self.get_mUnit_mut() as *mut _;
let value = self.get_mValue_mut() as *mut _;
(&mut *unit, &mut *value)
}
}
impl nsStyleCoord_CalcValue {
pub fn new() -> Self {
nsStyleCoord_CalcValue {
mLength: 0,
mPercent: 0.0,
mHasPercent: false,
}
}
}
impl nsStyleSides {
#[inline]
pub fn data_at(&self, index: usize) -> SidesData {
SidesData {
sides: self,
index: index,
}
}
#[inline]
pub fn data_at_mut(&mut self, index: usize) -> SidesDataMut {
SidesDataMut {
sides: self,
index: index,
}
}
}
pub struct SidesData<'a> {
sides: &'a nsStyleSides,
index: usize,
}
pub struct SidesDataMut<'a> {
sides: &'a mut nsStyleSides,
index: usize,
}
impl<'a> CoordData for SidesData<'a> {
#[inline]
fn unit(&self) -> nsStyleUnit {
unsafe {
self.sides.get_mUnits()[self.index]
}
}
#[inline]
fn union(&self) -> nsStyleUnion {
unsafe {
self.sides.get_mValues()[self.index]
}
}
}
impl<'a> CoordData for SidesDataMut<'a> {
#[inline]
fn unit(&self) -> nsStyleUnit {
unsafe {
self.sides.get_mUnits()[self.index]
}
}
#[inline]
fn union(&self) -> nsStyleUnion {
unsafe {
self.sides.get_mValues()[self.index]
}
}
}
impl<'a> CoordDataMut for SidesDataMut<'a> {
unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) {
let unit = &mut self.sides.get_mUnits_mut()[self.index] as *mut _;
let value = &mut self.sides.get_mValues_mut()[self.index] as *mut _;
(&mut *unit, &mut *value)
}
}
impl nsStyleCorners {
#[inline]
pub fn data_at(&self, index: usize) -> CornersData {
CornersData {
corners: self,
index: index,
}
}
#[inline]
pub fn data_at_mut(&mut self, index: usize) -> CornersDataMut {
CornersDataMut {
corners: self,
index: index,
}
}
}
pub struct CornersData<'a> {
corners: &'a nsStyleCorners,
index: usize,
}
pub struct CornersDataMut<'a> {
corners: &'a mut nsStyleCorners,
index: usize,
}
impl<'a> CoordData for CornersData<'a> {
fn unit(&self) -> nsStyleUnit {
unsafe {
self.corners.get_mUnits()[self.index]
}
}
fn union(&self) -> nsStyleUnion {
unsafe {
self.corners.get_mValues()[self.index]
}
}
}
impl<'a> CoordData for CornersDataMut<'a> {
fn unit(&self) -> nsStyleUnit {
unsafe {
self.corners.get_mUnits()[self.index]
}
}
fn union(&self) -> nsStyleUnion {
unsafe {
self.corners.get_mValues()[self.index]
}
}
}
impl<'a> CoordDataMut for CornersDataMut<'a> {
unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) {
let unit = &mut self.corners.get_mUnits_mut()[self.index] as *mut _;
let value = &mut self.corners.get_mValues_mut()[self.index] as *mut _;
(&mut *unit, &mut *value)
}
}
#[derive(Copy, Clone)]
/// Enum representing the tagged union that is CoordData.
/// In release mode this should never actually exist in the code,
/// and will be optimized out by threading matches and inlining.
pub enum CoordDataValue {
Null,
Normal,
Auto,
None,
Percent(f32),
Factor(f32),
Degree(f32),
Grad(f32),
Radian(f32),
Turn(f32),
FlexFraction(f32),
Coord(nscoord),
Integer(i32),
Enumerated(u32),
Calc(nsStyleCoord_CalcValue),
}
pub trait CoordDataMut : CoordData {
// This can't be two methods since we can't mutably borrow twice
/// This is unsafe since it's possible to modify
/// the unit without changing the union
unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion);
/// Clean up any resources used by the union
/// Currently, this only happens if the nsStyleUnit
/// is a Calc
#[inline]
fn reset(&mut self) {
unsafe {
if self.unit() == nsStyleUnit::eStyleUnit_Calc {
let (unit, union) = self.values_mut();
Gecko_ResetStyleCoord(unit, union);
}
}
}
#[inline]
fn copy_from<T: CoordData>(&mut self, other: &T) {
unsafe {
self.reset();
{
let (unit, union) = self.values_mut();
*unit = other.unit();
*union = other.union();
}
self.addref_if_calc();
}
}
#[inline]
unsafe fn copy_from_unchecked<T: CoordData>(&mut self, other: &T) {
let (unit, union) = self.values_mut();
*unit = other.unit();
*union = other.union();
}
/// Useful for initializing uninits
/// (set_value may segfault on uninits)
fn leaky_set_null(&mut self) {
use gecko_bindings::structs::nsStyleUnit::*;
unsafe {
let (unit, union) = self.values_mut();
*unit = eStyleUnit_Null;
*union.mInt.as_mut() = 0;
}
}
#[inline(always)]
fn set_value(&mut self, value: CoordDataValue) {
use self::CoordDataValue::*;
use gecko_bindings::structs::nsStyleUnit::*;
self.reset();
unsafe {
let (unit, union) = self.values_mut();
match value {
Null => {
*unit = eStyleUnit_Null;
*union.mInt.as_mut() = 0;
}
Normal => {
*unit = eStyleUnit_Normal;
*union.mInt.as_mut() = 0;
}
Auto => {
*unit = eStyleUnit_Auto;
*union.mInt.as_mut() = 0;
}
None => {
*unit = eStyleUnit_None;
*union.mInt.as_mut() = 0;
}
Percent(f) => {
*unit = eStyleUnit_Percent;
*union.mFloat.as_mut() = f;
}
Factor(f) => {
*unit = eStyleUnit_Factor;
*union.mFloat.as_mut() = f;
}
Degree(f) => {
*unit = eStyleUnit_Degree;
*union.mFloat.as_mut() = f;
}
Grad(f) => {
*unit = eStyleUnit_Grad;
*union.mFloat.as_mut() = f;
}
Radian(f) => {
*unit = eStyleUnit_Radian;
*union.mFloat.as_mut() = f;
}
Turn(f) => {
*unit = eStyleUnit_Turn;
*union.mFloat.as_mut() = f;
}
FlexFraction(f) => {
*unit = eStyleUnit_FlexFraction;
*union.mFloat.as_mut() = f;
}
Coord(coord) => {
*unit = eStyleUnit_Coord;
*union.mInt.as_mut() = coord;
}
Integer(i) => {
*unit = eStyleUnit_Integer;
*union.mInt.as_mut() = i;
}
Enumerated(i) => {
*unit = eStyleUnit_Enumerated;
*union.mInt.as_mut() = i as i32;
}
Calc(calc) => {
// Gecko_SetStyleCoordCalcValue changes the unit internally
Gecko_SetStyleCoordCalcValue(unit, union, calc);
}
}
}
}
#[inline]
unsafe fn as_calc_mut(&mut self) -> &mut nsStyleCoord_Calc {
debug_assert!(self.unit() == nsStyleUnit::eStyleUnit_Calc);
&mut *(*self.union().mPointer.as_mut() as *mut nsStyleCoord_Calc)
}
#[inline]
fn addref_if_calc(&mut self) {
unsafe {
if self.unit() == nsStyleUnit::eStyleUnit_Calc {
Gecko_AddRefCalcArbitraryThread(self.as_calc_mut());
}
}
}
}
pub trait CoordData {
fn unit(&self) -> nsStyleUnit;
fn union(&self) -> nsStyleUnion;
#[inline(always)]
fn as_value(&self) -> CoordDataValue {
use self::CoordDataValue::*;
use gecko_bindings::structs::nsStyleUnit::*;
unsafe {
match self.unit() {
eStyleUnit_Null => Null,
eStyleUnit_Normal => Normal,
eStyleUnit_Auto => Auto,
eStyleUnit_None => None,
eStyleUnit_Percent => Percent(self.get_float()),
eStyleUnit_Factor => Factor(self.get_float()),
eStyleUnit_Degree => Degree(self.get_float()),
eStyleUnit_Grad => Grad(self.get_float()),
eStyleUnit_Radian => Radian(self.get_float()),
eStyleUnit_Turn => Turn(self.get_float()),
eStyleUnit_FlexFraction => FlexFraction(self.get_float()),
eStyleUnit_Coord => Coord(self.get_integer()),
eStyleUnit_Integer => Integer(self.get_integer()),
eStyleUnit_Enumerated => Enumerated(self.get_integer() as u32),
eStyleUnit_Calc => Calc(self.get_calc_value()),
}
}
}
#[inline]
/// Pretend inner value is a float; obtain it.
unsafe fn get_float(&self) -> f32 {
use gecko_bindings::structs::nsStyleUnit::*;
debug_assert!(self.unit() == eStyleUnit_Percent || self.unit() == eStyleUnit_Factor
|| self.unit() == eStyleUnit_Degree || self.unit() == eStyleUnit_Grad
|| self.unit() == eStyleUnit_Radian || self.unit() == eStyleUnit_Turn
|| self.unit() == eStyleUnit_FlexFraction);
*self.union().mFloat.as_ref()
}
#[inline]
/// Pretend inner value is an int; obtain it.
unsafe fn get_integer(&self) -> i32 {
use gecko_bindings::structs::nsStyleUnit::*;
debug_assert!(self.unit() == eStyleUnit_Coord || self.unit() == eStyleUnit_Integer
|| self.unit() == eStyleUnit_Enumerated);
*self.union().mInt.as_ref()
}
#[inline]
/// Pretend inner value is a calc; obtain it.
/// Ensure that the unit is Calc before calling this.
unsafe fn get_calc_value(&self) -> nsStyleCoord_CalcValue {
debug_assert!(self.unit() == nsStyleUnit::eStyleUnit_Calc);
(*self.as_calc())._base
}
#[inline]
unsafe fn as_calc(&self) -> &nsStyleCoord_Calc {
debug_assert!(self.unit() == nsStyleUnit::eStyleUnit_Calc);
&*(*self.union().mPointer.as_ref() as *const nsStyleCoord_Calc)
}
}

View file

@ -0,0 +1,93 @@
/* 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 std::mem;
use std::ops::{Deref, DerefMut};
use std::os::raw::c_void;
use std::slice;
use gecko_bindings::structs::{nsTArray, nsTArrayHeader};
impl<T> Deref for nsTArray<T> {
type Target = [T];
fn deref<'a>(&'a self) -> &'a [T] {
unsafe {
slice::from_raw_parts(self.slice_begin(),
self.header().mLength as usize)
}
}
}
impl<T> DerefMut for nsTArray<T> {
fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
unsafe {
slice::from_raw_parts_mut(self.slice_begin(),
self.header().mLength as usize)
}
}
}
impl<T> nsTArray<T> {
#[inline]
fn header<'a>(&'a self) -> &'a nsTArrayHeader {
debug_assert!(!self.mBuffer.is_null());
unsafe { mem::transmute(self.mBuffer) }
}
// unsafe, since header may be in shared static or something
unsafe fn header_mut<'a>(&'a mut self) -> &'a mut nsTArrayHeader {
debug_assert!(!self.mBuffer.is_null());
mem::transmute(self.mBuffer)
}
#[inline]
unsafe fn slice_begin(&self) -> *mut T {
debug_assert!(!self.mBuffer.is_null());
(self.mBuffer as *const nsTArrayHeader).offset(1) as *mut _
}
/// Ensures the array has enough capacity at least to hold `cap` elements.
///
/// NOTE: This doesn't call the constructor on the values!
pub fn ensure_capacity(&mut self, cap: usize) {
if cap >= self.len() {
unsafe {
bindings::Gecko_EnsureTArrayCapacity(self as *mut nsTArray<T> as *mut _,
cap, mem::size_of::<T>())
}
}
}
/// Clears the array storage without calling the destructor on the values.
#[inline]
pub unsafe fn clear(&mut self) {
if self.len() != 0 {
bindings::Gecko_ClearPODTArray(self as *mut nsTArray<T> as *mut _,
mem::size_of::<T>(),
mem::align_of::<T>());
}
}
/// Clears a POD array. This is safe since copy types are memcopyable.
#[inline]
pub fn clear_pod(&mut self)
where T: Copy
{
unsafe { self.clear() }
}
// unsafe because the array may contain uninits
// This will not call constructors, either manually
// add bindings or run the typed ensurecapacity call
// on the gecko side
pub unsafe fn set_len(&mut self, len: u32) {
// this can leak
debug_assert!(len >= self.len() as u32);
self.ensure_capacity(len as usize);
let mut header = self.header_mut();
header.mLength = len;
}
}

View file

@ -0,0 +1,397 @@
/* 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 std::marker::PhantomData;
use std::mem::{forget, transmute};
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::sync::Arc;
/// Indicates that a given Servo type has a corresponding
/// Gecko FFI type
/// The correspondence is not defined at this stage,
/// use HasArcFFI or similar traits to define it
pub unsafe trait HasFFI : Sized {
type FFIType: Sized;
}
/// Indicates that a given Servo type has the same layout
/// as the corresponding HasFFI::FFIType type
pub unsafe trait HasSimpleFFI : HasFFI {
#[inline]
/// Given a Servo-side reference, converts it to an
/// FFI-safe reference which can be passed to Gecko
///
/// &ServoType -> &GeckoType
fn as_ffi(&self) -> &Self::FFIType {
unsafe { transmute(self) }
}
#[inline]
/// Given a Servo-side mutable reference, converts it to an
/// FFI-safe mutable reference which can be passed to Gecko
///
/// &mut ServoType -> &mut GeckoType
fn as_ffi_mut(&mut self) -> &mut Self::FFIType {
unsafe { transmute(self) }
}
#[inline]
/// Given an FFI-safe reference obtained from Gecko
/// converts it to a Servo-side reference
///
/// &GeckoType -> &ServoType
fn from_ffi(ffi: &Self::FFIType) -> &Self {
unsafe { transmute(ffi) }
}
#[inline]
/// Given an FFI-safe mutable reference obtained from Gecko
/// converts it to a Servo-side mutable reference
///
/// &mut GeckoType -> &mut ServoType
fn from_ffi_mut(ffi: &mut Self::FFIType) -> &mut Self {
unsafe { transmute(ffi) }
}
}
/// Indicates that the given Servo type is passed over FFI
/// as a Box
pub unsafe trait HasBoxFFI : HasSimpleFFI {
#[inline]
fn into_ffi(self: Box<Self>) -> Owned<Self::FFIType> {
unsafe { transmute(self) }
}
}
/// Helper trait for conversions between FFI Strong/Borrowed types and Arcs
///
/// Should be implemented by types which are passed over FFI as Arcs
/// via Strong and Borrowed
///
/// In this case, the FFIType is the rough equivalent of ArcInner<Self>
pub unsafe trait HasArcFFI : HasFFI {
// these methods can't be on Borrowed because it leads to an unspecified
// impl parameter
/// Artificially increments the refcount of a (possibly null) borrowed Arc over FFI.
unsafe fn addref_opt(ptr: Borrowed<Self::FFIType>) {
forget(ptr.as_arc_opt::<Self>().clone())
}
/// Given a (possibly null) borrowed FFI reference, decrements the refcount.
/// Unsafe since it doesn't consume the backing Arc. Run it only when you
/// know that a strong reference to the backing Arc is disappearing
/// (usually on the C++ side) without running the Arc destructor.
unsafe fn release_opt(ptr: Borrowed<Self::FFIType>) {
if let Some(arc) = ptr.as_arc_opt::<Self>() {
let _: Arc<_> = ptr::read(arc as *const Arc<_>);
}
}
/// Artificially increments the refcount of a borrowed Arc over FFI.
unsafe fn addref(ptr: &Self::FFIType) {
forget(Self::as_arc(&ptr).clone())
}
/// Given a non-null borrowed FFI reference, decrements the refcount.
/// Unsafe since it doesn't consume the backing Arc. Run it only when you
/// know that a strong reference to the backing Arc is disappearing
/// (usually on the C++ side) without running the Arc destructor.
unsafe fn release(ptr: &Self::FFIType) {
let _: Arc<_> = ptr::read(Self::as_arc(&ptr) as *const Arc<_>);
}
#[inline]
/// Converts a borrowed FFI reference to a borrowed Arc.
///
/// &GeckoType -> &Arc<ServoType>
fn as_arc<'a>(ptr: &'a &Self::FFIType) -> &'a Arc<Self> {
debug_assert!(!(ptr as *const _).is_null());
unsafe {
transmute::<&&Self::FFIType, &Arc<Self>>(ptr)
}
}
}
#[repr(C)]
/// Gecko-FFI-safe borrowed type
/// This can be null.
pub struct Borrowed<'a, T: 'a> {
ptr: *const T,
_marker: PhantomData<&'a T>,
}
#[repr(C)]
/// Gecko-FFI-safe mutably borrowed type
/// This can be null.
pub struct BorrowedMut<'a, T: 'a> {
ptr: *mut T,
_marker: PhantomData<&'a mut T>,
}
// manual impls because derive doesn't realize that `T: Clone` isn't necessary
impl<'a, T> Copy for Borrowed<'a, T> {}
impl<'a, T> Clone for Borrowed<'a, T> {
#[inline]
fn clone(&self) -> Self { *self }
}
impl<'a, T> Borrowed<'a, T> {
#[inline]
pub fn is_null(self) -> bool {
self.ptr == ptr::null()
}
#[inline]
/// Like Deref, but gives an Option
pub fn borrow_opt(self) -> Option<&'a T> {
if self.is_null() {
None
} else {
Some(unsafe { &*self.ptr })
}
}
#[inline]
/// Borrowed<GeckoType> -> Option<&Arc<ServoType>>
pub fn as_arc_opt<U>(&self) -> Option<&Arc<U>> where U: HasArcFFI<FFIType = T> {
unsafe {
if self.is_null() {
None
} else {
Some(transmute::<&Borrowed<_>, &Arc<_>>(self))
}
}
}
#[inline]
/// Converts a borrowed FFI reference to a borrowed Arc.
/// Panics on null.
///
/// &Borrowed<GeckoType> -> &Arc<ServoType>
pub fn as_arc<U>(&self) -> &Arc<U> where U: HasArcFFI<FFIType = T> {
self.as_arc_opt().unwrap()
}
#[inline]
/// Borrowed<ServoType> -> Borrowed<GeckoType>
pub fn as_ffi(self) -> Borrowed<'a, <Self as HasFFI>::FFIType> where Self: HasSimpleFFI {
unsafe { transmute(self) }
}
#[inline]
/// Borrowed<GeckoType> -> Borrowed<ServoType>
pub fn from_ffi<U>(self) -> Borrowed<'a, U> where U: HasSimpleFFI<FFIType = T> {
unsafe { transmute(self) }
}
#[inline]
/// Borrowed<GeckoType> -> &ServoType
pub fn as_servo_ref<U>(self) -> Option<&'a U> where U: HasSimpleFFI<FFIType = T> {
self.borrow_opt().map(HasSimpleFFI::from_ffi)
}
pub fn null() -> Borrowed<'static, T> {
Borrowed {
ptr: ptr::null_mut(),
_marker: PhantomData
}
}
}
impl<'a, T> BorrowedMut<'a, T> {
#[inline]
/// Like DerefMut, but gives an Option
pub fn borrow_mut_opt(self) -> Option<&'a mut T> {
// We have two choices for the signature here, it can either be
// Self -> Option<&'a mut T> or
// &'b mut Self -> Option<'b mut T>
// The former consumes the BorrowedMut (which isn't Copy),
// which can be annoying. The latter only temporarily
// borrows it, so the return value can't exit the scope
// even if Self has a longer lifetime ('a)
//
// This is basically the implicit "reborrow" pattern used with &mut
// not cleanly translating to our custom types.
// I've chosen the former solution -- you can manually convert back
// if you need to reuse the BorrowedMut.
if self.is_null() {
None
} else {
Some(unsafe { &mut *self.ptr })
}
}
#[inline]
/// BorrowedMut<GeckoType> -> &mut ServoType
pub fn as_servo_mut_ref<U>(self) -> Option<&'a mut U> where U: HasSimpleFFI<FFIType = T> {
self.borrow_mut_opt().map(HasSimpleFFI::from_ffi_mut)
}
pub fn null_mut() -> BorrowedMut<'static, T> {
BorrowedMut {
ptr: ptr::null_mut(),
_marker: PhantomData
}
}
}
// technically not how we're supposed to use
// Deref, but that's a minor style issue
impl<'a, T> Deref for BorrowedMut<'a, T> {
type Target = Borrowed<'a, T>;
fn deref(&self) -> &Self::Target {
unsafe { transmute(self) }
}
}
#[repr(C)]
/// Gecko-FFI-safe Arc (T is an ArcInner).
/// This can be null.
/// Leaks on drop. Please don't drop this.
/// TODO: Add destructor bomb once drop flags are gone
pub struct Strong<T> {
ptr: *const T,
_marker: PhantomData<T>,
}
impl<T> Strong<T> {
#[inline]
pub fn is_null(&self) -> bool {
self.ptr == ptr::null()
}
#[inline]
/// Given a non-null strong FFI reference,
/// converts it into a servo-side Arc
/// Panics on null.
///
/// Strong<GeckoType> -> Arc<ServoType>
pub fn into_arc<U>(self) -> Arc<U> where U: HasArcFFI<FFIType = T> {
self.into_arc_opt().unwrap()
}
#[inline]
/// Given a strong FFI reference,
/// converts it into a servo-side Arc
/// Returns None on null.
///
/// Strong<GeckoType> -> Arc<ServoType>
pub fn into_arc_opt<U>(self) -> Option<Arc<U>> where U: HasArcFFI<FFIType = T> {
if self.is_null() {
None
} else {
unsafe { Some(transmute(self)) }
}
}
#[inline]
/// Produces a null strong FFI reference
pub fn null() -> Self {
unsafe { transmute(ptr::null::<T>()) }
}
}
pub unsafe trait FFIArcHelpers {
type Inner: HasArcFFI;
/// Converts an Arc into a strong FFI reference.
///
/// Arc<ServoType> -> Strong<GeckoType>
fn into_strong(self) -> Strong<<Self::Inner as HasFFI>::FFIType>;
/// Produces a (nullable) borrowed FFI reference by borrowing an Arc.
///
/// &Arc<ServoType> -> Borrowed<GeckoType>
fn as_borrowed_opt(&self) -> Borrowed<<Self::Inner as HasFFI>::FFIType>;
/// Produces a borrowed FFI reference by borrowing an Arc.
///
/// &Arc<ServoType> -> &GeckoType
fn as_borrowed(&self) -> &<Self::Inner as HasFFI>::FFIType;
}
unsafe impl<T: HasArcFFI> FFIArcHelpers for Arc<T> {
type Inner = T;
#[inline]
fn into_strong(self) -> Strong<T::FFIType> {
unsafe { transmute(self) }
}
#[inline]
fn as_borrowed_opt(&self) -> Borrowed<T::FFIType> {
let borrowedptr = self as *const Arc<T> as *const Borrowed<T::FFIType>;
unsafe { ptr::read(borrowedptr) }
}
#[inline]
fn as_borrowed(&self) -> &T::FFIType {
let borrowedptr = self as *const Arc<T> as *const & T::FFIType;
unsafe { ptr::read(borrowedptr) }
}
}
#[repr(C)]
/// Gecko-FFI-safe owned pointer
/// Cannot be null
/// Leaks on drop. Please don't drop this.
pub struct Owned<T> {
ptr: *mut T,
_marker: PhantomData<T>,
}
impl<T> Owned<T> {
/// Owned<GeckoType> -> Box<ServoType>
pub fn into_box<U>(self) -> Box<T> where U: HasBoxFFI<FFIType = T> {
unsafe { transmute(self) }
}
pub fn maybe(self) -> OwnedOrNull<T> {
unsafe { transmute(self) }
}
}
impl<T> Deref for Owned<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.ptr }
}
}
impl<T> DerefMut for Owned<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.ptr }
}
}
#[repr(C)]
/// Gecko-FFI-safe owned pointer
/// Can be null
pub struct OwnedOrNull<T> {
ptr: *mut T,
_marker: PhantomData<T>,
}
impl<T> OwnedOrNull<T> {
pub fn is_null(&self) -> bool {
self.ptr == ptr::null_mut()
}
/// OwnedOrNull<GeckoType> -> Option<Box<ServoType>>
pub fn into_box_opt<U>(self) -> Option<Box<T>> where U: HasBoxFFI<FFIType = T> {
if self.is_null() {
None
} else {
Some(unsafe { transmute(self) })
}
}
/// OwnedOrNull<GeckoType> -> Option<Owned<GeckoType>>
pub fn into_owned_opt(self) -> Option<Owned<T>> {
if self.is_null() {
None
} else {
Some(unsafe { transmute(self) })
}
}
pub fn borrow(&self) -> Borrowed<T> {
unsafe { transmute(self) }
}
pub fn borrow_mut(&self) -> BorrowedMut<T> {
unsafe { transmute(self) }
}
}