Skip to main content

devtools/actors/
property_iterator.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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}