use jsapi::JS;
use jsapi::jsid;
use jsapi::JSFlatString;
use jsapi::JSFunction;
use jsapi::JSObject;
use jsapi::JSScript;
use jsapi::JSString;
use jsapi::JSTracer;
use jsid::JSID_VOID;
use std::cell::UnsafeCell;
use std::mem;
use std::os::raw::c_void;
use std::ptr;
pub trait RootKind {
#[allow(non_snake_case)]
#[inline(always)]
fn rootKind() -> JS::RootKind;
}
impl RootKind for *mut JSObject {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::Object }
}
impl RootKind for *mut JSFlatString {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::String }
}
impl RootKind for *mut JSFunction {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::Object }
}
impl RootKind for *mut JSString {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::String }
}
impl RootKind for *mut JS::Symbol {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::Symbol }
}
impl RootKind for *mut JSScript {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::Script }
}
impl RootKind for jsid {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::Id }
}
impl RootKind for JS::Value {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::Value }
}
impl RootKind for JS::PropertyDescriptor {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::Traceable }
}
#[repr(C)]
#[derive(Debug)]
pub struct Rooted<T> {
pub stack: *mut *mut Rooted<*mut c_void>,
pub prev: *mut Rooted<*mut c_void>,
pub ptr: T,
}
pub trait GCMethods {
unsafe fn initial() -> Self;
unsafe fn post_barrier(v: *mut Self, prev: Self, next: Self);
}
impl GCMethods for jsid {
unsafe fn initial() -> jsid { JSID_VOID }
unsafe fn post_barrier(_: *mut jsid, _: jsid, _: jsid) {}
}
impl GCMethods for *mut JSObject {
unsafe fn initial() -> *mut JSObject { ptr::null_mut() }
unsafe fn post_barrier(v: *mut *mut JSObject,
prev: *mut JSObject, next: *mut JSObject) {
JS::HeapObjectPostBarrier(v, prev, next);
}
}
impl GCMethods for *mut JSString {
unsafe fn initial() -> *mut JSString { ptr::null_mut() }
unsafe fn post_barrier(_: *mut *mut JSString, _: *mut JSString, _: *mut JSString) {}
}
impl GCMethods for *mut JSScript {
unsafe fn initial() -> *mut JSScript { ptr::null_mut() }
unsafe fn post_barrier(_: *mut *mut JSScript, _: *mut JSScript, _: *mut JSScript) { }
}
impl GCMethods for *mut JSFunction {
unsafe fn initial() -> *mut JSFunction { ptr::null_mut() }
unsafe fn post_barrier(v: *mut *mut JSFunction,
prev: *mut JSFunction, next: *mut JSFunction) {
JS::HeapObjectPostBarrier(mem::transmute(v),
mem::transmute(prev), mem::transmute(next));
}
}
impl GCMethods for JS::Value {
unsafe fn initial() -> JS::Value { JS::Value::default() }
unsafe fn post_barrier(v: *mut JS::Value, prev: JS::Value, next: JS::Value) {
JS::HeapValuePostBarrier(v, &prev, &next);
}
}
impl GCMethods for JS::PropertyDescriptor {
unsafe fn initial() -> JS::PropertyDescriptor { JS::PropertyDescriptor::default() }
unsafe fn post_barrier(_ : *mut JS::PropertyDescriptor, _ : JS::PropertyDescriptor, _ : JS::PropertyDescriptor) {}
}
#[repr(C)]
#[derive(Debug)]
pub struct Heap<T: GCMethods + Copy> {
pub ptr: UnsafeCell<T>,
}
impl<T: GCMethods + Copy> Heap<T> {
pub fn boxed(v: T) -> Box<Heap<T>>
where Heap<T>: Default
{
let boxed = Box::new(Heap::default());
boxed.set(v);
boxed
}
pub fn set(&self, v: T) {
unsafe {
let ptr = self.ptr.get();
let prev = *ptr;
*ptr = v;
T::post_barrier(ptr, prev, v);
}
}
pub fn get(&self) -> T {
unsafe { *self.ptr.get() }
}
pub fn get_unsafe(&self) -> *mut T {
self.ptr.get()
}
pub fn handle_mut(&self) -> JS::MutableHandle<T> {
unsafe {
JS::MutableHandle::from_marked_location(self.ptr.get())
}
}
pub unsafe fn handle(&self) -> JS::Handle<T> {
JS::Handle::from_marked_location(self.ptr.get() as *const _)
}
}
impl<T> Default for Heap<*mut T>
where *mut T: GCMethods + Copy
{
fn default() -> Heap<*mut T> {
Heap {
ptr: UnsafeCell::new(ptr::null_mut())
}
}
}
impl Default for Heap<JS::Value> {
fn default() -> Heap<JS::Value> {
Heap {
ptr: UnsafeCell::new(JS::Value::default())
}
}
}
impl<T: GCMethods + Copy> Drop for Heap<T> {
fn drop(&mut self) {
unsafe {
let ptr = self.ptr.get();
T::post_barrier(ptr, *ptr, T::initial());
}
}
}
impl<T: GCMethods + Copy + PartialEq> PartialEq for Heap<T> {
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
pub trait IntoHandle {
type Target;
fn into_handle(self) -> JS::Handle<Self::Target>;
}
pub trait IntoMutableHandle: IntoHandle {
fn into_handle_mut(self) -> JS::MutableHandle<Self::Target>;
}
impl<T: IntoHandle> From<T> for JS::Handle<T::Target> {
fn from(value: T) -> Self {
value.into_handle()
}
}
impl<T: IntoMutableHandle> From<T> for JS::MutableHandle<T::Target> {
fn from(value: T) -> Self {
value.into_handle_mut()
}
}
#[repr(C)]
pub struct CustomAutoRooterVFTable {
#[cfg(windows)]
pub padding: [usize; 1],
#[cfg(not(windows))]
pub padding: [usize; 2],
pub trace: unsafe extern "C" fn (this: *mut c_void, trc: *mut JSTracer),
}
impl CustomAutoRooterVFTable {
#[cfg(windows)]
pub const PADDING: [usize; 1] = [0];
#[cfg(not(windows))]
pub const PADDING: [usize; 2] = [0, 0];
}