diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e7fcb887782..f418a1ba569 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1335,8 +1335,8 @@ def MemberCondition(pref, func): assert pref is None or isinstance(pref, str) assert func is None or isinstance(func, str) if pref: - return 'Some("%s")' % pref - return "None" + return 'Condition::Pref("%s")' % pref + return "Condition::Satisfied" class PropertyDefiner: @@ -1380,8 +1380,8 @@ class PropertyDefiner: PropertyDefiner.getStringAttr(interfaceMember, "Func")) - def generatePrefableArray(self, array, name, specTemplate, specTerminator, - specType, getCondition, getDataTuple): + def generateGuardedArray(self, array, name, specTemplate, specTerminator, + specType, getCondition, getDataTuple): """ This method generates our various arrays. @@ -1409,7 +1409,7 @@ class PropertyDefiner: assert len(array) != 0 specs = [] prefableSpecs = [] - prefableTemplate = ' Prefable { pref: %s, specs: %s[%d] }' + prefableTemplate = ' Guard::new(%s, %s[%d])' for cond, members in groupby(array, lambda m: getCondition(m, self.descriptor)): currentSpecs = [specTemplate % getDataTuple(m) for m in members] @@ -1423,7 +1423,7 @@ class PropertyDefiner: ",\n".join(specs) + "\n" + "];\n") % (name, specType) - prefArray = ("const %s: &'static [Prefable<%s>] = &[\n" + + prefArray = ("const %s: &'static [Guard<&'static [%s]>] = &[\n" + ",\n".join(prefableSpecs) + "\n" + "];\n") % (name, specType) return specsArray + prefArray @@ -1470,7 +1470,7 @@ class MethodDefiner(PropertyDefiner): "methodInfo": False, "selfHostedName": "ArrayValues", "length": 0, - "condition": "None"}) + "condition": "Condition::Satisfied"}) isUnforgeableInterface = bool(descriptor.interface.getExtendedAttribute("Unforgeable")) if not static and unforgeable == isUnforgeableInterface: @@ -1521,7 +1521,7 @@ class MethodDefiner(PropertyDefiner): % m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName) return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], flags, selfHostedName) - return self.generatePrefableArray( + return self.generateGuardedArray( array, name, ' JSFunctionSpec {\n' ' name: %s as *const u8 as *const libc::c_char,\n' @@ -1601,7 +1601,7 @@ class AttrDefiner(PropertyDefiner): return (str_to_const_array(attr.identifier.name), flags, getter(attr), setter(attr)) - return self.generatePrefableArray( + return self.generateGuardedArray( array, name, ' JSPropertySpec {\n' ' name: %s as *const u8 as *const libc::c_char,\n' @@ -1636,7 +1636,7 @@ class ConstDefiner(PropertyDefiner): return (str_to_const_array(const.identifier.name), convertConstIDLValueToJSVal(const.value)) - return self.generatePrefableArray( + return self.generateGuardedArray( array, name, ' ConstantSpec { name: %s, value: %s }', None, @@ -2297,8 +2297,8 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties): """ unforgeables = [] - defineUnforgeableAttrs = "define_prefable_properties(cx, unforgeable_holder.handle(), %s);" - defineUnforgeableMethods = "define_prefable_methods(cx, unforgeable_holder.handle(), %s);" + defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s);" + defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s);" unforgeableMembers = [ (defineUnforgeableAttrs, properties.unforgeable_attrs), @@ -5528,13 +5528,13 @@ class CGBindingRoot(CGThing): 'dom::bindings::interface::{InterfaceConstructorBehavior, NonCallbackInterfaceObjectClass}', 'dom::bindings::interface::{create_callback_interface_object, create_interface_prototype_object}', 'dom::bindings::interface::{create_named_constructors, create_noncallback_interface_object}', - 'dom::bindings::interface::{define_prefable_methods, define_prefable_properties}', + 'dom::bindings::interface::{define_guarded_methods, define_guarded_properties}', 'dom::bindings::interface::{ConstantSpec, NonNullJSNative}', 'dom::bindings::interface::ConstantVal::{IntVal, UintVal}', 'dom::bindings::js::{JS, Root, RootedReference}', 'dom::bindings::js::{OptionalRootedReference}', 'dom::bindings::reflector::{Reflectable}', - 'dom::bindings::utils::{DOMClass, DOMJSClass, Prefable}', + 'dom::bindings::utils::{DOMClass, DOMJSClass}', 'dom::bindings::utils::{DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, JSCLASS_DOM_GLOBAL}', 'dom::bindings::utils::{ProtoOrIfaceArray, create_dom_global}', 'dom::bindings::utils::{enumerate_global, finalize_global, find_enum_string_index}', @@ -5558,6 +5558,7 @@ class CGBindingRoot(CGThing): 'dom::bindings::error::{Fallible, Error, ErrorResult}', 'dom::bindings::error::Error::JSFailed', 'dom::bindings::error::throw_dom_exception', + 'dom::bindings::guard::{Condition, Guard}', 'dom::bindings::proxyhandler', 'dom::bindings::proxyhandler::{ensure_expando_object, fill_property_descriptor}', 'dom::bindings::proxyhandler::{get_expando_object, get_property_descriptor}', diff --git a/components/script/dom/bindings/guard.rs b/components/script/dom/bindings/guard.rs new file mode 100644 index 00000000000..15b7c418a31 --- /dev/null +++ b/components/script/dom/bindings/guard.rs @@ -0,0 +1,49 @@ +/* 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 conditionally expose things. + +use util::prefs::get_pref; + +/// A container with a condition. +pub struct Guard { + condition: Condition, + value: T, +} + +impl Guard { + /// Construct a new guarded value. + pub const fn new(condition: Condition, value: T) -> Self { + Guard { + condition: condition, + value: value, + } + } + + /// Expose the value if the condition is satisfied. + pub fn expose(&self) -> Option { + if self.condition.is_satisfied() { + Some(self.value) + } else { + None + } + } +} + +/// A condition to expose things. +pub enum Condition { + /// The condition is satisfied if the preference is set. + Pref(&'static str), + /// The condition is always satisfied. + Satisfied, +} + +impl Condition { + fn is_satisfied(&self) -> bool { + match *self { + Condition::Pref(name) => get_pref(name).as_boolean().unwrap_or(false), + Condition::Satisfied => true, + } + } +} diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 8791cd4da08..65727ebfa8d 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -6,7 +6,8 @@ use dom::bindings::codegen::PrototypeList; use dom::bindings::conversions::get_dom_class; -use dom::bindings::utils::{get_proto_or_iface_array, Prefable}; +use dom::bindings::guard::Guard; +use dom::bindings::utils::get_proto_or_iface_array; use js::error::throw_type_error; use js::glue::UncheckedUnwrapObject; use js::jsapi::{Class, ClassExtension, ClassSpec, GetGlobalForObjectCrossCompartment}; @@ -209,14 +210,14 @@ impl InterfaceConstructorBehavior { pub unsafe fn create_callback_interface_object( cx: *mut JSContext, receiver: HandleObject, - constants: &'static [Prefable], + constants: &'static [Guard<&'static [ConstantSpec]>], name: &'static [u8], rval: MutableHandleObject) { assert!(!constants.is_empty()); rval.set(JS_NewObject(cx, ptr::null())); assert!(!rval.ptr.is_null()); - for prefable in constants { - if let Some(specs) = prefable.specs() { + for guard in constants { + if let Some(specs) = guard.expose() { define_constants(cx, rval.handle(), specs); } } @@ -229,9 +230,9 @@ pub unsafe fn create_interface_prototype_object( cx: *mut JSContext, proto: HandleObject, class: &'static JSClass, - regular_methods: &'static [Prefable], - regular_properties: &'static [Prefable], - constants: &'static [Prefable], + regular_methods: &'static [Guard<&'static [JSFunctionSpec]>], + regular_properties: &'static [Guard<&'static [JSPropertySpec]>], + constants: &'static [Guard<&'static [ConstantSpec]>], rval: MutableHandleObject) { create_object(cx, proto, class, regular_methods, regular_properties, constants, rval); } @@ -242,9 +243,9 @@ pub unsafe fn create_noncallback_interface_object( receiver: HandleObject, proto: HandleObject, class: &'static NonCallbackInterfaceObjectClass, - static_methods: &'static [Prefable], - static_properties: &'static [Prefable], - constants: &'static [Prefable], + static_methods: &'static [Guard<&'static [JSFunctionSpec]>], + static_properties: &'static [Guard<&'static [JSPropertySpec]>], + constants: &'static [Guard<&'static [ConstantSpec]>], interface_prototype_object: HandleObject, name: &'static [u8], length: u32, @@ -356,40 +357,40 @@ unsafe fn create_object( cx: *mut JSContext, proto: HandleObject, class: &'static JSClass, - methods: &'static [Prefable], - properties: &'static [Prefable], - constants: &'static [Prefable], + methods: &'static [Guard<&'static [JSFunctionSpec]>], + properties: &'static [Guard<&'static [JSPropertySpec]>], + constants: &'static [Guard<&'static [ConstantSpec]>], rval: MutableHandleObject) { rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); assert!(!rval.ptr.is_null()); - define_prefable_methods(cx, rval.handle(), methods); - define_prefable_properties(cx, rval.handle(), properties); - for prefable in constants { - if let Some(specs) = prefable.specs() { + define_guarded_methods(cx, rval.handle(), methods); + define_guarded_properties(cx, rval.handle(), properties); + for guard in constants { + if let Some(specs) = guard.expose() { define_constants(cx, rval.handle(), specs); } } } /// Conditionally define methods on an object. -pub unsafe fn define_prefable_methods( +pub unsafe fn define_guarded_methods( cx: *mut JSContext, obj: HandleObject, - methods: &'static [Prefable]) { - for prefable in methods { - if let Some(specs) = prefable.specs() { + methods: &'static [Guard<&'static [JSFunctionSpec]>]) { + for guard in methods { + if let Some(specs) = guard.expose() { define_methods(cx, obj, specs).unwrap(); } } } /// Conditionally define properties on an object. -pub unsafe fn define_prefable_properties( +pub unsafe fn define_guarded_properties( cx: *mut JSContext, obj: HandleObject, - properties: &'static [Prefable]) { - for prefable in properties { - if let Some(specs) = prefable.specs() { + properties: &'static [Guard<&'static [JSPropertySpec]>]) { + for guard in properties { + if let Some(specs) = guard.expose() { define_properties(cx, obj, specs).unwrap(); } } diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index d69720dc538..19797a473d0 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -133,6 +133,7 @@ pub mod cell; pub mod conversions; pub mod error; pub mod global; +pub mod guard; pub mod inheritance; pub mod interface; pub mod js; diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 3ba5838a4fa..cf1f437b1cf 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -39,7 +39,6 @@ use std::ffi::CString; use std::os::raw::c_void; use std::ptr; use std::slice; -use util::prefs; /// Proxy handler for a WindowProxy. pub struct WindowProxyHandler(pub *const libc::c_void); @@ -550,24 +549,3 @@ unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi:: pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks { instanceClassMatchesProto: Some(instance_class_has_proto_at_depth), }; - -/// A container around JS member specifications that are conditionally enabled. -pub struct Prefable { - /// If present, the name of the preference used to conditionally enable these specs. - pub pref: Option<&'static str>, - /// The underlying slice of specifications. - pub specs: &'static [T], -} - -impl Prefable { - /// Retrieve the slice represented by this container, unless the condition - /// guarding it is false. - pub fn specs(&self) -> Option<&'static [T]> { - if let Some(pref) = self.pref { - if !prefs::get_pref(pref).as_boolean().unwrap_or(false) { - return None; - } - } - Some(self.specs) - } -}