1use crate::{
2 atom::{Atom, AtomKind},
3 context::ContextImpl,
4 error::{JS_ThrowTypeErrorPrivateNotFound, JSResult},
5 object::{JSProperty, Object},
6 utils::unlikely,
7 value::JSValue,
8};
9
10use super::JS_PROP_C_W_E;
11
12impl Object {
13 pub fn check_brand(&self, ctx: &ContextImpl, func: JSValue) -> Result<bool, i32> {
15 if let Some(home_obj) = func
16 .as_object_BCFunction()
17 .and_then(|o| o.payload().home_object())
18 {
19 if let Some((idx, _)) = home_obj.find_shape_property(Atom::CONST_Private_brand) {
20 let atom = if let JSProperty::Normal(JSValue::Symbol(a)) =
21 home_obj.prop_values.get(idx).unwrap()
22 {
23 *a
24 } else {
25 ctx.throw_type_error_not_an_object();
26 return Err(-1);
27 };
28 Ok(self.has_shape_property(atom))
29 } else {
30 ctx.throw_type_error("expecting <brand> private field");
31 Err(-1)
32 }
33 } else {
34 ctx.throw_type_error_not_an_object();
36 Err(-1)
37 }
38 }
39
40 fn set_private_field(
41 &mut self,
42 ctx: &ContextImpl,
43 name: JSValue,
44 val: JSValue,
45 ) -> Result<(), i32> {
46 if let JSValue::Symbol(atom) = name {
47 if let Some((idx, _)) = self.find_shape_property(atom) {
48 self.prop_values[idx] = JSProperty::Normal(val);
49 Ok(())
50 } else {
51 JS_ThrowTypeErrorPrivateNotFound(ctx, atom);
52 Err(-1)
53 }
54 } else {
55 ctx.throw_type_error_not_a_symbol();
56 Err(-1)
57 }
58 }
59
60 fn get_private_field(&self, ctx: &ContextImpl, name: JSValue) -> JSResult {
61 if let JSValue::Symbol(atom) = name {
62 if let Some((idx, _)) = self.find_shape_property(atom) {
63 if let JSProperty::Normal(val) = self.prop_values.get(idx).unwrap() {
64 Ok(*val)
65 } else {
66 unreachable!()
67 }
68 } else {
69 JS_ThrowTypeErrorPrivateNotFound(ctx, atom);
70 Err(-1)
71 }
72 } else {
73 ctx.throw_type_error_not_a_symbol();
74 Err(-1)
75 }
76 }
77
78 pub fn define_private_field(
80 &mut self,
81 ctx: &ContextImpl,
82 name: JSValue,
83 val: JSValue,
84 ) -> Result<(), i32> {
85 if let JSValue::Symbol(atom) = name {
86 if self.has_shape_property(atom) {
87 ctx.throw_type_error(&format!(
88 "private class field '{}' already exists",
89 atom.to_utf8()
90 ));
91 Err(-1)
92 } else {
93 self.add_own_property(ctx, atom, JS_PROP_C_W_E, JSProperty::Normal(val))
94 }
95 } else {
96 ctx.throw_type_error_not_a_symbol();
97 Err(-1)
98 }
99 }
100}
101
102impl JSValue {
103 pub fn check_brand(&self, ctx: &ContextImpl, func: JSValue) -> Result<bool, i32> {
105 if let JSValue::Object(ob) = self {
106 ob.check_brand(ctx, func)
107 } else {
108 ctx.throw_type_error_not_an_object();
109 Err(-1)
110 }
111 }
112
113 pub fn add_brand(&mut self, ctx: &ContextImpl, home_obj: JSValue) -> Result<(), i32> {
116 if let JSValue::Object(mut home) = home_obj {
117 let brand_sym: JSValue =
118 if let Some((idx, _)) = home.find_shape_property(Atom::CONST_Private_brand) {
119 if let JSProperty::Normal(val) = home.prop_values.get(idx).unwrap() {
120 *val
121 } else {
122 unreachable!()
123 }
124 } else {
125 let br = ctx.create_symbol_from_atom(Atom::CONST__brand_, AtomKind::Private)?;
127 home.add_own_property(
128 ctx,
129 Atom::CONST_Private_brand,
130 JS_PROP_C_W_E,
131 JSProperty::Normal(br),
132 )?;
133 br
134 };
135
136 if let Some(ob) = self.as_object_mut() {
137 let brand_atom = brand_sym.to_atom(ctx).unwrap();
138 if ob.has_shape_property(brand_atom) {
139 ctx.throw_type_error("private method is already present");
140 Err(-1)
141 } else {
142 ob.add_own_property(
143 ctx,
144 brand_atom,
145 JS_PROP_C_W_E,
146 JSProperty::Normal(JSValue::UNDEFINED),
147 )
148 }
149 } else {
150 Ok(())
151 }
152 } else {
153 ctx.throw_type_error_not_an_object();
154 Err(-1)
155 }
156 }
157
158 pub fn set_private_field(
159 &mut self,
160 ctx: &ContextImpl,
161 name: JSValue,
162 val: JSValue,
163 ) -> Result<(), i32> {
164 if let JSValue::Object(o) = self {
165 if unlikely(!o.flags().extensible()) {
166 ctx.throw_type_error("object is nonextensible for private field");
167 Err(-1)
168 } else {
169 o.set_private_field(ctx, name, val)
170 }
171 } else {
172 ctx.throw_type_error_not_an_object();
173 Err(-1)
174 }
175 }
176
177 pub fn get_private_field(&self, ctx: &ContextImpl, name: JSValue) -> JSResult {
178 if let Self::Object(ob) = self {
179 ob.get_private_field(ctx, name)
180 } else {
181 ctx.throw_type_error_not_an_object();
182 Err(-1)
183 }
184 }
185
186 pub fn define_private_field(
188 &mut self,
189 ctx: &ContextImpl,
190 name: JSValue,
191 val: JSValue,
192 ) -> Result<(), i32> {
193 if let Self::Object(ob) = self {
194 ob.define_private_field(ctx, name, val)
195 } else {
196 ctx.throw_type_error_not_an_object();
197 Err(-1)
198 }
199 }
200}