use std::ffi;
pub(crate) use js::conversions::{
ConversionBehavior, ConversionResult, FromJSValConvertible, ToJSValConvertible,
};
use js::jsapi::{JS_IsExceptionPending, JSContext as RawJSContext, JSObject};
use js::jsval::UndefinedValue;
use js::rust::wrappers::{JS_GetProperty, JS_HasProperty};
use js::rust::{HandleObject, MutableHandleValue};
pub(crate) use script_bindings::conversions::{is_dom_proxy, *};
use script_bindings::script_runtime::JSContext;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot;
pub(crate) fn root_from_object_static<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()>
where
T: DomObject + IDLInterface,
{
unsafe { native_from_object_static(obj).map(|ptr| DomRoot::from_ref(&*ptr)) }
}
pub(crate) fn root_from_handleobject<T>(
obj: HandleObject,
cx: *mut RawJSContext,
) -> Result<DomRoot<T>, ()>
where
T: DomObject + IDLInterface,
{
unsafe { root_from_object(obj.get(), cx) }
}
pub(crate) fn get_property_jsval(
cx: JSContext,
object: HandleObject,
name: &ffi::CStr,
mut rval: MutableHandleValue,
) -> Fallible<()> {
rval.set(UndefinedValue());
let mut found = false;
unsafe {
if !JS_HasProperty(*cx, object, name.as_ptr(), &mut found) || !found {
if JS_IsExceptionPending(*cx) {
return Err(Error::JSFailed);
}
return Ok(());
}
JS_GetProperty(*cx, object, name.as_ptr(), rval);
if JS_IsExceptionPending(*cx) {
return Err(Error::JSFailed);
}
Ok(())
}
}
pub(crate) fn get_property<T>(
cx: JSContext,
object: HandleObject,
name: &ffi::CStr,
option: T::Config,
) -> Fallible<Option<T>>
where
T: FromJSValConvertible,
{
debug!("Getting property {:?}.", name);
rooted!(in(*cx) let mut result = UndefinedValue());
get_property_jsval(cx, object, name, result.handle_mut())?;
if result.is_undefined() {
debug!("No property {:?}.", name);
return Ok(None);
}
debug!("Converting property {:?}.", name);
let value = unsafe { T::from_jsval(*cx, result.handle(), option) };
match value {
Ok(ConversionResult::Success(value)) => Ok(Some(value)),
Ok(ConversionResult::Failure(_)) => Ok(None),
Err(()) => Err(Error::JSFailed),
}
}