1use 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}