devtools/actors/
property_iterator.rs1use std::collections::HashMap;
6use std::sync::Arc;
7
8use devtools_traits::{DebuggerValue, PropertyDescriptor};
9use malloc_size_of_derive::MallocSizeOf;
10use serde::Serialize;
11use serde_json::{Map, Value};
12
13use crate::actor::{Actor, ActorError, ActorRegistry, new_actor_name};
14use crate::actors::object::ObjectPropertyDescriptor;
15use crate::protocol::ClientRequest;
16use crate::{StreamId, debugger_value_to_json};
17
18#[derive(Serialize)]
19#[serde(rename_all = "camelCase")]
20struct SliceReply {
21 from: String,
22 own_properties: HashMap<String, ObjectPropertyDescriptor>,
23}
24
25#[derive(Serialize)]
26struct MapEntryPreview {
27 key: Value,
28 value: Value,
29}
30
31#[derive(Serialize)]
32struct MapEntryGrip {
33 #[serde(rename = "type")]
34 type_: &'static str,
35 preview: MapEntryPreview,
36}
37
38impl ObjectPropertyDescriptor {
39 fn from_map_entry(
40 registry: &ActorRegistry,
41 key: &DebuggerValue,
42 value: &DebuggerValue,
43 ) -> Self {
44 Self {
45 value: serde_json::to_value(MapEntryGrip {
46 type_: "mapEntry",
47 preview: MapEntryPreview {
48 key: debugger_value_to_json(registry, key.clone()),
49 value: debugger_value_to_json(registry, value.clone()),
50 },
51 })
52 .unwrap_or_default(),
53 configurable: None,
54 enumerable: true,
55 writable: None,
56 is_accessor: None,
57 }
58 }
59}
60
61#[derive(MallocSizeOf)]
62pub(crate) enum PropertyIteratorEntry {
63 Property(PropertyDescriptor),
64 MapEntry(DebuggerValue, DebuggerValue),
65}
66
67#[derive(MallocSizeOf)]
68pub(crate) struct PropertyIteratorActor {
69 name: String,
70 entries: Vec<PropertyIteratorEntry>,
71}
72
73impl PropertyIteratorActor {
74 pub fn register(registry: &ActorRegistry, entries: Vec<PropertyIteratorEntry>) -> Arc<Self> {
75 let name = new_actor_name::<Self>();
76 let actor = Self { name, entries };
77 registry.register::<Self>(actor)
78 }
79
80 pub fn count(&self) -> u32 {
81 self.entries.len() as u32
82 }
83}
84
85impl Actor for PropertyIteratorActor {
86 fn name(&self) -> &str {
87 &self.name
88 }
89
90 fn handle_message(
91 &self,
92 request: ClientRequest,
93 registry: &ActorRegistry,
94 msg_type: &str,
95 msg: &Map<String, Value>,
96 _id: StreamId,
97 ) -> Result<(), ActorError> {
98 match msg_type {
99 "slice" => {
100 let start = msg.get("start").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
101 let count = msg
102 .get("count")
103 .and_then(|v| v.as_u64())
104 .unwrap_or(self.entries.len() as u64) as usize;
105
106 let mut own_properties = HashMap::new();
107 for (index, entry) in self.entries.iter().enumerate().skip(start).take(count) {
108 match entry {
109 PropertyIteratorEntry::Property(prop) => {
110 own_properties.insert(
111 prop.name.clone(),
112 ObjectPropertyDescriptor::from_property_descriptor(registry, prop),
113 );
114 },
115 PropertyIteratorEntry::MapEntry(key, value) => {
116 own_properties.insert(
117 index.to_string(),
118 ObjectPropertyDescriptor::from_map_entry(registry, key, value),
119 );
120 },
121 }
122 }
123
124 let reply = SliceReply {
125 from: self.name().into(),
126 own_properties,
127 };
128 request.reply_final(&reply)?
129 },
130 _ => return Err(ActorError::UnrecognizedPacketType),
131 }
132 Ok(())
133 }
134}