diff options
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 203 | ||||
-rw-r--r-- | components/script/dom/bindings/interface.rs | 155 | ||||
-rw-r--r-- | components/script/dom/bindings/mod.rs | 1 | ||||
-rw-r--r-- | components/script/dom/bindings/utils.rs | 202 |
4 files changed, 261 insertions, 300 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 8ff336566d6..067e5b76386 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2355,30 +2355,6 @@ class PropertyArrays(): return define -class CGNativeProperties(CGThing): - def __init__(self, descriptor, properties): - CGThing.__init__(self) - self.properties = properties - - def define(self): - def getField(array): - propertyArray = getattr(self.properties, array) - if propertyArray.length() > 0: - value = "Some(%s)" % propertyArray.variableName() - else: - value = "None" - - return CGGeneric(string.Template('${name}: ${value},').substitute({ - 'name': array, - 'value': value, - })) - - nativeProps = CGList([getField(array) for array in self.properties.arrayNames()], '\n') - return CGWrapper(CGIndenter(nativeProps), - pre="static sNativeProperties: NativeProperties = NativeProperties {\n", - post="\n};\n").define() - - class CGCreateInterfaceObjectsMethod(CGAbstractMethod): """ Generate the CreateInterfaceObjects method for an interface descriptor. @@ -2389,59 +2365,85 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'), Argument('HandleObject', 'receiver'), Argument('MutableHandleObject', 'rval')] - CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args) + CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args, + unsafe=True) self.properties = properties def definition_body(self): + name = self.descriptor.interface.identifier.name + if self.descriptor.interface.isCallback(): + assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants() + return CGGeneric("""\ +create_callback_interface_object(cx, receiver, throwing_constructor, 0, sConstants, %s);""" % str_to_const_array(name)) + protoChain = self.descriptor.prototypeChain if len(protoChain) == 1: - self.unsafe = True - getParentProto = "parent_proto.ptr = JS_GetObjectPrototype(cx, global)" + getPrototypeProto = "prototype_proto.ptr = JS_GetObjectPrototype(cx, global)" else: - parentProtoName = self.descriptor.prototypeChain[-2] - getParentProto = ("%s::GetProtoObject(cx, global, receiver, parent_proto.handle_mut())" % - toBindingNamespace(parentProtoName)) - - getParentProto = ("let mut parent_proto = RootedObject::new(cx, ptr::null_mut());\n" - "%s;\n" - "assert!(!parent_proto.ptr.is_null());\n") % getParentProto - - if self.descriptor.interface.isCallback(): - protoClass = "None" - else: - protoClass = "Some(&PrototypeClass)" + getPrototypeProto = ("%s::GetProtoObject(cx, global, receiver, prototype_proto.handle_mut())" % + toBindingNamespace(self.descriptor.prototypeChain[-2])) + + code = [CGGeneric("""\ +let mut prototype_proto = RootedObject::new(cx, ptr::null_mut()); +%s; +assert!(!prototype_proto.ptr.is_null());""" % getPrototypeProto)] + + properties = {"id": name} + for arrayName in self.properties.arrayNames(): + array = getattr(self.properties, arrayName) + if arrayName == "consts": + if array.length(): + properties[arrayName] = array.variableName() + else: + properties[arrayName] = "&[]" + elif array.length(): + properties[arrayName] = "Some(%s)" % array.variableName() + else: + properties[arrayName] = "None" + + code.append(CGGeneric(""" +create_interface_prototype_object(cx, + prototype_proto.handle(), + &PrototypeClass, + %(methods)s, + %(attrs)s, + %(consts)s, + rval); +assert!(!rval.ptr.is_null());""" % properties)) if self.descriptor.interface.hasInterfaceObject(): + properties["name"] = str_to_const_array(name) if self.descriptor.interface.ctor(): - constructHook = CONSTRUCT_HOOK_NAME - constructArgs = methodLength(self.descriptor.interface.ctor()) + properties["constructor"] = CONSTRUCT_HOOK_NAME + properties["length"] = methodLength(self.descriptor.interface.ctor()) else: - constructHook = "throwing_constructor" - constructArgs = 0 - - constructor = 'Some((%s as NonNullJSNative, "%s", %d))' % ( - constructHook, self.descriptor.interface.identifier.name, - constructArgs) - else: - constructor = 'None' - - call = """\ -do_create_interface_objects(cx, receiver, parent_proto.handle(), - %s, %s, - &named_constructors, - &sNativeProperties, rval);""" % (protoClass, constructor) - - createArray = """\ -let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [ -""" % len(self.descriptor.interface.namedConstructors) - for ctor in self.descriptor.interface.namedConstructors: - constructHook = CONSTRUCT_HOOK_NAME + "_" + ctor.identifier.name - constructArgs = methodLength(ctor) - constructor = '(%s as NonNullJSNative, "%s", %d)' % ( - constructHook, ctor.identifier.name, constructArgs) - createArray += constructor - createArray += "," - createArray += "];" + properties["constructor"] = "throwing_constructor" + properties["length"] = 0 + + code.append(CGGeneric("""\ + +create_noncallback_interface_object(cx, + receiver, + %(constructor)s, + %(static_methods)s, + %(static_attrs)s, + %(consts)s, + rval.handle(), + %(name)s, + %(length)s);""" % properties)) + + constructors = self.descriptor.interface.namedConstructors + if constructors: + decl = "let named_constructors: [(NonNullJSNative, &'static [u8], u32); %d]" % len(constructors) + specs = [] + for constructor in constructors: + hook = CONSTRUCT_HOOK_NAME + "_" + constructor.identifier.name + name = str_to_const_array(constructor.identifier.name) + length = methodLength(constructor) + specs.append(CGGeneric("(%s as NonNullJSNative, %s, %d)" % (hook, name, length))) + values = CGIndenter(CGList(specs, "\n"), 4) + code.append(CGWrapper(values, pre="%s = [\n" % decl, post="\n];")) + code.append(CGGeneric("create_named_constructors(cx, receiver, &named_constructors, rval.handle());")) if self.descriptor.hasUnforgeableMembers: # We want to use the same JSClass and prototype as the object we'll @@ -2457,41 +2459,22 @@ let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [ # the prototype. if self.descriptor.proxy or self.descriptor.isGlobal(): holderClass = "ptr::null()" - holderProto = "ptr::null_mut()" + holderProto = "HandleObject::null()" else: holderClass = "&Class.base as *const js::jsapi::Class as *const JSClass" - holderProto = "rval.get()" - # JS_NewObjectWithoutMetadata() is unsafe. - self.unsafe = True - createUnforgeableHolder = CGGeneric(""" + holderProto = "rval.handle()" + code.append(CGGeneric(""" let mut unforgeable_holder = RootedObject::new(cx, ptr::null_mut()); -{ - let holder_class = %(holderClass)s; - let holder_proto = RootedObject::new(cx, %(holderProto)s); - unforgeable_holder.handle_mut().set( - JS_NewObjectWithoutMetadata(cx, holder_class, holder_proto.handle())); - assert!(!unforgeable_holder.ptr.is_null()); -}""" % {'holderClass': holderClass, 'holderProto': holderProto}) - defineUnforgeables = InitUnforgeablePropertiesOnHolder(self.descriptor, - self.properties) - createUnforgeableHolder = CGList( - [createUnforgeableHolder, defineUnforgeables], "\n") - - installUnforgeableHolder = CGGeneric("""\ +unforgeable_holder.handle_mut().set( + JS_NewObjectWithoutMetadata(cx, %(holderClass)s, %(holderProto)s)); +assert!(!unforgeable_holder.ptr.is_null()); +""" % {'holderClass': holderClass, 'holderProto': holderProto})) + code.append(InitUnforgeablePropertiesOnHolder(self.descriptor, self.properties)) + code.append(CGGeneric("""\ JS_SetReservedSlot(rval.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, - ObjectValue(&*unforgeable_holder.ptr))""") - - unforgeableHolderSetup = CGList( - [createUnforgeableHolder, installUnforgeableHolder], "\n") - else: - unforgeableHolderSetup = None + ObjectValue(&*unforgeable_holder.ptr))""")) - return CGList([ - CGGeneric(getParentProto), - CGGeneric(createArray), - CGGeneric(call % self.properties.variableNames()), - unforgeableHolderSetup, - ], "\n") + return CGList(code, "\n") class CGGetPerInterfaceObject(CGAbstractMethod): @@ -4883,7 +4866,6 @@ class CGDescriptor(CGThing): properties = PropertyArrays(descriptor) cgThings.append(CGGeneric(str(properties))) - cgThings.append(CGNativeProperties(descriptor, properties)) cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties)) cgThings.append(CGNamespace.build([descriptor.name + "Constants"], @@ -5271,16 +5253,16 @@ class CGBindingRoot(CGThing): 'js::jsapi::{HandleId, HandleObject, HandleValue, HandleValueArray}', 'js::jsapi::{INTERNED_STRING_TO_JSID, IsCallable, JS_CallFunctionValue}', 'js::jsapi::{JS_ComputeThis, JS_CopyPropertiesFrom, JS_ForwardGetPropertyTo}', - 'js::jsapi::{JS_GetClass, JS_GetGlobalForObject, JS_GetObjectPrototype}', - 'js::jsapi::{JS_GetProperty, JS_GetPropertyById, JS_GetPropertyDescriptorById}', - 'js::jsapi::{JS_GetReservedSlot, JS_HasProperty, JS_HasPropertyById}', - 'js::jsapi::{JS_InitializePropertiesFromCompatibleNativeObject, JS_InternString}', - 'js::jsapi::{JS_IsExceptionPending, JS_NewObject, JS_NewObjectWithGivenProto}', - 'js::jsapi::{JS_NewObjectWithoutMetadata, JS_SetProperty, JS_SetPrototype}', - 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSAutoCompartment, JSAutoRequest}', - 'js::jsapi::{JSContext, JSClass, JSFreeOp, JSFunctionSpec, JSJitGetterCallArgs}', - 'js::jsapi::{JSJitInfo, JSJitMethodCallArgs, JSJitSetterCallArgs, JSNative}', - 'js::jsapi::{JSObject, JSNativeWrapper, JSPropertyDescriptor, JSPropertySpec}', + 'js::jsapi::{JS_GetClass, JS_GetFunctionPrototype, JS_GetGlobalForObject}', + 'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}', + 'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot, JS_HasProperty}', + 'js::jsapi::{JS_HasPropertyById, JS_InitializePropertiesFromCompatibleNativeObject}', + 'js::jsapi::{JS_InternString, JS_IsExceptionPending, JS_NewObject}', + 'js::jsapi::{JS_NewObjectWithGivenProto, JS_NewObjectWithoutMetadata, JS_SetProperty}', + 'js::jsapi::{JS_SetPrototype, JS_SetReservedSlot, JS_WrapValue, JSAutoCompartment}', + 'js::jsapi::{JSAutoRequest, JSContext, JSClass, JSFreeOp, JSFunctionSpec}', + 'js::jsapi::{JSJitGetterCallArgs, JSJitInfo, JSJitMethodCallArgs, JSJitSetterCallArgs}', + 'js::jsapi::{JSNative, JSObject, JSNativeWrapper, JSPropertyDescriptor, JSPropertySpec}', 'js::jsapi::{JSString, JSTracer, JSType, JSTypedMethodJitInfo, JSValueType}', 'js::jsapi::{ObjectOpResult, OpType, MutableHandle, MutableHandleObject}', 'js::jsapi::{MutableHandleValue, RootedId, RootedObject, RootedString}', @@ -5296,13 +5278,14 @@ class CGBindingRoot(CGThing): 'js::rust::{GCMethods, define_methods, define_properties}', 'dom::bindings', 'dom::bindings::global::{GlobalRef, global_root_from_object, global_root_from_reflector}', + 'dom::bindings::interface::{create_callback_interface_object, create_interface_prototype_object}', + 'dom::bindings::interface::{create_named_constructors, create_noncallback_interface_object}', 'dom::bindings::js::{JS, Root, RootedReference}', 'dom::bindings::js::{OptionalRootedReference}', 'dom::bindings::reflector::{Reflectable}', 'dom::bindings::utils::{ConstantSpec, DOMClass, DOMJSClass}', 'dom::bindings::utils::{DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, JSCLASS_DOM_GLOBAL}', - 'dom::bindings::utils::{NativeProperties, NonNullJSNative, create_dom_global}', - 'dom::bindings::utils::{do_create_interface_objects, finalize_global}', + 'dom::bindings::utils::{NonNullJSNative, create_dom_global, finalize_global}', 'dom::bindings::utils::{find_enum_string_index, generic_getter}', 'dom::bindings::utils::{generic_lenient_getter, generic_lenient_setter}', 'dom::bindings::utils::{generic_method, generic_setter, get_array_index_from_id}', diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs new file mode 100644 index 00000000000..a7420c2aeb4 --- /dev/null +++ b/components/script/dom/bindings/interface.rs @@ -0,0 +1,155 @@ +/* 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/. */ + +//! Machinery to initialise interface prototype objects and interface objects. + +use dom::bindings::utils::{ConstantSpec, NonNullJSNative, define_constants}; +use js::jsapi::{HandleObject, JSClass, JSContext, JSFunctionSpec, JSObject}; +use js::jsapi::{JSPropertySpec, JS_DefineProperty1, JS_GetFunctionObject}; +use js::jsapi::{JS_LinkConstructorAndPrototype, JS_NewFunction}; +use js::jsapi::{JS_NewObjectWithUniqueType, MutableHandleObject, RootedObject}; +use js::rust::{define_methods, define_properties}; +use js::{JSFUN_CONSTRUCTOR, JSPROP_PERMANENT, JSPROP_READONLY}; +use libc; +use std::ptr; + +/// Create and define the interface object of a callback interface. +pub unsafe fn create_callback_interface_object( + cx: *mut JSContext, + receiver: HandleObject, + constructor_native: NonNullJSNative, + length: u32, + constants: &'static [ConstantSpec], + name: &'static [u8]) { + assert!(!constants.is_empty()); + let interface_object = + RootedObject::new(cx, create_constructor(cx, constructor_native, length, name)); + assert!(!interface_object.ptr.is_null()); + define_constants(cx, interface_object.handle(), constants); + define_on_global_object(cx, receiver, name, interface_object.handle()); +} + +/// Create the interface prototype object of a non-callback interface. +pub unsafe fn create_interface_prototype_object( + cx: *mut JSContext, + proto: HandleObject, + class: &'static JSClass, + regular_methods: Option<&'static [JSFunctionSpec]>, + regular_properties: Option<&'static [JSPropertySpec]>, + constants: &'static [ConstantSpec], + rval: MutableHandleObject) { + create_object(cx, proto, class, regular_methods, regular_properties, constants, rval); +} + +/// Create and define the interface object of a non-callback interface. +pub unsafe fn create_noncallback_interface_object( + cx: *mut JSContext, + receiver: HandleObject, + constructor_native: NonNullJSNative, + static_methods: Option<&'static [JSFunctionSpec]>, + static_properties: Option<&'static [JSPropertySpec]>, + constants: &'static [ConstantSpec], + interface_prototype_object: HandleObject, + name: &'static [u8], + length: u32) { + assert!(!interface_prototype_object.ptr.is_null()); + + let interface_object = + RootedObject::new(cx, create_constructor(cx, constructor_native, length, name)); + assert!(!interface_object.ptr.is_null()); + + if let Some(static_methods) = static_methods { + define_methods(cx, interface_object.handle(), static_methods).unwrap(); + } + + if let Some(static_properties) = static_properties { + define_properties(cx, interface_object.handle(), static_properties).unwrap(); + } + + define_constants(cx, interface_object.handle(), constants); + + assert!(JS_LinkConstructorAndPrototype(cx, interface_object.handle(), + interface_prototype_object)); + define_on_global_object(cx, receiver, name, interface_object.handle()); +} + +/// Create and define the named constructors of a non-callback interface. +pub unsafe fn create_named_constructors( + cx: *mut JSContext, + receiver: HandleObject, + named_constructors: &[(NonNullJSNative, &'static [u8], u32)], + interface_prototype_object: HandleObject) { + let mut constructor = RootedObject::new(cx, ptr::null_mut()); + + for &(native, name, arity) in named_constructors { + assert!(*name.last().unwrap() == b'\0'); + + constructor.ptr = create_constructor(cx, native, arity, name); + assert!(!constructor.ptr.is_null()); + + assert!(JS_DefineProperty1(cx, + constructor.handle(), + b"prototype\0".as_ptr() as *const libc::c_char, + interface_prototype_object, + JSPROP_PERMANENT | JSPROP_READONLY, + None, + None)); + + define_on_global_object(cx, receiver, name, constructor.handle()); + } +} + +unsafe fn create_constructor( + cx: *mut JSContext, + constructor_native: NonNullJSNative, + ctor_nargs: u32, + name: &'static [u8]) + -> *mut JSObject { + assert!(*name.last().unwrap() == b'\0'); + + let fun = JS_NewFunction(cx, + Some(constructor_native), + ctor_nargs, + JSFUN_CONSTRUCTOR, + name.as_ptr() as *const _); + assert!(!fun.is_null()); + + let constructor = JS_GetFunctionObject(fun); + assert!(!constructor.is_null()); + + constructor +} + +unsafe fn create_object( + cx: *mut JSContext, + proto: HandleObject, + class: &'static JSClass, + methods: Option<&'static [JSFunctionSpec]>, + properties: Option<&'static [JSPropertySpec]>, + constants: &'static [ConstantSpec], + rval: MutableHandleObject) { + rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); + assert!(!rval.ptr.is_null()); + if let Some(methods) = methods { + define_methods(cx, rval.handle(), methods).unwrap(); + } + if let Some(properties) = properties { + define_properties(cx, rval.handle(), properties).unwrap(); + } + define_constants(cx, rval.handle(), constants); +} + +unsafe fn define_on_global_object( + cx: *mut JSContext, + receiver: HandleObject, + name: &'static [u8], + obj: HandleObject) { + assert!(*name.last().unwrap() == b'\0'); + assert!(JS_DefineProperty1(cx, + receiver, + name.as_ptr() as *const libc::c_char, + obj, + 0, + None, None)); +} diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index df5f37ad07f..8bef928034c 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -138,6 +138,7 @@ pub mod conversions; pub mod error; pub mod global; pub mod inheritance; +pub mod interface; pub mod js; pub mod num; pub mod proxyhandler; diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 6173144490e..7815593355c 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -19,32 +19,19 @@ use js::glue::{CallJitGetterOp, CallJitMethodOp, CallJitSetterOp, IsWrapper}; use js::glue::{GetCrossCompartmentWrapper, WrapperNew}; use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT}; use js::glue::{RUST_JSID_TO_INT, UnwrapObject}; -use js::jsapi::JSAutoCompartment; -use js::jsapi::JS_DeletePropertyById1; -use js::jsapi::JS_GetFunctionObject; -use js::jsapi::JS_IsExceptionPending; -use js::jsapi::JS_NewObjectWithUniqueType; -use js::jsapi::JS_ObjectToOuterObject; -use js::jsapi::{CallArgs, GetGlobalForObjectCrossCompartment, JSJitInfo}; -use js::jsapi::{CompartmentOptions, OnNewGlobalHookOption}; -use js::jsapi::{DOMCallbacks, JSWrapObjectCallbacks}; -use js::jsapi::{HandleId, HandleObject, HandleValue, MutableHandleValue}; -use js::jsapi::{Heap, MutableHandleObject, ObjectOpResult, RootedObject, RootedValue}; -use js::jsapi::{JSClass, JSContext, JSObject, JSTracer}; -use js::jsapi::{JSFunctionSpec, JSPropertySpec}; -use js::jsapi::{JSTraceOp, JS_AlreadyHasOwnProperty, JS_NewFunction}; -use js::jsapi::{JSVersion, JS_FireOnNewGlobalObject}; -use js::jsapi::{JS_DefineProperty, JS_DefineProperty1, JS_ForwardGetPropertyTo}; -use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype}; -use js::jsapi::{JS_GetProperty, JS_HasProperty, JS_SetProperty}; -use js::jsapi::{JS_GetPrototype, JS_HasPropertyById}; -use js::jsapi::{JS_GetReservedSlot, JS_SetReservedSlot}; -use js::jsapi::{JS_InitStandardClasses, JS_NewGlobalObject}; +use js::jsapi::{CallArgs, CompartmentOptions, DOMCallbacks, GetGlobalForObjectCrossCompartment}; +use js::jsapi::{HandleId, HandleObject, HandleValue, Heap, JSAutoCompartment, JSClass, JSContext}; +use js::jsapi::{JSJitInfo, JSObject, JSTraceOp, JSTracer, JSVersion, JSWrapObjectCallbacks}; +use js::jsapi::{JS_DefineProperty, JS_DeletePropertyById1, JS_FireOnNewGlobalObject}; +use js::jsapi::{JS_ForwardGetPropertyTo, JS_GetClass, JS_GetProperty, JS_GetPrototype}; +use js::jsapi::{JS_GetReservedSlot, JS_HasProperty, JS_HasPropertyById, JS_InitStandardClasses}; +use js::jsapi::{JS_IsExceptionPending, JS_NewGlobalObject, JS_ObjectToOuterObject, JS_SetProperty}; +use js::jsapi::{JS_SetReservedSlot, MutableHandleValue, ObjectOpResult, OnNewGlobalHookOption}; +use js::jsapi::{RootedObject, RootedValue}; use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue}; use js::jsval::{PrivateValue, UInt32Value, UndefinedValue}; -use js::rust::{GCMethods, ToString, define_methods, define_properties}; -use js::{JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE, JS_CALLEE}; -use js::{JSPROP_PERMANENT, JSPROP_READONLY}; +use js::rust::{GCMethods, ToString}; +use js::{JS_CALLEE, JSPROP_ENUMERATE, JSPROP_PERMANENT, JSPROP_READONLY}; use libc::{self, c_uint}; use std::default::Default; use std::ffi::CString; @@ -168,153 +155,13 @@ pub fn get_proto_or_iface_array(global: *mut JSObject) -> *mut ProtoOrIfaceArray } } -/// Contains references to lists of methods, attributes, and constants for a -/// given interface. -pub struct NativeProperties { - /// Instance methods for the interface. - pub methods: Option<&'static [JSFunctionSpec]>, - /// Unforgeable instance methods for the interface. - pub unforgeable_methods: Option<&'static [JSFunctionSpec]>, - /// Instance attributes for the interface. - pub attrs: Option<&'static [JSPropertySpec]>, - /// Unforgeable instance attributes for the interface. - pub unforgeable_attrs: Option<&'static [JSPropertySpec]>, - /// Constants for the interface. - pub consts: Option<&'static [ConstantSpec]>, - /// Static methods for the interface. - pub static_methods: Option<&'static [JSFunctionSpec]>, - /// Static attributes for the interface. - pub static_attrs: Option<&'static [JSPropertySpec]>, -} -unsafe impl Sync for NativeProperties {} - /// A JSNative that cannot be null. pub type NonNullJSNative = unsafe extern "C" fn (arg1: *mut JSContext, arg2: c_uint, arg3: *mut JSVal) -> bool; -/// Creates the *interface prototype object* (if a `proto_class` is given) -/// and the *interface object* (if a `constructor` is given). -/// Fails on JSAPI failure. -pub fn do_create_interface_objects(cx: *mut JSContext, - receiver: HandleObject, - proto_proto: HandleObject, - proto_class: Option<&'static JSClass>, - constructor: Option<(NonNullJSNative, &'static str, u32)>, - named_constructors: &[(NonNullJSNative, &'static str, u32)], - members: &'static NativeProperties, - rval: MutableHandleObject) { - assert!(rval.get().is_null()); - if let Some(proto_class) = proto_class { - create_interface_prototype_object(cx, proto_proto, proto_class, members, rval); - } - - if let Some((native, name, nargs)) = constructor { - let s = CString::new(name).unwrap(); - create_interface_object(cx, - receiver, - native, - nargs, - rval.handle(), - members, - s.as_ptr()) - } - - for ctor in named_constructors { - let (cnative, cname, cnargs) = *ctor; - - let cs = CString::new(cname).unwrap(); - let constructor = RootedObject::new(cx, - create_constructor(cx, cnative, cnargs, cs.as_ptr())); - assert!(!constructor.ptr.is_null()); - unsafe { - assert!(JS_DefineProperty1(cx, - constructor.handle(), - b"prototype\0".as_ptr() as *const libc::c_char, - rval.handle(), - JSPROP_PERMANENT | JSPROP_READONLY, - None, - None)); - } - define_constructor(cx, receiver, cs.as_ptr(), constructor.handle()); - } - -} - -fn create_constructor(cx: *mut JSContext, - constructor_native: NonNullJSNative, - ctor_nargs: u32, - name: *const libc::c_char) - -> *mut JSObject { - unsafe { - let fun = JS_NewFunction(cx, - Some(constructor_native), - ctor_nargs, - JSFUN_CONSTRUCTOR, - name); - assert!(!fun.is_null()); - - let constructor = JS_GetFunctionObject(fun); - assert!(!constructor.is_null()); - - constructor - } -} - -fn define_constructor(cx: *mut JSContext, - receiver: HandleObject, - name: *const libc::c_char, - constructor: HandleObject) { - unsafe { - let mut already_defined = false; - assert!(JS_AlreadyHasOwnProperty(cx, receiver, name, &mut already_defined)); - - if !already_defined { - assert!(JS_DefineProperty1(cx, receiver, name, constructor, 0, None, None)); - } - - } -} - -/// Creates the *interface object*. -/// Fails on JSAPI failure. -fn create_interface_object(cx: *mut JSContext, - receiver: HandleObject, - constructor_native: NonNullJSNative, - ctor_nargs: u32, - proto: HandleObject, - members: &'static NativeProperties, - name: *const libc::c_char) { - unsafe { - let constructor = RootedObject::new(cx, - create_constructor(cx, - constructor_native, - ctor_nargs, - name)); - assert!(!constructor.ptr.is_null()); - - if let Some(static_methods) = members.static_methods { - define_methods(cx, constructor.handle(), static_methods).unwrap(); - } - - if let Some(static_properties) = members.static_attrs { - define_properties(cx, constructor.handle(), static_properties).unwrap(); - } - - if let Some(constants) = members.consts { - define_constants(cx, constructor.handle(), constants); - } - - if !proto.get().is_null() { - assert!(JS_LinkConstructorAndPrototype(cx, constructor.handle(), proto)); - } - - define_constructor(cx, receiver, name, constructor.handle()); - } -} - /// Defines constants on `obj`. /// Fails on JSAPI failure. -fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [ConstantSpec]) { +pub fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [ConstantSpec]) { for spec in constants { let value = RootedValue::new(cx, spec.get_value()); unsafe { @@ -329,31 +176,6 @@ fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [ } } -/// Creates the *interface prototype object*. -/// Fails on JSAPI failure. -fn create_interface_prototype_object(cx: *mut JSContext, - parent_proto: HandleObject, - proto_class: &'static JSClass, - members: &'static NativeProperties, - rval: MutableHandleObject) { - unsafe { - rval.set(JS_NewObjectWithUniqueType(cx, proto_class, parent_proto)); - assert!(!rval.get().is_null()); - - if let Some(methods) = members.methods { - define_methods(cx, rval.handle(), methods).unwrap(); - } - - if let Some(properties) = members.attrs { - define_properties(cx, rval.handle(), properties).unwrap(); - } - - if let Some(constants) = members.consts { - define_constants(cx, rval.handle(), constants); - } - } -} - /// A throwing constructor, for those interfaces that have neither /// `NoInterfaceObject` nor `Constructor`. pub unsafe extern "C" fn throwing_constructor(cx: *mut JSContext, |