use std::sync::Arc;
use crate::js_handle::JSHandle;
use crate::page::Page;
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct ConsoleMessageLocation {
pub url: String,
#[serde(rename = "lineNumber")]
pub line_number: u32,
#[serde(rename = "columnNumber")]
pub column_number: u32,
}
#[derive(Clone)]
pub struct ConsoleMessage {
inner: Arc<ConsoleMessageState>,
}
struct ConsoleMessageState {
type_str: String,
text_override: std::sync::OnceLock<String>,
explicit_text: Option<String>,
args: Vec<JSHandle>,
location: ConsoleMessageLocation,
timestamp: u64,
page: std::sync::Weak<Page>,
}
impl ConsoleMessage {
#[must_use]
pub fn new(
page: &Arc<Page>,
type_str: impl Into<String>,
text: Option<String>,
args: Vec<JSHandle>,
location: ConsoleMessageLocation,
timestamp: u64,
) -> Self {
Self {
inner: Arc::new(ConsoleMessageState {
type_str: type_str.into(),
text_override: std::sync::OnceLock::new(),
explicit_text: text,
args,
location,
timestamp,
page: Arc::downgrade(page),
}),
}
}
#[must_use]
pub fn new_detached(
type_str: impl Into<String>,
text: Option<String>,
args: Vec<JSHandle>,
location: ConsoleMessageLocation,
timestamp: u64,
) -> Self {
Self {
inner: Arc::new(ConsoleMessageState {
type_str: type_str.into(),
text_override: std::sync::OnceLock::new(),
explicit_text: text,
args,
location,
timestamp,
page: std::sync::Weak::new(),
}),
}
}
#[must_use]
pub fn type_str(&self) -> &str {
&self.inner.type_str
}
#[must_use]
pub fn text(&self) -> &str {
if let Some(ref s) = self.inner.explicit_text {
return s.as_str();
}
self
.inner
.text_override
.get_or_init(|| self.inner.args.iter().map(preview_arg).collect::<Vec<_>>().join(" "))
.as_str()
}
#[must_use]
pub fn args(&self) -> &[JSHandle] {
&self.inner.args
}
#[must_use]
pub fn location(&self) -> &ConsoleMessageLocation {
&self.inner.location
}
#[must_use]
pub fn page(&self) -> Option<Arc<Page>> {
self.inner.page.upgrade()
}
#[must_use]
pub fn timestamp(&self) -> u64 {
self.inner.timestamp
}
}
impl std::fmt::Debug for ConsoleMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ConsoleMessage")
.field("type", &self.inner.type_str)
.field("text", &self.text())
.field("args_count", &self.inner.args.len())
.field("location", &self.inner.location)
.field("timestamp", &self.inner.timestamp)
.finish()
}
}
fn preview_arg(h: &JSHandle) -> String {
match h.backing() {
crate::js_handle::JSHandleBacking::Value(v) => match v.to_json_like() {
Some(serde_json::Value::Null) => "null".to_string(),
Some(serde_json::Value::Bool(b)) => b.to_string(),
Some(serde_json::Value::Number(n)) => n.to_string(),
Some(serde_json::Value::String(s)) => s,
Some(other) => other.to_string(),
None => "JSHandle@primitive".to_string(),
},
crate::js_handle::JSHandleBacking::Remote(_) => "JSHandle@object".to_string(),
}
}