2021-02-13 07:31:18 -05:00
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
2020-04-01 20:19:07 -04:00
//! Bindings to the V8 Inspector API. Documentation for the V8 inspector API is
//! very sparse, so here are a few references for the next sorry soul who has to
//! dig into it.
//!
//! https://medium.com/@hyperandroid/v8-inspector-from-an-embedder-standpoint-7f9c0472e2b7
//! https://v8.dev/docs/inspector
//! https://chromedevtools.github.io/debugger-protocol-viewer/tot/
//! https://cs.chromium.org/chromium/src/v8/include/v8-inspector.h
//! https://github.com/nodejs/node/blob/v13.7.0/src/inspector_agent.cc
//! https://github.com/nodejs/node/blob/v13.7.0/src/inspector_agent.h
//! https://github.com/nodejs/node/tree/v13.7.0/src/inspector
//! https://github.com/denoland/deno/blob/v0.38.0/cli/inspector.rs
use crate ::support ::int ;
use crate ::support ::CxxVTable ;
use crate ::support ::FieldOffset ;
use crate ::support ::Opaque ;
use crate ::support ::RustVTable ;
use crate ::support ::UniquePtr ;
use crate ::support ::UniqueRef ;
use crate ::Context ;
use crate ::Isolate ;
use crate ::Local ;
2022-12-07 08:43:55 -05:00
use crate ::StackTrace ;
use crate ::Value ;
2020-11-18 09:17:25 -05:00
use std ::fmt ::{ self , Debug , Formatter } ;
2020-04-01 20:19:07 -04:00
extern " C " {
fn v8_inspector__V8Inspector__Channel__BASE__CONSTRUCT (
buf : & mut std ::mem ::MaybeUninit < Channel > ,
2020-04-16 09:35:15 -04:00
) ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8Inspector__Channel__sendResponse (
this : & mut Channel ,
call_id : int ,
message : UniquePtr < StringBuffer > ,
2020-04-16 09:35:15 -04:00
) ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8Inspector__Channel__sendNotification (
this : & mut Channel ,
message : UniquePtr < StringBuffer > ,
2020-04-16 09:35:15 -04:00
) ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8Inspector__Channel__flushProtocolNotifications (
this : & mut Channel ,
2020-04-16 09:35:15 -04:00
) ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8InspectorClient__BASE__CONSTRUCT (
buf : & mut std ::mem ::MaybeUninit < V8InspectorClient > ,
2020-04-16 09:35:15 -04:00
) ;
2020-04-01 20:19:07 -04:00
2021-01-21 04:06:34 -05:00
fn v8_inspector__V8InspectorClient__generateUniqueId (
this : & mut V8InspectorClient ,
) -> i64 ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8InspectorClient__runMessageLoopOnPause (
this : & mut V8InspectorClient ,
context_group_id : int ,
2020-04-16 09:35:15 -04:00
) ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8InspectorClient__quitMessageLoopOnPause (
this : & mut V8InspectorClient ,
2020-04-16 09:35:15 -04:00
) ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8InspectorClient__runIfWaitingForDebugger (
this : & mut V8InspectorClient ,
context_group_id : int ,
2020-04-16 09:35:15 -04:00
) ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8InspectorClient__consoleAPIMessage (
this : & mut V8InspectorClient ,
context_group_id : int ,
level : int ,
message : & StringView ,
url : & StringView ,
line_number : u32 ,
column_number : u32 ,
stack_trace : & mut V8StackTrace ,
2020-04-16 09:35:15 -04:00
) ;
2020-04-01 20:19:07 -04:00
2020-04-15 21:01:16 -04:00
fn v8_inspector__V8InspectorSession__DELETE ( this : & mut V8InspectorSession ) ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8InspectorSession__dispatchProtocolMessage (
session : * mut V8InspectorSession ,
2020-05-05 18:06:35 -04:00
message : StringView ,
2020-04-01 20:19:07 -04:00
) ;
fn v8_inspector__V8InspectorSession__schedulePauseOnNextStatement (
session : * mut V8InspectorSession ,
2020-05-05 18:06:35 -04:00
break_reason : StringView ,
break_details : StringView ,
2020-04-01 20:19:07 -04:00
) ;
2021-08-09 09:53:30 -04:00
fn v8_inspector__V8InspectorSession__canDispatchMethod (
method : StringView ,
) -> bool ;
2020-04-01 20:19:07 -04:00
2020-04-16 09:35:15 -04:00
fn v8_inspector__StringBuffer__DELETE ( this : & mut StringBuffer ) ;
2020-05-05 18:06:35 -04:00
fn v8_inspector__StringBuffer__string ( this : & StringBuffer ) -> StringView ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__StringBuffer__create (
2020-05-05 18:06:35 -04:00
source : StringView ,
2020-04-01 20:19:07 -04:00
) -> UniquePtr < StringBuffer > ;
2020-04-15 21:01:16 -04:00
fn v8_inspector__V8Inspector__DELETE ( this : & mut V8Inspector ) ;
2020-04-01 20:19:07 -04:00
fn v8_inspector__V8Inspector__create (
isolate : * mut Isolate ,
client : * mut V8InspectorClient ,
) -> * mut V8Inspector ;
fn v8_inspector__V8Inspector__connect (
inspector : * mut V8Inspector ,
context_group_id : int ,
channel : * mut Channel ,
2020-05-05 18:06:35 -04:00
state : StringView ,
2022-05-18 04:53:34 -04:00
client_trust_level : V8InspectorClientTrustLevel ,
2020-04-01 20:19:07 -04:00
) -> * mut V8InspectorSession ;
fn v8_inspector__V8Inspector__contextCreated (
2020-04-13 08:43:56 -04:00
this : * mut V8Inspector ,
context : * const Context ,
contextGroupId : int ,
2020-05-05 18:06:35 -04:00
humanReadableName : StringView ,
2022-11-26 10:11:35 -05:00
auxData : StringView ,
2020-04-01 20:19:07 -04:00
) ;
2022-11-22 17:50:49 -05:00
fn v8_inspector__V8Inspector__contextDestroyed (
this : * mut V8Inspector ,
context : * const Context ,
) ;
2022-12-07 08:43:55 -05:00
fn v8_inspector__V8Inspector__exceptionThrown (
this : * mut V8Inspector ,
context : * const Context ,
message : StringView ,
exception : * const Value ,
detailed_message : StringView ,
url : StringView ,
line_number : u32 ,
column_number : u32 ,
stack_trace : * mut V8StackTrace ,
script_id : int ,
) -> u32 ;
fn v8_inspector__V8Inspector__createStackTrace (
this : * mut V8Inspector ,
stack_trace : * const StackTrace ,
) -> * mut V8StackTrace ;
fn v8_inspector__V8StackTrace__DELETE ( this : & mut V8StackTrace ) ;
2020-04-01 20:19:07 -04:00
}
#[ no_mangle ]
pub unsafe extern " C " fn v8_inspector__V8Inspector__Channel__BASE__sendResponse (
this : & mut Channel ,
call_id : int ,
message : UniquePtr < StringBuffer > ,
) {
ChannelBase ::dispatch_mut ( this ) . send_response ( call_id , message )
}
#[ no_mangle ]
pub unsafe extern " C " fn v8_inspector__V8Inspector__Channel__BASE__sendNotification (
this : & mut Channel ,
message : UniquePtr < StringBuffer > ,
) {
ChannelBase ::dispatch_mut ( this ) . send_notification ( message )
}
#[ no_mangle ]
pub unsafe extern " C " fn v8_inspector__V8Inspector__Channel__BASE__flushProtocolNotifications (
this : & mut Channel ,
) {
ChannelBase ::dispatch_mut ( this ) . flush_protocol_notifications ( )
}
2021-01-21 04:06:34 -05:00
#[ no_mangle ]
pub unsafe extern " C " fn v8_inspector__V8InspectorClient__BASE__generateUniqueId (
this : & mut V8InspectorClient ,
) -> i64 {
V8InspectorClientBase ::dispatch_mut ( this ) . generate_unique_id ( )
}
2020-04-01 20:19:07 -04:00
#[ no_mangle ]
pub unsafe extern " C " fn v8_inspector__V8InspectorClient__BASE__runMessageLoopOnPause (
this : & mut V8InspectorClient ,
context_group_id : int ,
) {
V8InspectorClientBase ::dispatch_mut ( this )
. run_message_loop_on_pause ( context_group_id )
}
#[ no_mangle ]
pub unsafe extern " C " fn v8_inspector__V8InspectorClient__BASE__quitMessageLoopOnPause (
this : & mut V8InspectorClient ,
) {
V8InspectorClientBase ::dispatch_mut ( this ) . quit_message_loop_on_pause ( )
}
#[ no_mangle ]
pub unsafe extern " C " fn v8_inspector__V8InspectorClient__BASE__runIfWaitingForDebugger (
this : & mut V8InspectorClient ,
context_group_id : int ,
) {
V8InspectorClientBase ::dispatch_mut ( this )
. run_if_waiting_for_debugger ( context_group_id )
}
#[ no_mangle ]
pub unsafe extern " C " fn v8_inspector__V8InspectorClient__BASE__consoleAPIMessage (
this : & mut V8InspectorClient ,
context_group_id : int ,
level : int ,
message : & StringView ,
url : & StringView ,
line_number : u32 ,
column_number : u32 ,
stack_trace : & mut V8StackTrace ,
) {
V8InspectorClientBase ::dispatch_mut ( this ) . console_api_message (
context_group_id ,
level ,
message ,
url ,
line_number ,
column_number ,
stack_trace ,
)
}
#[ repr(C) ]
2020-11-18 09:17:25 -05:00
#[ derive(Debug) ]
2020-04-01 20:19:07 -04:00
pub struct Channel {
_cxx_vtable : CxxVTable ,
}
impl Channel {
pub fn send_response (
& mut self ,
call_id : i32 ,
message : UniquePtr < StringBuffer > ,
) {
unsafe {
v8_inspector__V8Inspector__Channel__sendResponse ( self , call_id , message )
}
}
pub fn send_notification ( & mut self , message : UniquePtr < StringBuffer > ) {
unsafe {
v8_inspector__V8Inspector__Channel__sendNotification ( self , message )
}
}
pub fn flush_protocol_notifications ( & mut self ) {
unsafe {
v8_inspector__V8Inspector__Channel__flushProtocolNotifications ( self )
}
}
}
pub trait AsChannel {
fn as_channel ( & self ) -> & Channel ;
fn as_channel_mut ( & mut self ) -> & mut Channel ;
}
impl AsChannel for Channel {
fn as_channel ( & self ) -> & Channel {
self
}
fn as_channel_mut ( & mut self ) -> & mut Channel {
self
}
}
impl < T > AsChannel for T
where
T : ChannelImpl ,
{
fn as_channel ( & self ) -> & Channel {
& self . base ( ) . cxx_base
}
fn as_channel_mut ( & mut self ) -> & mut Channel {
& mut self . base_mut ( ) . cxx_base
}
}
pub trait ChannelImpl : AsChannel {
fn base ( & self ) -> & ChannelBase ;
fn base_mut ( & mut self ) -> & mut ChannelBase ;
2023-01-15 09:30:38 -05:00
/// This is used for calculating the offset to the base field, and care must be taken not to create any references in the process of creating the pointer because the *const Self pointer is not valid (thus resulting in instant UB)
unsafe fn base_ptr ( this : * const Self ) -> * const ChannelBase
where
Self : Sized ;
2020-04-01 20:19:07 -04:00
2020-04-16 09:35:15 -04:00
fn send_response ( & mut self , call_id : i32 , message : UniquePtr < StringBuffer > ) ;
fn send_notification ( & mut self , message : UniquePtr < StringBuffer > ) ;
fn flush_protocol_notifications ( & mut self ) ;
2020-04-01 20:19:07 -04:00
}
pub struct ChannelBase {
cxx_base : Channel ,
offset_within_embedder : FieldOffset < Self > ,
rust_vtable : RustVTable < & 'static dyn ChannelImpl > ,
}
impl ChannelBase {
fn construct_cxx_base ( ) -> Channel {
unsafe {
let mut buf = std ::mem ::MaybeUninit ::< Channel > ::uninit ( ) ;
v8_inspector__V8Inspector__Channel__BASE__CONSTRUCT ( & mut buf ) ;
buf . assume_init ( )
}
}
fn get_cxx_base_offset ( ) -> FieldOffset < Channel > {
let buf = std ::mem ::MaybeUninit ::< Self > ::uninit ( ) ;
2022-05-10 20:22:10 -04:00
let base = unsafe { addr_of! ( ( * buf . as_ptr ( ) ) . cxx_base ) } ;
FieldOffset ::from_ptrs ( buf . as_ptr ( ) , base )
2020-04-01 20:19:07 -04:00
}
fn get_offset_within_embedder < T > ( ) -> FieldOffset < Self >
where
T : ChannelImpl ,
{
let buf = std ::mem ::MaybeUninit ::< T > ::uninit ( ) ;
let embedder_ptr : * const T = buf . as_ptr ( ) ;
2023-01-15 09:30:38 -05:00
let self_ptr : * const Self = unsafe { T ::base_ptr ( embedder_ptr ) } ;
2020-04-01 20:19:07 -04:00
FieldOffset ::from_ptrs ( embedder_ptr , self_ptr )
}
fn get_rust_vtable < T > ( ) -> RustVTable < & 'static dyn ChannelImpl >
where
T : ChannelImpl ,
{
let buf = std ::mem ::MaybeUninit ::< T > ::uninit ( ) ;
let embedder_ptr = buf . as_ptr ( ) ;
let trait_object : * const dyn ChannelImpl = embedder_ptr ;
let ( data_ptr , vtable ) : ( * const T , RustVTable < _ > ) =
unsafe { std ::mem ::transmute ( trait_object ) } ;
assert_eq! ( data_ptr , embedder_ptr ) ;
vtable
}
pub fn new < T > ( ) -> Self
where
T : ChannelImpl ,
{
Self {
cxx_base : Self ::construct_cxx_base ( ) ,
offset_within_embedder : Self ::get_offset_within_embedder ::< T > ( ) ,
rust_vtable : Self ::get_rust_vtable ::< T > ( ) ,
}
}
pub unsafe fn dispatch ( channel : & Channel ) -> & dyn ChannelImpl {
let this = Self ::get_cxx_base_offset ( ) . to_embedder ::< Self > ( channel ) ;
let embedder = this . offset_within_embedder . to_embedder ::< Opaque > ( this ) ;
std ::mem ::transmute ( ( embedder , this . rust_vtable ) )
}
pub unsafe fn dispatch_mut ( channel : & mut Channel ) -> & mut dyn ChannelImpl {
let this = Self ::get_cxx_base_offset ( ) . to_embedder_mut ::< Self > ( channel ) ;
let vtable = this . rust_vtable ;
let embedder = this . offset_within_embedder . to_embedder_mut ::< Opaque > ( this ) ;
std ::mem ::transmute ( ( embedder , vtable ) )
}
}
2020-11-18 09:17:25 -05:00
impl Debug for ChannelBase {
fn fmt ( & self , f : & mut Formatter < '_ > ) -> fmt ::Result {
f . debug_struct ( " ChannelBase " )
. field ( " cxx_base " , & self . cxx_base )
. field ( " offset_within_embedder " , & self . offset_within_embedder )
. finish ( )
}
}
2020-04-01 20:19:07 -04:00
#[ cfg(test) ]
mod tests {
use super ::* ;
use crate ::support ::UniquePtr ;
use std ::sync ::atomic ::AtomicUsize ;
use std ::sync ::atomic ::Ordering ::SeqCst ;
static MESSAGE : & [ u8 ] = b " Hello Pluto! " ;
static CALL_COUNT : AtomicUsize = AtomicUsize ::new ( 0 ) ;
// Using repr(C) to preserve field ordering and test that everything works
// when the ChannelBase field is not the first element of the struct.
#[ repr(C) ]
2020-11-18 09:17:25 -05:00
#[ derive(Debug) ]
2020-04-01 20:19:07 -04:00
pub struct TestChannel {
field1 : i32 ,
base : ChannelBase ,
field2 : u64 ,
}
impl ChannelImpl for TestChannel {
fn base ( & self ) -> & ChannelBase {
& self . base
}
fn base_mut ( & mut self ) -> & mut ChannelBase {
& mut self . base
}
2023-01-15 09:30:38 -05:00
unsafe fn base_ptr ( _this : * const Self ) -> * const ChannelBase
where
Self : Sized ,
{
unsafe { addr_of! ( ( * _this ) . base ) }
}
2020-04-01 20:19:07 -04:00
fn send_response (
& mut self ,
call_id : i32 ,
mut message : UniquePtr < StringBuffer > ,
) {
assert_eq! ( call_id , 999 ) ;
assert_eq! ( message . as_mut ( ) . unwrap ( ) . string ( ) . len ( ) , MESSAGE . len ( ) ) ;
self . log_call ( ) ;
}
fn send_notification ( & mut self , mut message : UniquePtr < StringBuffer > ) {
assert_eq! ( message . as_mut ( ) . unwrap ( ) . string ( ) . len ( ) , MESSAGE . len ( ) ) ;
self . log_call ( ) ;
}
fn flush_protocol_notifications ( & mut self ) {
self . log_call ( )
}
}
impl TestChannel {
pub fn new ( ) -> Self {
Self {
base : ChannelBase ::new ::< Self > ( ) ,
field1 : - 42 ,
field2 : 420 ,
}
}
fn log_call ( & self ) {
assert_eq! ( self . field1 , - 42 ) ;
assert_eq! ( self . field2 , 420 ) ;
CALL_COUNT . fetch_add ( 1 , SeqCst ) ;
}
}
#[ test ]
fn test_channel ( ) {
let mut channel = TestChannel ::new ( ) ;
let msg_view = StringView ::from ( MESSAGE ) ;
2020-05-05 18:06:35 -04:00
channel . send_response ( 999 , StringBuffer ::create ( msg_view ) ) ;
2020-04-01 20:19:07 -04:00
assert_eq! ( CALL_COUNT . swap ( 0 , SeqCst ) , 1 ) ;
2020-05-05 18:06:35 -04:00
channel . send_notification ( StringBuffer ::create ( msg_view ) ) ;
2020-04-01 20:19:07 -04:00
assert_eq! ( CALL_COUNT . swap ( 0 , SeqCst ) , 1 ) ;
channel . flush_protocol_notifications ( ) ;
assert_eq! ( CALL_COUNT . swap ( 0 , SeqCst ) , 1 ) ;
}
}
#[ repr(C) ]
2020-11-18 09:17:25 -05:00
#[ derive(Debug) ]
2020-04-01 20:19:07 -04:00
pub struct V8InspectorClient {
_cxx_vtable : CxxVTable ,
}
impl V8InspectorClient {
pub fn run_message_loop_on_pause ( & mut self , context_group_id : i32 ) {
unsafe {
v8_inspector__V8InspectorClient__runMessageLoopOnPause (
self ,
context_group_id ,
)
}
}
pub fn quit_message_loop_on_pause ( & mut self ) {
unsafe { v8_inspector__V8InspectorClient__quitMessageLoopOnPause ( self ) }
}
pub fn run_if_waiting_for_debugger ( & mut self , context_group_id : i32 ) {
unsafe {
v8_inspector__V8InspectorClient__runIfWaitingForDebugger (
self ,
context_group_id ,
)
}
}
#[ allow(clippy::too_many_arguments) ]
pub fn console_api_message (
& mut self ,
context_group_id : i32 ,
level : i32 ,
message : & StringView ,
url : & StringView ,
line_number : u32 ,
column_number : u32 ,
stack_trace : & mut V8StackTrace ,
) {
unsafe {
v8_inspector__V8InspectorClient__consoleAPIMessage (
self ,
context_group_id ,
level ,
message ,
url ,
line_number ,
column_number ,
stack_trace ,
)
}
}
2021-01-21 04:06:34 -05:00
pub fn generate_unique_id ( & mut self ) -> i64 {
unsafe { v8_inspector__V8InspectorClient__generateUniqueId ( self ) }
}
2020-04-01 20:19:07 -04:00
}
pub trait AsV8InspectorClient {
fn as_client ( & self ) -> & V8InspectorClient ;
fn as_client_mut ( & mut self ) -> & mut V8InspectorClient ;
}
impl AsV8InspectorClient for V8InspectorClient {
fn as_client ( & self ) -> & V8InspectorClient {
self
}
fn as_client_mut ( & mut self ) -> & mut V8InspectorClient {
self
}
}
impl < T > AsV8InspectorClient for T
where
T : V8InspectorClientImpl ,
{
fn as_client ( & self ) -> & V8InspectorClient {
& self . base ( ) . cxx_base
}
fn as_client_mut ( & mut self ) -> & mut V8InspectorClient {
& mut self . base_mut ( ) . cxx_base
}
}
#[ allow(unused_variables) ]
pub trait V8InspectorClientImpl : AsV8InspectorClient {
fn base ( & self ) -> & V8InspectorClientBase ;
fn base_mut ( & mut self ) -> & mut V8InspectorClientBase ;
2023-01-15 09:30:38 -05:00
/// This is used for calculating the offset to the base field, and care must be taken not to create any references in the process of creating the pointer because the *const Self pointer is not valid (thus resulting in instant UB)
unsafe fn base_ptr ( this : * const Self ) -> * const V8InspectorClientBase
where
Self : Sized ;
2020-04-01 20:19:07 -04:00
fn run_message_loop_on_pause ( & mut self , context_group_id : i32 ) { }
fn quit_message_loop_on_pause ( & mut self ) { }
fn run_if_waiting_for_debugger ( & mut self , context_group_id : i32 ) { }
2021-01-21 04:06:34 -05:00
fn generate_unique_id ( & mut self ) -> i64 {
0 // 0 = let V8 pick a unique id itself
}
2020-04-01 20:19:07 -04:00
#[ allow(clippy::too_many_arguments) ]
fn console_api_message (
& mut self ,
context_group_id : i32 ,
level : i32 ,
message : & StringView ,
url : & StringView ,
line_number : u32 ,
column_number : u32 ,
stack_trace : & mut V8StackTrace ,
) {
}
}
pub struct V8InspectorClientBase {
cxx_base : V8InspectorClient ,
offset_within_embedder : FieldOffset < Self > ,
rust_vtable : RustVTable < & 'static dyn V8InspectorClientImpl > ,
}
impl V8InspectorClientBase {
fn construct_cxx_base ( ) -> V8InspectorClient {
unsafe {
let mut buf = std ::mem ::MaybeUninit ::< V8InspectorClient > ::uninit ( ) ;
v8_inspector__V8InspectorClient__BASE__CONSTRUCT ( & mut buf ) ;
buf . assume_init ( )
}
}
fn get_cxx_base_offset ( ) -> FieldOffset < V8InspectorClient > {
let buf = std ::mem ::MaybeUninit ::< Self > ::uninit ( ) ;
2022-05-10 20:22:10 -04:00
let base = unsafe { addr_of! ( ( * buf . as_ptr ( ) ) . cxx_base ) } ;
FieldOffset ::from_ptrs ( buf . as_ptr ( ) , base )
2020-04-01 20:19:07 -04:00
}
fn get_offset_within_embedder < T > ( ) -> FieldOffset < Self >
where
T : V8InspectorClientImpl ,
{
let buf = std ::mem ::MaybeUninit ::< T > ::uninit ( ) ;
let embedder_ptr : * const T = buf . as_ptr ( ) ;
2023-01-15 09:30:38 -05:00
let self_ptr : * const Self = unsafe { T ::base_ptr ( embedder_ptr ) } ;
2020-04-01 20:19:07 -04:00
FieldOffset ::from_ptrs ( embedder_ptr , self_ptr )
}
fn get_rust_vtable < T > ( ) -> RustVTable < & 'static dyn V8InspectorClientImpl >
where
T : V8InspectorClientImpl ,
{
let buf = std ::mem ::MaybeUninit ::< T > ::uninit ( ) ;
let embedder_ptr = buf . as_ptr ( ) ;
let trait_object : * const dyn V8InspectorClientImpl = embedder_ptr ;
let ( data_ptr , vtable ) : ( * const T , RustVTable < _ > ) =
unsafe { std ::mem ::transmute ( trait_object ) } ;
assert_eq! ( data_ptr , embedder_ptr ) ;
vtable
}
pub fn new < T > ( ) -> Self
where
T : V8InspectorClientImpl ,
{
Self {
cxx_base : Self ::construct_cxx_base ( ) ,
offset_within_embedder : Self ::get_offset_within_embedder ::< T > ( ) ,
rust_vtable : Self ::get_rust_vtable ::< T > ( ) ,
}
}
pub unsafe fn dispatch (
client : & V8InspectorClient ,
) -> & dyn V8InspectorClientImpl {
let this = Self ::get_cxx_base_offset ( ) . to_embedder ::< Self > ( client ) ;
let embedder = this . offset_within_embedder . to_embedder ::< Opaque > ( this ) ;
std ::mem ::transmute ( ( embedder , this . rust_vtable ) )
}
pub unsafe fn dispatch_mut (
client : & mut V8InspectorClient ,
) -> & mut dyn V8InspectorClientImpl {
let this = Self ::get_cxx_base_offset ( ) . to_embedder_mut ::< Self > ( client ) ;
let vtable = this . rust_vtable ;
let embedder = this . offset_within_embedder . to_embedder_mut ::< Opaque > ( this ) ;
std ::mem ::transmute ( ( embedder , vtable ) )
}
}
2020-11-18 09:17:25 -05:00
impl Debug for V8InspectorClientBase {
fn fmt ( & self , f : & mut Formatter < '_ > ) -> fmt ::Result {
f . debug_struct ( " V8InspectorClientBase " )
. field ( " cxx_base " , & self . cxx_base )
. field ( " offset_within_embedder " , & self . offset_within_embedder )
. finish ( )
}
}
2020-04-01 20:19:07 -04:00
#[ repr(C) ]
2020-11-18 09:17:25 -05:00
#[ derive(Debug) ]
2020-04-01 20:19:07 -04:00
pub struct V8InspectorSession ( Opaque ) ;
impl V8InspectorSession {
2021-08-09 09:53:30 -04:00
pub fn can_dispatch_method ( method : StringView ) -> bool {
unsafe { v8_inspector__V8InspectorSession__canDispatchMethod ( method ) }
}
2020-05-05 18:06:35 -04:00
pub fn dispatch_protocol_message ( & mut self , message : StringView ) {
2020-04-01 20:19:07 -04:00
unsafe {
v8_inspector__V8InspectorSession__dispatchProtocolMessage ( self , message )
}
}
pub fn schedule_pause_on_next_statement (
& mut self ,
2020-05-05 18:06:35 -04:00
reason : StringView ,
detail : StringView ,
2020-04-01 20:19:07 -04:00
) {
unsafe {
v8_inspector__V8InspectorSession__schedulePauseOnNextStatement (
self , reason , detail ,
)
}
}
}
2020-04-15 21:59:08 -04:00
impl Drop for V8InspectorSession {
fn drop ( & mut self ) {
2020-04-01 20:19:07 -04:00
unsafe { v8_inspector__V8InspectorSession__DELETE ( self ) } ;
}
}
// TODO: in C++, this class is intended to be user-extensible, just like
// like `Task`, `Client`, `Channel`. In Rust this would ideally also be the
// case, but currently to obtain a `UniquePtr<StringBuffer>` is by making a
// copy using `StringBuffer::create()`.
#[ repr(C) ]
2020-11-18 09:17:25 -05:00
#[ derive(Debug) ]
2020-04-01 20:19:07 -04:00
pub struct StringBuffer {
_cxx_vtable : CxxVTable ,
}
// TODO: make it possible to obtain a `UniquePtr<StringBuffer>` directly from
// an owned `Vec<u8>` or `Vec<u16>`,
impl StringBuffer {
// The C++ class definition does not declare `string()` to be a const method,
// therefore we declare self as mutable here.
// TODO: figure out whether it'd be safe to assume a const receiver here.
// That would make it possible to implement `Deref<Target = StringBuffer>`.
2020-05-05 18:06:35 -04:00
pub fn string ( & self ) -> StringView {
2020-04-01 20:19:07 -04:00
unsafe { v8_inspector__StringBuffer__string ( self ) }
}
/// This method copies contents.
2020-05-05 18:06:35 -04:00
pub fn create ( source : StringView ) -> UniquePtr < StringBuffer > {
2020-04-01 20:19:07 -04:00
unsafe { v8_inspector__StringBuffer__create ( source ) }
}
}
2020-04-15 21:59:08 -04:00
impl Drop for StringBuffer {
fn drop ( & mut self ) {
2020-04-01 20:19:07 -04:00
unsafe { v8_inspector__StringBuffer__DELETE ( self ) }
}
}
unsafe impl Send for StringBuffer { }
use std ::iter ::ExactSizeIterator ;
use std ::iter ::IntoIterator ;
use std ::marker ::PhantomData ;
use std ::ops ::Deref ;
2022-05-10 20:22:10 -04:00
use std ::ptr ::addr_of ;
2020-04-01 20:19:07 -04:00
use std ::ptr ::null ;
use std ::ptr ::NonNull ;
use std ::slice ;
use std ::string ;
// Notes:
// * This class is ported, not wrapped using bindings.
// * Since Rust `repr(bool)` is not allowed, we're assuming that `bool` and
// `u8` have the same size. This is assumption is checked in 'support.h'.
// TODO: find/open upstream issue to allow #[repr(bool)] support.
2020-11-18 09:17:25 -05:00
#[ derive(Clone, Debug, Copy) ]
2020-04-01 20:19:07 -04:00
#[ repr(u8) ]
pub enum StringView < ' a > {
// Do not reorder!
U16 ( CharacterArray < ' a , u16 > ) ,
U8 ( CharacterArray < ' a , u8 > ) ,
}
impl StringView < 'static > {
pub fn empty ( ) -> Self {
Self ::U8 ( CharacterArray ::< 'static , u8 > ::empty ( ) )
}
}
impl fmt ::Display for StringView < '_ > {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
match self {
2020-11-18 09:17:25 -05:00
Self ::U16 ( v ) = > write! ( f , " {} " , v ) ,
Self ::U8 ( v ) = > write! ( f , " {} " , v ) ,
2020-04-01 20:19:07 -04:00
}
}
}
impl < ' a > From < & ' a [ u8 ] > for StringView < ' a > {
fn from ( v : & ' a [ u8 ] ) -> Self {
Self ::U8 ( CharacterArray ::< ' a , u8 > ::from ( v ) )
}
}
impl < ' a > From < & ' a [ u16 ] > for StringView < ' a > {
fn from ( v : & ' a [ u16 ] ) -> Self {
Self ::U16 ( CharacterArray ::< ' a , u16 > ::from ( v ) )
}
}
impl < ' a > StringView < ' a > {
pub fn is_8bit ( & self ) -> bool {
match self {
Self ::U16 ( .. ) = > false ,
Self ::U8 ( .. ) = > true ,
}
}
pub fn is_empty ( & self ) -> bool {
self . len ( ) = = 0
}
pub fn len ( & self ) -> usize {
match self {
Self ::U16 ( v ) = > v . len ( ) ,
Self ::U8 ( v ) = > v . len ( ) ,
}
}
pub fn characters8 ( & self ) -> Option < & [ u8 ] > {
match self {
Self ::U16 ( .. ) = > None ,
Self ::U8 ( v ) = > Some ( v ) ,
}
}
pub fn characters16 ( & self ) -> Option < & [ u16 ] > {
match self {
Self ::U16 ( v ) = > Some ( v ) ,
Self ::U8 ( .. ) = > None ,
}
}
}
2020-05-05 18:06:35 -04:00
impl < ' a > IntoIterator for StringView < ' a > {
type IntoIter = StringViewIterator < ' a > ;
2020-04-01 20:19:07 -04:00
type Item = u16 ;
fn into_iter ( self ) -> Self ::IntoIter {
StringViewIterator { view : self , pos : 0 }
}
}
#[ repr(C) ]
#[ derive(Copy, Clone, Debug) ]
pub struct CharacterArray < ' a , T > {
m_length : usize ,
m_characters : * const T ,
_phantom : PhantomData < & ' a T > ,
}
impl CharacterArray < 'static , u8 > {
pub fn empty ( ) -> Self {
Self {
m_length : 0 ,
m_characters : null ( ) ,
_phantom : PhantomData ,
}
}
}
impl < ' a , T > CharacterArray < ' a , T >
where
T : Copy ,
{
#[ inline(always) ]
fn len ( & self ) -> usize {
self . m_length
}
#[ inline(always) ]
fn get_at ( & self , index : usize ) -> Option < T > {
if index < self . m_length {
Some ( unsafe { * self . m_characters . add ( index ) } )
} else {
None
}
}
}
unsafe impl < ' a , T > Send for CharacterArray < ' a , T > where T : Copy { }
unsafe impl < ' a , T > Sync for CharacterArray < ' a , T > where T : Sync { }
impl fmt ::Display for CharacterArray < '_ , u8 > {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
f . write_str (
self
. iter ( )
. cloned ( )
. map ( char ::from )
. collect ::< string ::String > ( )
. as_str ( ) ,
)
}
}
impl fmt ::Display for CharacterArray < '_ , u16 > {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
2022-11-25 08:32:52 -05:00
f . write_str ( & string ::String ::from_utf16_lossy ( self ) )
2020-04-01 20:19:07 -04:00
}
}
impl < ' a , T > From < & ' a [ T ] > for CharacterArray < ' a , T > {
fn from ( v : & ' a [ T ] ) -> Self {
Self {
m_length : v . len ( ) ,
m_characters : v . as_ptr ( ) ,
_phantom : PhantomData ,
}
}
}
impl < ' a , T > Deref for CharacterArray < ' a , T > {
type Target = [ T ] ;
fn deref ( & self ) -> & [ T ] {
let Self {
m_length ,
mut m_characters ,
..
} = * self ;
if m_characters . is_null ( ) {
assert_eq! ( m_length , 0 ) ;
m_characters = NonNull ::dangling ( ) . as_ptr ( )
} ;
unsafe { slice ::from_raw_parts ( m_characters , m_length ) }
}
}
2020-11-18 09:17:25 -05:00
#[ derive(Copy, Clone, Debug) ]
2020-05-05 18:06:35 -04:00
pub struct StringViewIterator < ' a > {
view : StringView < ' a > ,
2020-04-01 20:19:07 -04:00
pos : usize ,
}
2020-05-05 18:06:35 -04:00
impl < ' a > Iterator for StringViewIterator < ' a > {
2020-04-01 20:19:07 -04:00
type Item = u16 ;
fn next ( & mut self ) -> Option < Self ::Item > {
let result = Some ( match self . view {
StringView ::U16 ( v ) = > v . get_at ( self . pos ) ? ,
StringView ::U8 ( v ) = > u16 ::from ( v . get_at ( self . pos ) ? ) ,
} ) ;
self . pos + = 1 ;
result
}
}
2020-05-05 18:06:35 -04:00
impl < ' a > ExactSizeIterator for StringViewIterator < ' a > {
2020-04-01 20:19:07 -04:00
fn len ( & self ) -> usize {
self . view . len ( )
}
}
#[ test ]
fn string_view_display ( ) {
let ok : [ u16 ; 2 ] = [ 111 , 107 ] ;
assert_eq! ( " ok " , format! ( " {} " , StringView ::from ( & ok [ .. ] ) ) ) ;
assert_eq! ( " ok " , format! ( " {} " , StringView ::from ( & b " ok " [ .. ] ) ) ) ;
assert_eq! ( " ØÞ " , format! ( " {} " , StringView ::from ( & [ 216 u8 , 222 u8 ] [ .. ] ) ) ) ;
}
2022-05-18 04:53:34 -04:00
#[ derive(Copy, Clone, Debug, Eq, Hash, PartialEq) ]
#[ repr(C) ]
pub enum V8InspectorClientTrustLevel {
Untrusted = 0 ,
FullyTrusted = 1 ,
}
2020-04-01 20:19:07 -04:00
#[ repr(C) ]
2020-11-18 09:17:25 -05:00
#[ derive(Debug) ]
2020-04-01 20:19:07 -04:00
pub struct V8Inspector ( Opaque ) ;
impl V8Inspector {
pub fn create < T > (
2020-06-03 01:38:34 -04:00
isolate : & mut Isolate ,
2020-04-01 20:19:07 -04:00
client : & mut T ,
) -> UniqueRef < V8Inspector >
where
T : AsV8InspectorClient ,
{
unsafe {
UniqueRef ::from_raw ( v8_inspector__V8Inspector__create (
2020-06-03 01:38:34 -04:00
isolate ,
2020-04-01 20:19:07 -04:00
client . as_client_mut ( ) ,
) )
}
}
pub fn connect < T > (
& mut self ,
context_group_id : i32 ,
channel : & mut T ,
2020-05-05 18:06:35 -04:00
state : StringView ,
2022-05-18 04:53:34 -04:00
client_trust_level : V8InspectorClientTrustLevel ,
2020-04-01 20:19:07 -04:00
) -> UniqueRef < V8InspectorSession >
where
T : AsChannel ,
{
unsafe {
UniqueRef ::from_raw ( v8_inspector__V8Inspector__connect (
self ,
context_group_id ,
channel . as_channel_mut ( ) ,
state ,
2022-05-18 04:53:34 -04:00
client_trust_level ,
2020-04-01 20:19:07 -04:00
) )
}
}
/// Note: this method deviates from the C++ API here because it's a lot of
/// work to bind the V8ContextInfo, which is not used elsewhere.
pub fn context_created (
& mut self ,
2020-04-13 08:43:56 -04:00
context : Local < Context > ,
2020-04-01 20:19:07 -04:00
context_group_id : i32 ,
2020-05-05 18:06:35 -04:00
human_readable_name : StringView ,
2022-11-26 10:11:35 -05:00
aux_data : StringView ,
2020-04-01 20:19:07 -04:00
) {
unsafe {
v8_inspector__V8Inspector__contextCreated (
self ,
2020-04-13 08:43:56 -04:00
& * context ,
2020-04-01 20:19:07 -04:00
context_group_id ,
human_readable_name ,
2022-11-26 10:11:35 -05:00
aux_data ,
2020-04-01 20:19:07 -04:00
)
}
}
2022-11-22 17:50:49 -05:00
pub fn context_destroyed ( & mut self , context : Local < Context > ) {
unsafe { v8_inspector__V8Inspector__contextDestroyed ( self , & * context ) }
}
2022-12-07 08:43:55 -05:00
#[ allow(clippy::too_many_arguments) ]
pub fn exception_thrown (
& mut self ,
context : Local < Context > ,
message : StringView ,
exception : Local < Value > ,
detailed_message : StringView ,
url : StringView ,
line_number : u32 ,
column_number : u32 ,
stack_trace : UniquePtr < V8StackTrace > ,
script_id : i32 ,
) -> u32 {
unsafe {
v8_inspector__V8Inspector__exceptionThrown (
self ,
& * context ,
message ,
& * exception ,
detailed_message ,
url ,
line_number ,
column_number ,
stack_trace . into_raw ( ) ,
script_id ,
)
}
}
pub fn create_stack_trace (
& mut self ,
stack_trace : Local < StackTrace > ,
) -> UniquePtr < V8StackTrace > {
unsafe {
UniquePtr ::from_raw ( v8_inspector__V8Inspector__createStackTrace (
self ,
& * stack_trace ,
) )
}
}
2020-04-01 20:19:07 -04:00
}
2020-04-15 21:59:08 -04:00
impl Drop for V8Inspector {
fn drop ( & mut self ) {
2020-04-01 20:19:07 -04:00
unsafe { v8_inspector__V8Inspector__DELETE ( self ) } ;
}
}
#[ repr(C) ]
2020-11-18 09:17:25 -05:00
#[ derive(Debug) ]
2020-04-01 20:19:07 -04:00
pub struct V8StackTrace {
_cxx_vtable : CxxVTable ,
}
2022-12-07 08:43:55 -05:00
impl Drop for V8StackTrace {
fn drop ( & mut self ) {
unsafe { v8_inspector__V8StackTrace__DELETE ( self ) } ;
}
}
2020-04-01 20:19:07 -04:00
// TODO(bnoordhuis) This needs to be fleshed out more but that can wait
// until it's actually needed.