ion/object/
descriptor.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use std::ops::{Deref, DerefMut};
8
9use mozjs::glue::{SetAccessorPropertyDescriptor, SetDataPropertyDescriptor};
10use mozjs::jsapi::{
11	FromPropertyDescriptor, JS_GetObjectFunction, PropertyDescriptor as JSPropertyDescriptor,
12	ToCompletePropertyDescriptor,
13};
14
15use crate::flags::PropertyFlags;
16use crate::{Context, Function, Local, Object, Value};
17
18pub struct PropertyDescriptor<'pd> {
19	desc: Local<'pd, JSPropertyDescriptor>,
20}
21
22impl<'pd> PropertyDescriptor<'pd> {
23	pub fn empty(cx: &'pd Context) -> PropertyDescriptor<'pd> {
24		PropertyDescriptor::from(cx.root(JSPropertyDescriptor::default()))
25	}
26
27	pub fn new(cx: &'pd Context, value: &Value, attrs: PropertyFlags) -> PropertyDescriptor<'pd> {
28		let mut desc = PropertyDescriptor::empty(cx);
29		unsafe { SetDataPropertyDescriptor(desc.handle_mut().into(), value.handle().into(), u32::from(attrs.bits())) };
30		desc
31	}
32
33	pub fn new_accessor(
34		cx: &'pd Context, getter: &Function, setter: &Function, attrs: PropertyFlags,
35	) -> PropertyDescriptor<'pd> {
36		let getter = getter.to_object(cx);
37		let setter = setter.to_object(cx);
38		let mut desc = PropertyDescriptor::empty(cx);
39		unsafe {
40			SetAccessorPropertyDescriptor(
41				desc.handle_mut().into(),
42				getter.handle().into(),
43				setter.handle().into(),
44				u32::from(attrs.bits()),
45			);
46		}
47		desc
48	}
49
50	pub fn from_object(cx: &'pd Context, object: &Object) -> Option<PropertyDescriptor<'pd>> {
51		let mut desc = PropertyDescriptor::empty(cx);
52		let desc_value = Value::object(cx, object);
53		unsafe {
54			ToCompletePropertyDescriptor(cx.as_ptr(), desc_value.handle().into(), desc.handle_mut().into())
55				.then_some(desc)
56		}
57	}
58
59	pub fn to_object<'cx>(&self, cx: &'cx Context) -> Option<Object<'cx>> {
60		let mut value = Value::undefined(cx);
61		unsafe { FromPropertyDescriptor(cx.as_ptr(), self.handle().into(), value.handle_mut().into()) }
62			.then(|| value.to_object(cx))
63	}
64
65	pub fn is_configurable(&self) -> bool {
66		self.handle().hasConfigurable_() && self.handle().configurable_()
67	}
68
69	pub fn is_enumerable(&self) -> bool {
70		self.handle().hasEnumerable_() && self.handle().enumerable_()
71	}
72
73	pub fn is_writable(&self) -> bool {
74		self.handle().hasWritable_() && self.handle().writable_()
75	}
76
77	pub fn is_resolving(&self) -> bool {
78		self.handle().resolving_()
79	}
80
81	pub fn getter<'cx>(&self, cx: &'cx Context) -> Option<Function<'cx>> {
82		(self.handle().hasGetter_() && !self.handle().getter_.is_null())
83			.then(|| Function::from(cx.root(unsafe { JS_GetObjectFunction(self.handle().getter_) })))
84	}
85
86	pub fn setter<'cx>(&self, cx: &'cx Context) -> Option<Function<'cx>> {
87		(self.handle().hasSetter_() && !self.handle().setter_.is_null())
88			.then(|| Function::from(cx.root(unsafe { JS_GetObjectFunction(self.handle().setter_) })))
89	}
90
91	pub fn value<'cx>(&self, cx: &'cx Context) -> Option<Value<'cx>> {
92		self.handle().hasValue_().then(|| Value::from(cx.root(self.handle().value_)))
93	}
94
95	pub fn into_local(self) -> Local<'pd, JSPropertyDescriptor> {
96		self.desc
97	}
98}
99
100impl<'pd> From<Local<'pd, JSPropertyDescriptor>> for PropertyDescriptor<'pd> {
101	fn from(desc: Local<'pd, JSPropertyDescriptor>) -> PropertyDescriptor<'pd> {
102		PropertyDescriptor { desc }
103	}
104}
105
106impl<'pd> Deref for PropertyDescriptor<'pd> {
107	type Target = Local<'pd, JSPropertyDescriptor>;
108
109	fn deref(&self) -> &Self::Target {
110		&self.desc
111	}
112}
113
114impl DerefMut for PropertyDescriptor<'_> {
115	fn deref_mut(&mut self) -> &mut Self::Target {
116		&mut self.desc
117	}
118}