use atomic_refcell::AtomicRefCell;
use devtools_traits::{DevtoolScriptControlMsg, FrameInfo};
use malloc_size_of_derive::MallocSizeOf;
use serde::Serialize;
use serde_json::{Map, Value};
use servo_base::generic_channel::channel;
use crate::StreamId;
use crate::actor::{Actor, ActorEncode, ActorError, ActorRegistry};
use crate::actors::environment::{EnvironmentActor, EnvironmentActorMsg};
use crate::actors::object::{ObjectActor, ObjectActorMsg};
use crate::actors::source::SourceActor;
use crate::protocol::{ClientRequest, JsonPacketStream};
#[derive(Serialize)]
struct FrameEnvironmentReply {
from: String,
#[serde(flatten)]
environment: EnvironmentActorMsg,
}
#[derive(Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum FrameState {
OnStack,
_Suspended,
_Dead,
}
#[derive(Serialize)]
pub(crate) struct FrameWhere {
actor: String,
line: u32,
column: u32,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct FrameActorMsg {
actor: String,
#[serde(rename = "type")]
type_: String,
arguments: Vec<Value>,
async_cause: Option<String>,
display_name: String,
oldest: bool,
state: FrameState,
this: ObjectActorMsg,
#[serde(rename = "where")]
where_: FrameWhere,
}
#[derive(MallocSizeOf)]
pub(crate) struct FrameActor {
name: String,
object_actor: String,
source_name: String,
frame_result: FrameInfo,
current_offset: AtomicRefCell<(u32, u32)>,
}
impl Actor for FrameActor {
fn name(&self) -> String {
self.name.clone()
}
fn handle_message(
&self,
mut request: ClientRequest,
registry: &ActorRegistry,
msg_type: &str,
_msg: &Map<String, Value>,
_id: StreamId,
) -> Result<(), ActorError> {
match msg_type {
"getEnvironment" => {
let Some((tx, rx)) = channel() else {
return Err(ActorError::Internal);
};
let source_actor = registry.find::<SourceActor>(&self.source_name);
source_actor
.script_sender
.send(DevtoolScriptControlMsg::GetEnvironment(self.name(), tx))
.map_err(|_| ActorError::Internal)?;
let environment_name = rx.recv().map_err(|_| ActorError::Internal)?;
let msg = FrameEnvironmentReply {
from: self.name(),
environment: registry.encode::<EnvironmentActor, _>(&environment_name),
};
request.write_json_packet(&msg)?;
request.mark_handled();
},
_ => return Err(ActorError::UnrecognizedPacketType),
};
Ok(())
}
}
impl FrameActor {
pub fn register(
registry: &ActorRegistry,
source_name: String,
frame_result: FrameInfo,
) -> String {
let object_name = ObjectActor::register(registry, None, "Object".to_owned(), None);
let name = registry.new_name::<Self>();
let actor = Self {
name: name.clone(),
object_actor: object_name,
source_name,
frame_result,
current_offset: Default::default(),
};
registry.register::<Self>(actor);
name
}
pub(crate) fn set_offset(&self, column: u32, line: u32) {
*self.current_offset.borrow_mut() = (column, line);
}
}
impl ActorEncode<FrameActorMsg> for FrameActor {
fn encode(&self, registry: &ActorRegistry) -> FrameActorMsg {
let state = FrameState::OnStack;
let async_cause = if let FrameState::OnStack = state {
None
} else {
Some("await".into())
};
let (column, line) = *self.current_offset.borrow();
FrameActorMsg {
actor: self.name(),
type_: self.frame_result.type_.clone(),
arguments: vec![],
async_cause,
display_name: self.frame_result.display_name.clone(),
this: registry.encode::<ObjectActor, _>(&self.object_actor),
oldest: self.frame_result.oldest,
state,
where_: FrameWhere {
actor: self.source_name.clone(),
line,
column,
},
}
}
}