1use devtools_traits::{DebuggerValue, ObjectPreview, PropertyDescriptor};
6use malloc_size_of_derive::MallocSizeOf;
7use serde::Serialize;
8use serde_json::{Map, Number, Value};
9
10use crate::StreamId;
11use crate::actor::{Actor, ActorEncode, ActorError, ActorRegistry};
12use crate::actors::property_iterator::PropertyIteratorActor;
13use crate::protocol::ClientRequest;
14
15#[derive(Serialize)]
16#[serde(rename_all = "camelCase")]
17enum EnumIteratorType {
18 PropertyIterator,
19 SymbolIterator,
20}
21
22#[derive(Serialize)]
23struct EnumIterator {
24 actor: String,
25 #[serde(rename = "type")]
26 type_: EnumIteratorType,
27 count: u32,
28}
29
30#[derive(Serialize)]
31struct EnumReply {
32 from: String,
33 iterator: EnumIterator,
34}
35
36#[derive(Serialize)]
37struct PrototypeReply {
38 from: String,
39 prototype: Value,
40}
41
42#[derive(Serialize)]
43#[serde(rename_all = "camelCase")]
44pub(crate) struct ObjectActorMsg {
45 actor: String,
46 #[serde(rename = "type")]
47 type_: String,
48 class: String,
49 own_property_length: i32,
50 extensible: bool,
51 frozen: bool,
52 sealed: bool,
53 is_error: bool,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 preview: Option<ObjectPreview>,
56}
57
58#[derive(Serialize)]
59pub(crate) struct ObjectPropertyDescriptor {
60 pub configurable: bool,
61 pub enumerable: bool,
62 pub writable: bool,
63 pub value: Value,
64}
65
66impl ObjectPropertyDescriptor {
67 pub(crate) fn from_property_descriptor(
68 registry: &ActorRegistry,
69 prop: &PropertyDescriptor,
70 ) -> Self {
71 Self {
72 configurable: prop.configurable,
73 enumerable: prop.enumerable,
74 writable: prop.writable,
75 value: debugger_value_to_json(registry, prop.value.clone()),
76 }
77 }
78}
79
80pub(crate) fn debugger_value_to_json(registry: &ActorRegistry, value: DebuggerValue) -> Value {
82 let mut v = Map::new();
83 match value {
84 DebuggerValue::VoidValue => {
85 v.insert("type".to_owned(), Value::String("undefined".to_owned()));
86 Value::Object(v)
87 },
88 DebuggerValue::NullValue => {
89 v.insert("type".to_owned(), Value::String("null".to_owned()));
90 Value::Object(v)
91 },
92 DebuggerValue::BooleanValue(boolean) => Value::Bool(boolean),
93 DebuggerValue::NumberValue(val) => {
94 if val.is_nan() {
95 v.insert("type".to_owned(), Value::String("NaN".to_owned()));
96 Value::Object(v)
97 } else if val.is_infinite() {
98 if val < 0. {
99 v.insert("type".to_owned(), Value::String("-Infinity".to_owned()));
100 } else {
101 v.insert("type".to_owned(), Value::String("Infinity".to_owned()));
102 }
103 Value::Object(v)
104 } else if val == 0. && val.is_sign_negative() {
105 v.insert("type".to_owned(), Value::String("-0".to_owned()));
106 Value::Object(v)
107 } else {
108 Value::Number(Number::from_f64(val).unwrap())
109 }
110 },
111 DebuggerValue::StringValue(str) => Value::String(str),
112 DebuggerValue::ObjectValue {
113 uuid,
114 class,
115 preview,
116 ..
117 } => {
118 let object_name = ObjectActor::register(registry, Some(uuid), class, preview);
119 let object_msg = registry.encode::<ObjectActor, _>(&object_name);
120 let value = serde_json::to_value(object_msg).unwrap_or_default();
121 Value::Object(value.as_object().cloned().unwrap_or_default())
122 },
123 }
124}
125
126#[derive(MallocSizeOf)]
127pub(crate) struct ObjectActor {
128 name: String,
129 _uuid: Option<String>,
130 class: String,
131 preview: Option<ObjectPreview>,
132}
133
134impl Actor for ObjectActor {
135 fn name(&self) -> String {
136 self.name.clone()
137 }
138
139 fn handle_message(
141 &self,
142 request: ClientRequest,
143 registry: &ActorRegistry,
144 msg_type: &str,
145 _msg: &Map<String, Value>,
146 _id: StreamId,
147 ) -> Result<(), ActorError> {
148 match msg_type {
149 "enumProperties" => {
150 let properties = self
151 .preview
152 .as_ref()
153 .and_then(|preview| preview.own_properties.clone())
154 .unwrap_or_default();
155 let property_iterator_name = PropertyIteratorActor::register(registry, properties);
156 let property_iterator_actor =
157 registry.find::<PropertyIteratorActor>(&property_iterator_name);
158 let count = property_iterator_actor.count();
159 let msg = EnumReply {
160 from: self.name(),
161 iterator: EnumIterator {
162 actor: property_iterator_name,
163 type_: EnumIteratorType::PropertyIterator,
164 count,
165 },
166 };
167
168 request.reply_final(&msg)?
169 },
170
171 "enumSymbols" => {
172 let symbol_iterator_actor = SymbolIteratorActor {
173 name: registry.new_name::<SymbolIteratorActor>(),
174 };
175 let msg = EnumReply {
176 from: self.name(),
177 iterator: EnumIterator {
178 actor: symbol_iterator_actor.name(),
179 type_: EnumIteratorType::SymbolIterator,
180 count: 0,
181 },
182 };
183 registry.register(symbol_iterator_actor);
184 request.reply_final(&msg)?
185 },
186
187 "prototype" => {
188 let msg = PrototypeReply {
189 from: self.name(),
190 prototype: self.encode(registry),
191 };
192 request.reply_final(&msg)?
193 },
194
195 _ => return Err(ActorError::UnrecognizedPacketType),
196 };
197 Ok(())
198 }
199}
200
201impl ObjectActor {
202 pub fn register(
203 registry: &ActorRegistry,
204 uuid: Option<String>,
205 class: String,
206 preview: Option<ObjectPreview>,
207 ) -> String {
208 let Some(uuid) = uuid else {
209 let name = registry.new_name::<Self>();
210 let actor = ObjectActor {
211 name: name.clone(),
212 _uuid: None,
213 class,
214 preview,
215 };
216 registry.register(actor);
217 return name;
218 };
219 if !registry.script_actor_registered(uuid.clone()) {
220 let name = registry.new_name::<Self>();
221 let actor = ObjectActor {
222 name: name.clone(),
223 _uuid: Some(uuid.clone()),
224 class,
225 preview,
226 };
227
228 registry.register_script_actor(uuid, name.clone());
229 registry.register(actor);
230
231 name
232 } else {
233 registry.script_to_actor(uuid)
234 }
235 }
236}
237
238impl ActorEncode<Value> for ObjectActor {
239 fn encode(&self, registry: &ActorRegistry) -> Value {
240 let mut m = Map::new();
242 m.insert("type".to_owned(), Value::String("object".to_owned()));
243 m.insert("class".to_owned(), Value::String(self.class.clone()));
244 m.insert("actor".to_owned(), Value::String(self.name()));
245 m.insert("extensible".to_owned(), Value::Bool(true));
246 m.insert("frozen".to_owned(), Value::Bool(false));
247 m.insert("sealed".to_owned(), Value::Bool(false));
248
249 let Some(preview) = self.preview.clone() else {
252 return Value::Object(m);
253 };
254 let mut preview_map = Map::new();
255
256 if preview.kind == "ArrayLike" {
257 if let Some(length) = preview.array_length {
258 preview_map.insert("length".to_owned(), Value::Number(length.into()));
259 }
260 } else {
261 if let Some(ref props) = preview.own_properties {
262 let mut own_props_map = Map::new();
263 for prop in props {
264 let descriptor = serde_json::to_value(
265 ObjectPropertyDescriptor::from_property_descriptor(registry, prop),
266 )
267 .unwrap();
268 own_props_map.insert(prop.name.clone(), descriptor);
269 }
270 preview_map.insert("ownProperties".to_owned(), Value::Object(own_props_map));
271 }
272
273 if let Some(length) = preview.own_properties_length {
274 preview_map.insert(
275 "ownPropertiesLength".to_owned(),
276 Value::Number(length.into()),
277 );
278 m.insert("ownPropertyLength".to_owned(), Value::Number(length.into()));
279 }
280 }
281 preview_map.insert("kind".to_owned(), Value::String(preview.kind));
282
283 if let Some(function) = preview.function {
285 if let Some(name) = function.name {
286 m.insert("name".to_owned(), Value::String(name));
287 }
288 if let Some(display_name) = function.display_name {
289 m.insert("displayName".to_owned(), Value::String(display_name));
290 }
291 m.insert(
292 "parameterNames".to_owned(),
293 Value::Array(
294 function
295 .parameter_names
296 .into_iter()
297 .map(Value::String)
298 .collect(),
299 ),
300 );
301 m.insert("isAsync".to_owned(), Value::Bool(function.is_async));
302 m.insert("isGenerator".to_owned(), Value::Bool(function.is_generator));
303 }
304
305 m.insert("preview".to_owned(), Value::Object(preview_map));
306
307 Value::Object(m)
308 }
309}
310
311#[derive(MallocSizeOf)]
312struct SymbolIteratorActor {
313 name: String,
314}
315
316impl Actor for SymbolIteratorActor {
317 fn name(&self) -> String {
318 self.name.clone()
319 }
320}