1use std::sync::Arc;
6
7use atomic_refcell::AtomicRefCell;
8use devtools_traits::{DevtoolScriptControlMsg, FrameInfo, GetEnvironmentRequest};
9use malloc_size_of_derive::MallocSizeOf;
10use serde::Serialize;
11use serde_json::{Map, Value};
12use servo_base::generic_channel::channel;
13
14use crate::actor::{Actor, ActorEncode, ActorError, ActorRegistry, new_actor_name};
15use crate::actors::environment::{EnvironmentActor, EnvironmentActorMsg};
16use crate::actors::source::SourceActor;
17use crate::protocol::{ClientRequest, JsonPacketStream};
18use crate::{StreamId, debugger_value_to_json};
19
20#[derive(Serialize)]
21struct FrameEnvironmentReply {
22 from: String,
23 #[serde(flatten)]
24 environment: EnvironmentActorMsg,
25}
26
27#[derive(Serialize)]
28#[serde(rename_all = "kebab-case")]
29pub enum FrameState {
30 OnStack,
31 Suspended,
32 Dead,
33}
34
35#[derive(Serialize)]
36pub(crate) struct FrameWhere {
37 actor: String,
38 line: u32,
39 column: u32,
40}
41
42#[derive(Serialize)]
43#[serde(rename_all = "camelCase")]
44pub(crate) struct FrameActorMsg {
45 actor: String,
46 #[serde(rename = "type")]
47 type_: String,
48 arguments: Vec<Value>,
49 async_cause: Option<String>,
50 display_name: Option<String>,
51 oldest: bool,
52 state: FrameState,
53 this: Value,
54 #[serde(rename = "where")]
55 where_: FrameWhere,
56}
57
58#[derive(MallocSizeOf)]
61pub(crate) struct FrameActor {
62 name: String,
63 source_name: String,
64 frame_result: FrameInfo,
65 current_offset: AtomicRefCell<(u32, u32)>,
66}
67
68impl Actor for FrameActor {
69 fn name(&self) -> &str {
70 &self.name
71 }
72
73 fn handle_message(
75 &self,
76 mut request: ClientRequest,
77 registry: &ActorRegistry,
78 msg_type: &str,
79 _msg: &Map<String, Value>,
80 _id: StreamId,
81 ) -> Result<(), ActorError> {
82 match msg_type {
83 "getEnvironment" => {
84 let Some((tx, rx)) = channel() else {
85 return Err(ActorError::Internal);
86 };
87 let source_actor = registry.find::<SourceActor>(&self.source_name);
88 source_actor
89 .script_sender
90 .send(DevtoolScriptControlMsg::GetEnvironment(
91 GetEnvironmentRequest::Frame(self.name().into()),
92 tx,
93 ))
94 .map_err(|_| ActorError::Internal)?;
95 let environment_name = rx.recv().map_err(|_| ActorError::Internal)?;
96
97 let msg = FrameEnvironmentReply {
98 from: self.name().into(),
99 environment: registry.encode::<EnvironmentActor, _>(&environment_name),
100 };
101 request.write_json_packet(&msg)?;
104 request.mark_handled();
105 },
106 _ => return Err(ActorError::UnrecognizedPacketType),
107 };
108 Ok(())
109 }
110}
111
112impl FrameActor {
113 pub fn register(
114 registry: &ActorRegistry,
115 source_name: String,
116 frame_result: FrameInfo,
117 ) -> Arc<Self> {
118 let name = new_actor_name::<Self>();
119 let actor = Self {
120 name,
121 source_name,
122 frame_result,
123 current_offset: Default::default(),
124 };
125 registry.register::<Self>(actor)
126 }
127
128 pub(crate) fn set_offset(&self, column: u32, line: u32) {
129 *self.current_offset.borrow_mut() = (column, line);
130 }
131}
132
133impl ActorEncode<FrameActorMsg> for FrameActor {
134 fn encode(&self, registry: &ActorRegistry) -> FrameActorMsg {
135 let state = if self.frame_result.terminated {
136 FrameState::Dead
137 } else if self.frame_result.on_stack {
138 FrameState::OnStack
139 } else {
140 FrameState::Suspended
141 };
142 let async_cause = if let FrameState::OnStack = state {
143 None
144 } else {
145 Some("await".into())
146 };
147 let (column, line) = *self.current_offset.borrow();
148 FrameActorMsg {
150 actor: self.name().into(),
151 type_: self.frame_result.type_.clone(),
152 arguments: vec![],
153 async_cause,
154 display_name: self.frame_result.display_name.clone(),
155 this: debugger_value_to_json(registry, self.frame_result.this_value.clone()),
156 oldest: self.frame_result.oldest,
157 state,
158 where_: FrameWhere {
159 actor: self.source_name.clone(),
160 line,
161 column,
162 },
163 }
164 }
165}