Skip to main content

devtools_traits/
lib.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
5//! This module contains shared types and messages for use by devtools/script.
6//! The traits are here instead of in script so that the devtools crate can be
7//! modified independently of the rest of Servo.
8//!
9//! Since these types can be sent through the IPC channel and use non
10//! self-describing serializers, the `flatten`, `skip*`, `tag` and `untagged`
11//! serde annotations are not supported. Types like `serde_json::Value` aren't
12//! supported either. For JSON serialization it is preferred to use a wrapper
13//! struct in the devtools crate instead.
14
15#![crate_name = "devtools_traits"]
16#![crate_type = "rlib"]
17#![deny(unsafe_code)]
18
19use core::fmt;
20use std::collections::HashMap;
21use std::fmt::Display;
22use std::net::TcpStream;
23use std::str::FromStr;
24use std::time::{Duration, SystemTime, UNIX_EPOCH};
25
26pub use embedder_traits::ConsoleLogLevel;
27use embedder_traits::Theme;
28use http::{HeaderMap, Method};
29use malloc_size_of_derive::MallocSizeOf;
30use net_traits::TlsSecurityInfo;
31use net_traits::http_status::HttpStatus;
32use net_traits::request::Destination;
33use profile_traits::mem::ReportsChan;
34use serde::de::{Error, Visitor};
35use serde::{Deserialize, Serialize};
36use servo_base::cross_process_instant::CrossProcessInstant;
37use servo_base::generic_channel::GenericSender;
38use servo_base::id::{BrowsingContextId, PipelineId, WebViewId};
39use servo_url::ServoUrl;
40use uuid::Uuid;
41
42// Information would be attached to NewGlobal to be received and show in devtools.
43// Extend these fields if we need more information.
44#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
45pub struct DevtoolsPageInfo {
46    pub title: String,
47    pub url: ServoUrl,
48    pub is_top_level_global: bool,
49    pub is_service_worker: bool,
50}
51
52#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
53pub struct CSSError {
54    pub filename: String,
55    pub line: u32,
56    pub column: u32,
57    pub msg: String,
58}
59
60/// Messages to instruct the devtools server to update its known actors/state
61/// according to changes in the browser.
62#[derive(Debug)]
63pub enum DevtoolsControlMsg {
64    /// Messages from threads in the chrome process (resource/constellation/devtools)
65    FromChrome(ChromeToDevtoolsControlMsg),
66    /// Messages from script threads
67    FromScript(ScriptToDevtoolsControlMsg),
68    /// Sent when a devtools client thread terminates.
69    ClientExited,
70}
71
72/// Events that the devtools server must act upon.
73// FIXME: https://github.com/servo/servo/issues/34591
74#[expect(clippy::large_enum_variant)]
75#[derive(Debug)]
76pub enum ChromeToDevtoolsControlMsg {
77    /// A new client has connected to the server.
78    AddClient(TcpStream),
79    /// The browser is shutting down.
80    ServerExitMsg,
81    /// A network event occurred (request, reply, etc.). The actor with the
82    /// provided name should be notified.
83    NetworkEvent(String, NetworkEvent),
84    /// Perform a memory report.
85    CollectMemoryReport(ReportsChan),
86}
87
88/// The state of a page navigation.
89#[derive(Debug, Deserialize, Serialize)]
90pub enum NavigationState {
91    /// A browsing context is about to navigate to a given URL.
92    Start(ServoUrl),
93    /// A browsing context has completed navigating to the provided pipeline.
94    Stop(PipelineId, DevtoolsPageInfo),
95}
96
97#[derive(Debug, Deserialize, Serialize)]
98/// Events that the devtools server must act upon.
99pub enum ScriptToDevtoolsControlMsg {
100    /// A new global object was created, associated with a particular pipeline.
101    /// The means of communicating directly with it are provided.
102    NewGlobal(
103        (BrowsingContextId, PipelineId, Option<WorkerId>, WebViewId),
104        GenericSender<DevtoolScriptControlMsg>,
105        DevtoolsPageInfo,
106    ),
107    /// The given browsing context is performing a navigation.
108    Navigate(BrowsingContextId, NavigationState),
109    /// A particular page has invoked the console API.
110    ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
111    /// Request to clear the console for a given pipeline.
112    ClearConsole(PipelineId, Option<WorkerId>),
113    /// An animation frame with the given timestamp was processed in a script thread.
114    /// The actor with the provided name should be notified.
115    FramerateTick(String, f64),
116
117    /// Report a CSS parse error for the given pipeline
118    ReportCSSError(PipelineId, CSSError),
119
120    /// Report a page error for the given pipeline
121    ReportPageError(PipelineId, PageError),
122
123    /// Report a page title change
124    TitleChanged(PipelineId, String),
125
126    /// Get source information from script
127    CreateSourceActor(
128        GenericSender<DevtoolScriptControlMsg>,
129        PipelineId,
130        SourceInfo,
131    ),
132
133    UpdateSourceContent(PipelineId, String),
134
135    DomMutation(PipelineId, DomMutation),
136
137    /// The debugger is paused, sending frame information.
138    DebuggerPause(PipelineId, FrameOffset, PauseReason),
139
140    /// Get frame information from script
141    CreateFrameActor(GenericSender<String>, PipelineId, FrameInfo),
142
143    /// Get object information from script
144    CreateObjectActor(GenericSender<String>, DebuggerValue),
145
146    /// Get environment information from script
147    CreateEnvironmentActor(
148        GenericSender<String>,
149        EnvironmentInfo,
150        Option<String>,
151        Option<String>,
152    ),
153}
154
155#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
156pub enum DomMutation {
157    AttributeModified {
158        node: String,
159        attribute_name: String,
160        new_value: Option<String>,
161    },
162}
163
164#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
165#[serde(rename_all = "camelCase")]
166pub struct ObjectPreview {
167    pub kind: String,
168    pub size: Option<u32>,
169    pub entries: Option<Vec<(DebuggerValue, DebuggerValue)>>,
170    pub own_properties: Option<Vec<PropertyDescriptor>>,
171    pub own_properties_length: Option<u32>,
172    pub function: Option<FunctionPreview>,
173    pub array_length: Option<u32>,
174    pub items: Option<Vec<DebuggerValue>>,
175}
176
177#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
178#[serde(rename_all = "camelCase")]
179pub struct FunctionPreview {
180    pub name: Option<String>,
181    pub display_name: Option<String>,
182    pub parameter_names: Vec<String>,
183    pub is_async: Option<bool>,
184    pub is_generator: Option<bool>,
185}
186
187struct DebuggerNumberVisitor;
188
189impl Visitor<'_> for DebuggerNumberVisitor {
190    type Value = f64;
191
192    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
193        formatter.write_str("a debugger value number")
194    }
195
196    fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
197        Ok(value)
198    }
199
200    fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
201        Ok(value as f64)
202    }
203
204    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
205        Ok(value as f64)
206    }
207
208    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
209    where
210        E: Error,
211    {
212        value.parse().map_err(E::custom)
213    }
214}
215
216fn deserialize_debugger_number<'de, D>(deserializer: D) -> Result<f64, D::Error>
217where
218    D: serde::Deserializer<'de>,
219{
220    // `DebuggerValue` is also sent over Servo IPC, not only through debugger.js.
221    if !deserializer.is_human_readable() {
222        return f64::deserialize(deserializer);
223    }
224
225    deserializer.deserialize_any(DebuggerNumberVisitor)
226}
227
228#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
229#[serde(rename_all_fields = "camelCase")]
230pub enum DebuggerValue {
231    VoidValue,
232    NullValue(bool),
233    BooleanValue(bool),
234    NumberValue(#[serde(deserialize_with = "deserialize_debugger_number")] f64),
235    StringValue(String),
236    ObjectValue {
237        actor: Option<String>,
238        class: String,
239        own_property_length: Option<u32>,
240        preview: Option<Box<ObjectPreview>>,
241    },
242}
243
244/// <https://searchfox.org/mozilla-central/source/devtools/server/actors/object/property-iterator.js#51>
245#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
246#[serde(rename_all = "camelCase")]
247pub struct PropertyDescriptor {
248    pub name: String,
249    pub value: DebuggerValue,
250    pub configurable: bool,
251    pub enumerable: bool,
252    pub writable: bool,
253    pub is_accessor: bool,
254}
255
256#[derive(Debug, Deserialize, Serialize)]
257#[serde(rename_all = "camelCase")]
258pub struct EvaluateJSReply {
259    pub value: DebuggerValue,
260    pub exception_message: Option<String>,
261    pub has_exception: bool,
262}
263
264#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
265pub struct AttrInfo {
266    pub namespace: String,
267    pub name: String,
268    pub value: String,
269}
270
271#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
272#[serde(rename_all = "camelCase")]
273pub struct NodeInfo {
274    pub unique_id: String,
275    pub host: Option<String>,
276    #[serde(rename = "baseURI")]
277    pub base_uri: String,
278    pub parent: String,
279    pub node_type: u16,
280    pub node_name: String,
281    pub node_value: Option<String>,
282    pub num_children: usize,
283    pub attrs: Vec<AttrInfo>,
284    pub is_top_level_document: bool,
285    pub shadow_root_mode: Option<ShadowRootMode>,
286    pub is_shadow_host: bool,
287    pub display: Option<String>,
288    /// Whether this node is currently displayed.
289    ///
290    /// For example, the node might have `display: none`.
291    pub is_displayed: bool,
292
293    /// The `DOCTYPE` name if this is a `DocumentType` node, `None` otherwise
294    pub doctype_name: Option<String>,
295
296    /// The `DOCTYPE` public identifier if this is a `DocumentType` node , `None` otherwise
297    pub doctype_public_identifier: Option<String>,
298
299    /// The `DOCTYPE` system identifier if this is a `DocumentType` node, `None` otherwise
300    pub doctype_system_identifier: Option<String>,
301
302    pub has_event_listeners: bool,
303}
304
305pub struct StartedTimelineMarker {
306    name: String,
307    start_time: CrossProcessInstant,
308    start_stack: Option<Vec<()>>,
309}
310
311#[derive(Debug, Deserialize, Serialize)]
312pub struct TimelineMarker {
313    pub name: String,
314    pub start_time: CrossProcessInstant,
315    pub start_stack: Option<Vec<()>>,
316    pub end_time: CrossProcessInstant,
317    pub end_stack: Option<Vec<()>>,
318}
319
320#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
321pub enum TimelineMarkerType {
322    Reflow,
323    DOMEvent,
324}
325
326#[derive(Debug, Deserialize, Serialize)]
327#[serde(rename_all = "camelCase")]
328pub struct NodeStyle {
329    pub name: String,
330    pub value: String,
331    pub priority: String,
332}
333
334#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
335#[serde(tag = "type", rename_all = "camelCase")]
336pub enum AncestorData {
337    Layer {
338        actor_id: Option<String>,
339        value: Option<String>,
340    },
341}
342
343#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
344#[serde(rename_all = "camelCase")]
345pub struct MatchedRule {
346    pub selector: String,
347    pub stylesheet_index: usize,
348    pub block_id: usize,
349    pub ancestor_data: Vec<AncestorData>,
350}
351
352/// The properties of a DOM node as computed by layout.
353#[derive(Debug, Deserialize, Serialize)]
354#[serde(rename_all = "kebab-case")]
355pub struct ComputedNodeLayout {
356    pub display: String,
357    pub position: String,
358    pub z_index: String,
359    pub box_sizing: String,
360
361    pub margin_top: String,
362    pub margin_right: String,
363    pub margin_bottom: String,
364    pub margin_left: String,
365
366    pub border_top_width: String,
367    pub border_right_width: String,
368    pub border_bottom_width: String,
369    pub border_left_width: String,
370
371    pub padding_top: String,
372    pub padding_right: String,
373    pub padding_bottom: String,
374    pub padding_left: String,
375
376    pub width: f32,
377    pub height: f32,
378}
379
380#[derive(Debug, Default, Deserialize, Serialize)]
381pub struct AutoMargins {
382    pub top: bool,
383    pub right: bool,
384    pub bottom: bool,
385    pub left: bool,
386}
387
388#[derive(Debug, Deserialize, Serialize)]
389pub enum GetHTMLType {
390    OuterHTML,
391    InnerHTML,
392}
393
394/// Messages to process in a particular script thread, as instructed by a devtools client.
395/// TODO: better error handling, e.g. if pipeline id lookup fails?
396#[derive(Debug, Deserialize, Serialize)]
397pub enum DevtoolScriptControlMsg {
398    /// Retrieve the details of the root node (ie. the document) for the given pipeline.
399    GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
400    /// Retrieve the details of the document element for the given pipeline.
401    GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
402    /// Retrieve the details of the child nodes of the given node in the given pipeline.
403    GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
404    /// Retrieve the CSS style properties defined in the attribute tag for the given node.
405    GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
406    /// Retrieve the CSS style properties defined in an stylesheet for the given selector.
407    GetStylesheetStyle(
408        PipelineId,
409        String,
410        MatchedRule,
411        GenericSender<Option<Vec<NodeStyle>>>,
412    ),
413    /// Retrieve the list of stylesheets for the given pipeline and node.
414    GetStyleSheets(PipelineId, GenericSender<Vec<StyleSheetInfo>>),
415    /// Retrieve the actual CSS text for the stylesheet with the given node ID and index.
416    GetStyleSheetText(PipelineId, i32, GenericSender<Option<String>>),
417    /// Retrieves the CSS selectors for the given node. A selector is comprised of the text
418    /// of the selector and the id of the stylesheet that contains it.
419    GetSelectors(PipelineId, String, GenericSender<Option<Vec<MatchedRule>>>),
420    /// Retrieve the computed CSS style properties for the given node.
421    GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
422    /// Get information about event listeners on a node.
423    GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
424    /// Retrieve the computed layout properties of the given node in the given pipeline.
425    GetLayout(
426        PipelineId,
427        String,
428        GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
429    ),
430    /// Get a unique XPath selector for the node.
431    GetXPath(PipelineId, String, GenericSender<String>),
432    /// Get inner/outer HTML on a node.
433    GetInnerOrOuterHTML(
434        PipelineId,
435        String,
436        GenericSender<Option<String>>,
437        GetHTMLType,
438    ),
439    /// Update a given node's attributes with a list of modifications.
440    ModifyAttribute(PipelineId, String, Vec<AttrModification>),
441    /// Update a given node's style rules with a list of modifications.
442    ModifyRule(PipelineId, String, Vec<RuleModification>),
443    /// Request live console messages for a given pipeline (true if desired, false otherwise).
444    WantsLiveNotifications(PipelineId, bool),
445    /// Request live notifications for a given set of timeline events for a given pipeline.
446    SetTimelineMarkers(
447        PipelineId,
448        Vec<TimelineMarkerType>,
449        GenericSender<Option<TimelineMarker>>,
450    ),
451    /// Withdraw request for live timeline notifications for a given pipeline.
452    DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
453    /// Request a callback directed at the given actor name from the next animation frame
454    /// executed in the given pipeline.
455    RequestAnimationFrame(PipelineId, String),
456    /// Direct the WebView containing the given pipeline to load a new URL,
457    /// as if it was typed by the user.
458    NavigateTo(PipelineId, ServoUrl),
459    /// Direct the WebView containing the given pipeline to traverse history backward
460    /// up to one step.
461    GoBack(PipelineId),
462    /// Direct the WebView containing the given pipeline to traverse history forward
463    /// up to one step.
464    GoForward(PipelineId),
465    /// Direct the given pipeline to reload the current page.
466    Reload(PipelineId),
467    /// Gets the list of all allowed CSS rules and possible values.
468    GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
469    /// Simulates a light or dark color scheme for the given pipeline
470    SimulateColorScheme(PipelineId, Theme),
471    /// Highlight the given DOM node
472    HighlightDomNode(PipelineId, Option<String>),
473
474    Eval(
475        String,
476        PipelineId,
477        Option<String>,
478        bool,
479        GenericSender<EvaluateJSReply>,
480    ),
481    GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
482    SetBreakpoint(u32, u32, u32),
483    ClearBreakpoint(u32, u32, u32),
484    Interrupt,
485    Resume(Option<String>, Option<String>),
486    ListFrames(PipelineId, u32, u32, GenericSender<Vec<String>>),
487    GetEnvironment(GetEnvironmentRequest, GenericSender<String>),
488    Blackbox(u32, BlackboxCoverage),
489    Unblackbox(u32, BlackboxCoverage),
490}
491
492#[derive(Debug, Deserialize, Serialize)]
493pub enum GetEnvironmentRequest {
494    Global(PipelineId),
495    Frame(String),
496}
497
498#[derive(Debug, Deserialize, Serialize)]
499pub enum BlackboxCoverage {
500    Full,
501    Partial((u32, u32), (u32, u32)),
502}
503
504#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
505#[serde(rename_all = "camelCase")]
506pub struct AttrModification {
507    pub attribute_name: String,
508    pub new_value: Option<String>,
509}
510
511#[derive(Clone, Debug, Deserialize, Serialize)]
512#[serde(rename_all = "camelCase")]
513pub struct RuleModification {
514    #[serde(rename = "type")]
515    pub type_: String,
516    pub index: u32,
517    pub name: String,
518    pub value: String,
519    pub priority: String,
520}
521
522#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
523#[serde(rename_all = "camelCase")]
524pub struct StackFrame {
525    pub filename: String,
526    pub function_name: String,
527    pub column_number: u32,
528    pub line_number: u32,
529    // Not implemented in Servo
530    // source_id
531}
532
533pub fn get_time_stamp() -> u64 {
534    SystemTime::now()
535        .duration_since(UNIX_EPOCH)
536        .unwrap_or_default()
537        .as_millis() as u64
538}
539
540#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
541#[serde(rename_all = "camelCase")]
542pub struct ConsoleMessageFields {
543    pub level: ConsoleLogLevel,
544    pub filename: String,
545    pub line_number: u32,
546    pub column_number: u32,
547    pub time_stamp: u64,
548}
549
550#[derive(Clone, Debug, Deserialize, Serialize)]
551pub struct ConsoleMessage {
552    pub fields: ConsoleMessageFields,
553    pub arguments: Vec<DebuggerValue>,
554    pub stacktrace: Option<Vec<StackFrame>>,
555}
556
557#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
558#[serde(rename_all = "camelCase")]
559pub struct PageError {
560    pub error_message: String,
561    pub source_name: String,
562    pub line_number: u32,
563    pub column_number: u32,
564    pub time_stamp: u64,
565}
566
567#[derive(Debug, PartialEq, MallocSizeOf)]
568pub struct HttpRequest {
569    pub url: ServoUrl,
570    pub method: Method,
571    pub headers: HeaderMap,
572    pub body: Option<bytes::Bytes>,
573    pub pipeline_id: PipelineId,
574    pub started_date_time: SystemTime,
575    pub time_stamp: i64,
576    pub connect_time: Duration,
577    pub send_time: Duration,
578    pub destination: Destination,
579    pub is_xhr: bool,
580    pub browsing_context_id: BrowsingContextId,
581}
582
583#[derive(Debug, PartialEq, MallocSizeOf)]
584pub struct HttpResponse {
585    #[ignore_malloc_size_of = "Http type"]
586    pub headers: Option<HeaderMap>,
587    pub status: HttpStatus,
588    pub body: Option<bytes::Bytes>,
589    pub from_cache: bool,
590    pub pipeline_id: PipelineId,
591    pub browsing_context_id: BrowsingContextId,
592}
593
594#[derive(Debug, PartialEq)]
595pub struct SecurityInfoUpdate {
596    pub browsing_context_id: BrowsingContextId,
597    pub security_info: Option<TlsSecurityInfo>,
598}
599
600#[derive(Debug)]
601pub enum NetworkEvent {
602    HttpRequest(HttpRequest),
603    HttpRequestUpdate(HttpRequest),
604    HttpResponse(HttpResponse),
605    SecurityInfo(SecurityInfoUpdate),
606}
607
608impl NetworkEvent {
609    pub fn forward_to_devtools(&self) -> bool {
610        match self {
611            NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
612            NetworkEvent::HttpRequestUpdate(_) => true,
613            NetworkEvent::HttpResponse(_) => true,
614            NetworkEvent::SecurityInfo(_) => true,
615        }
616    }
617}
618
619impl TimelineMarker {
620    pub fn start(name: String) -> StartedTimelineMarker {
621        StartedTimelineMarker {
622            name,
623            start_time: CrossProcessInstant::now(),
624            start_stack: None,
625        }
626    }
627}
628
629impl StartedTimelineMarker {
630    pub fn end(self) -> TimelineMarker {
631        TimelineMarker {
632            name: self.name,
633            start_time: self.start_time,
634            start_stack: self.start_stack,
635            end_time: CrossProcessInstant::now(),
636            end_stack: None,
637        }
638    }
639}
640#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
641pub struct WorkerId(pub Uuid);
642impl Display for WorkerId {
643    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
644        write!(f, "{}", self.0)
645    }
646}
647impl FromStr for WorkerId {
648    type Err = uuid::Error;
649
650    fn from_str(s: &str) -> Result<Self, Self::Err> {
651        Ok(Self(s.parse()?))
652    }
653}
654
655#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
656#[serde(rename_all = "camelCase")]
657pub struct CssDatabaseProperty {
658    pub is_inherited: bool,
659    pub values: Vec<String>,
660    pub supports: Vec<String>,
661    pub subproperties: Vec<String>,
662}
663
664#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
665pub enum ShadowRootMode {
666    Open,
667    Closed,
668}
669
670impl fmt::Display for ShadowRootMode {
671    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
672        match self {
673            Self::Open => write!(f, "open"),
674            Self::Closed => write!(f, "close"),
675        }
676    }
677}
678
679#[derive(Debug, Deserialize, Serialize)]
680pub struct SourceInfo {
681    pub url: ServoUrl,
682    pub introduction_type: String,
683    pub inline: bool,
684    pub worker_id: Option<WorkerId>,
685    pub content: Option<String>,
686    pub content_type: Option<String>,
687    pub spidermonkey_id: u32,
688}
689
690#[derive(Clone, Debug, Deserialize, Serialize)]
691#[serde(rename_all = "camelCase")]
692pub struct RecommendedBreakpointLocation {
693    pub script_id: u32,
694    pub offset: u32,
695    pub line_number: u32,
696    pub column_number: u32,
697    pub is_step_start: bool,
698}
699
700#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
701pub struct FrameInfo {
702    pub display_name: Option<String>,
703    pub on_stack: bool,
704    pub oldest: bool,
705    pub this_value: DebuggerValue,
706    pub terminated: bool,
707    pub type_: String,
708    pub url: String,
709}
710
711#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
712pub struct EnvironmentInfo {
713    pub type_: Option<String>,
714    pub scope_kind: Option<String>,
715    pub function_display_name: Option<String>,
716    pub object: Option<DebuggerValue>,
717    pub binding_variables: Vec<PropertyDescriptor>,
718}
719
720#[derive(Clone, Debug, Deserialize, Serialize)]
721pub struct StyleSheetInfo {
722    pub href: Option<String>,
723    pub disabled: bool,
724    pub title: String,
725    pub style_sheet_index: i32,
726    pub system: bool,
727    pub rule_count: u32,
728}
729
730#[derive(Clone, Debug, Deserialize, Serialize)]
731pub struct EventListenerInfo {
732    pub event_type: String,
733    pub capturing: bool,
734}
735
736#[derive(Debug, Deserialize, Serialize)]
737#[serde(rename_all = "camelCase")]
738pub struct PauseReason {
739    #[serde(rename = "type")]
740    pub type_: String,
741    pub on_next: Option<bool>,
742}
743
744#[derive(Debug, Deserialize, Serialize)]
745pub struct FrameOffset {
746    pub actor: String,
747    pub column: u32,
748    pub line: u32,
749}