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: &str,
80    mut rval: MutableHandleValue,
81) -> Fallible<()> {
82    rval.set(UndefinedValue());
83
84    let Ok(cname) = ffi::CString::new(name) else {
85        return Ok(());
86    };
87
88    let mut found = false;
89    unsafe {
90        if !JS_HasProperty(*cx, object, cname.as_ptr(), &mut found) || !found {
91            if JS_IsExceptionPending(*cx) {
92                return Err(Error::JSFailed);
93            }
94            return Ok(());
95        }
96
97        JS_GetProperty(*cx, object, cname.as_ptr(), rval);
98        if JS_IsExceptionPending(*cx) {
99            return Err(Error::JSFailed);
100        }
101        Ok(())
102    }
103}
104
105/// Get a property from a JS object, and convert it to a Rust value.
106pub(crate) fn get_property<T>(
107    cx: JSContext,
108    object: HandleObject,
109    name: &str,
110    option: T::Config,
111) -> Fallible<Option<T>>
112where
113    T: FromJSValConvertible,
114{
115    debug!("Getting property {}.", name);
116    rooted!(in(*cx) let mut result = UndefinedValue());
117    get_property_jsval(cx, object, name, result.handle_mut())?;
118    if result.is_undefined() {
119        debug!("No property {}.", name);
120        return Ok(None);
121    }
122    debug!("Converting property {}.", name);
123    let value = unsafe { T::from_jsval(*cx, result.handle(), option) };
124    match value {
125        Ok(ConversionResult::Success(value)) => Ok(Some(value)),
126        Ok(ConversionResult::Failure(_)) => Ok(None),
127        Err(()) => Err(Error::JSFailed),
128    }
129}