script/dom/bindings/conversions.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Conversions of Rust values to and from `JSVal`.
6//!
7//! | IDL type | Argument type | Return type |
8//! |-------------------------|-----------------|----------------|
9//! | any | `JSVal` | |
10//! | boolean | `bool` | |
11//! | byte | `i8` | |
12//! | octet | `u8` | |
13//! | short | `i16` | |
14//! | unsigned short | `u16` | |
15//! | long | `i32` | |
16//! | unsigned long | `u32` | |
17//! | long long | `i64` | |
18//! | unsigned long long | `u64` | |
19//! | unrestricted float | `f32` | |
20//! | float | `Finite<f32>` | |
21//! | unrestricted double | `f64` | |
22//! | double | `Finite<f64>` | |
23//! | DOMString | `DOMString` | |
24//! | USVString | `USVString` | |
25//! | ByteString | `ByteString` | |
26//! | object | `*mut JSObject` | |
27//! | interface types | `&T` | `DomRoot<T>` |
28//! | dictionary types | `&T` | *unsupported* |
29//! | enumeration types | `T` | |
30//! | callback function types | `Rc<T>` | |
31//! | nullable types | `Option<T>` | |
32//! | sequences | `Vec<T>` | |
33//! | union types | `T` | |
34
35use std::ffi;
36
37pub(crate) use js::conversions::{
38 ConversionBehavior, ConversionResult, FromJSValConvertible, ToJSValConvertible,
39};
40use js::jsapi::{JS_IsExceptionPending, JSContext as RawJSContext, JSObject};
41use js::jsval::UndefinedValue;
42use js::rust::wrappers::{JS_GetProperty, JS_HasProperty};
43use js::rust::{HandleObject, MutableHandleValue};
44pub(crate) use script_bindings::conversions::{is_dom_proxy, *};
45use script_bindings::script_runtime::JSContext;
46
47use crate::dom::bindings::error::{Error, Fallible};
48use crate::dom::bindings::reflector::DomObject;
49use crate::dom::bindings::root::DomRoot;
50
51/// Get a `DomRoot<T>` for the given DOM object, unwrapping any wrapper
52/// around it first, and checking if the object is of the correct type.
53///
54/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
55/// not a reflector for a DOM object of the given type (as defined by the
56/// proto_id and proto_depth).
57pub(crate) fn root_from_object_static<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()>
58where
59 T: DomObject + IDLInterface,
60{
61 unsafe { native_from_object_static(obj).map(|ptr| DomRoot::from_ref(&*ptr)) }
62}
63
64/// Get a `DomRoot<T>` for a DOM object accessible from a `HandleObject`.
65pub(crate) fn root_from_handleobject<T>(
66 obj: HandleObject,
67 cx: *mut RawJSContext,
68) -> Result<DomRoot<T>, ()>
69where
70 T: DomObject + IDLInterface,
71{
72 unsafe { root_from_object(obj.get(), cx) }
73}
74
75/// Get a property from a JS object.
76pub(crate) fn get_property_jsval(
77 cx: JSContext,
78 object: HandleObject,
79 name: &ffi::CStr,
80 mut rval: MutableHandleValue,
81) -> Fallible<()> {
82 rval.set(UndefinedValue());
83
84 let mut found = false;
85 unsafe {
86 if !JS_HasProperty(*cx, object, name.as_ptr(), &mut found) || !found {
87 if JS_IsExceptionPending(*cx) {
88 return Err(Error::JSFailed);
89 }
90 return Ok(());
91 }
92
93 JS_GetProperty(*cx, object, name.as_ptr(), rval);
94 if JS_IsExceptionPending(*cx) {
95 return Err(Error::JSFailed);
96 }
97 Ok(())
98 }
99}
100
101/// Get a property from a JS object, and convert it to a Rust value.
102pub(crate) fn get_property<T>(
103 cx: JSContext,
104 object: HandleObject,
105 name: &ffi::CStr,
106 option: T::Config,
107) -> Fallible<Option<T>>
108where
109 T: FromJSValConvertible,
110{
111 debug!("Getting property {:?}.", name);
112 rooted!(in(*cx) let mut result = UndefinedValue());
113
114 get_property_jsval(cx, object, name, result.handle_mut())?;
115 if result.is_undefined() {
116 debug!("No property {:?}.", name);
117 return Ok(None);
118 }
119 debug!("Converting property {:?}.", name);
120 let value = unsafe { T::from_jsval(*cx, result.handle(), option) };
121 match value {
122 Ok(ConversionResult::Success(value)) => Ok(Some(value)),
123 Ok(ConversionResult::Failure(_)) => Ok(None),
124 Err(()) => Err(Error::JSFailed),
125 }
126}