mirror of
https://github.com/denoland/rusty_v8.git
synced 2025-03-09 13:38:51 -04:00
Merge all inspector bindings into one file (#331)
The file naming in the current src/inspector/ directory is inconsistent and difficult to navigate. It will be simpler if we just put them all in one place since they're rather interconnected.
This commit is contained in:
parent
bb0be74b0b
commit
fc948f4983
10 changed files with 908 additions and 957 deletions
908
src/inspector.rs
Normal file
908
src/inspector.rs
Normal file
|
@ -0,0 +1,908 @@
|
|||
// Copyright 2019-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
//! 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::scope_traits::InIsolate;
|
||||
use crate::support::int;
|
||||
use crate::support::CxxVTable;
|
||||
use crate::support::Delete;
|
||||
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;
|
||||
|
||||
extern "C" {
|
||||
fn v8_inspector__V8Inspector__Channel__BASE__CONSTRUCT(
|
||||
buf: &mut std::mem::MaybeUninit<Channel>,
|
||||
) -> ();
|
||||
|
||||
fn v8_inspector__V8Inspector__Channel__sendResponse(
|
||||
this: &mut Channel,
|
||||
call_id: int,
|
||||
message: UniquePtr<StringBuffer>,
|
||||
) -> ();
|
||||
fn v8_inspector__V8Inspector__Channel__sendNotification(
|
||||
this: &mut Channel,
|
||||
message: UniquePtr<StringBuffer>,
|
||||
) -> ();
|
||||
fn v8_inspector__V8Inspector__Channel__flushProtocolNotifications(
|
||||
this: &mut Channel,
|
||||
) -> ();
|
||||
|
||||
fn v8_inspector__V8InspectorClient__BASE__CONSTRUCT(
|
||||
buf: &mut std::mem::MaybeUninit<V8InspectorClient>,
|
||||
) -> ();
|
||||
|
||||
fn v8_inspector__V8InspectorClient__runMessageLoopOnPause(
|
||||
this: &mut V8InspectorClient,
|
||||
context_group_id: int,
|
||||
) -> ();
|
||||
fn v8_inspector__V8InspectorClient__quitMessageLoopOnPause(
|
||||
this: &mut V8InspectorClient,
|
||||
) -> ();
|
||||
fn v8_inspector__V8InspectorClient__runIfWaitingForDebugger(
|
||||
this: &mut V8InspectorClient,
|
||||
context_group_id: int,
|
||||
) -> ();
|
||||
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,
|
||||
) -> ();
|
||||
|
||||
fn v8_inspector__V8InspectorSession__DELETE(
|
||||
this: &'static mut V8InspectorSession,
|
||||
);
|
||||
fn v8_inspector__V8InspectorSession__dispatchProtocolMessage(
|
||||
session: *mut V8InspectorSession,
|
||||
message: &StringView,
|
||||
);
|
||||
fn v8_inspector__V8InspectorSession__schedulePauseOnNextStatement(
|
||||
session: *mut V8InspectorSession,
|
||||
break_reason: &StringView,
|
||||
break_details: &StringView,
|
||||
);
|
||||
|
||||
fn v8_inspector__StringBuffer__DELETE(this: &'static mut StringBuffer) -> ();
|
||||
fn v8_inspector__StringBuffer__string(this: &mut StringBuffer)
|
||||
-> &StringView;
|
||||
fn v8_inspector__StringBuffer__create(
|
||||
source: &StringView,
|
||||
) -> UniquePtr<StringBuffer>;
|
||||
|
||||
fn v8_inspector__V8Inspector__DELETE(this: &'static mut V8Inspector);
|
||||
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,
|
||||
state: *const StringView,
|
||||
) -> *mut V8InspectorSession;
|
||||
fn v8_inspector__V8Inspector__contextCreated(
|
||||
inspector: *mut V8Inspector,
|
||||
context: *mut Context,
|
||||
context_group_id: int,
|
||||
human_readable_name: *const StringView,
|
||||
);
|
||||
}
|
||||
|
||||
#[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()
|
||||
}
|
||||
|
||||
#[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)]
|
||||
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;
|
||||
|
||||
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) -> ();
|
||||
}
|
||||
|
||||
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();
|
||||
FieldOffset::from_ptrs(buf.as_ptr(), unsafe { &(*buf.as_ptr()).cxx_base })
|
||||
}
|
||||
|
||||
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();
|
||||
let self_ptr: *const Self = unsafe { (*embedder_ptr).base() };
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
#[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)]
|
||||
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
|
||||
}
|
||||
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);
|
||||
channel.send_response(999, StringBuffer::create(&msg_view));
|
||||
assert_eq!(CALL_COUNT.swap(0, SeqCst), 1);
|
||||
channel.send_notification(StringBuffer::create(&msg_view));
|
||||
assert_eq!(CALL_COUNT.swap(0, SeqCst), 1);
|
||||
channel.flush_protocol_notifications();
|
||||
assert_eq!(CALL_COUNT.swap(0, SeqCst), 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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) {}
|
||||
|
||||
#[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();
|
||||
FieldOffset::from_ptrs(buf.as_ptr(), unsafe { &(*buf.as_ptr()).cxx_base })
|
||||
}
|
||||
|
||||
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();
|
||||
let self_ptr: *const Self = unsafe { (*embedder_ptr).base() };
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct V8InspectorSession(Opaque);
|
||||
|
||||
impl V8InspectorSession {
|
||||
pub fn dispatch_protocol_message(&mut self, message: &StringView) {
|
||||
unsafe {
|
||||
v8_inspector__V8InspectorSession__dispatchProtocolMessage(self, message)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn schedule_pause_on_next_statement(
|
||||
&mut self,
|
||||
reason: &StringView,
|
||||
detail: &StringView,
|
||||
) {
|
||||
unsafe {
|
||||
v8_inspector__V8InspectorSession__schedulePauseOnNextStatement(
|
||||
self, reason, detail,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Delete for V8InspectorSession {
|
||||
fn delete(&'static mut self) {
|
||||
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)]
|
||||
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>`.
|
||||
pub fn string(&mut self) -> &StringView {
|
||||
unsafe { v8_inspector__StringBuffer__string(self) }
|
||||
}
|
||||
|
||||
/// This method copies contents.
|
||||
pub fn create(source: &StringView) -> UniquePtr<StringBuffer> {
|
||||
unsafe { v8_inspector__StringBuffer__create(source) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Delete for StringBuffer {
|
||||
fn delete(&'static mut self) {
|
||||
unsafe { v8_inspector__StringBuffer__DELETE(self) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for StringBuffer {}
|
||||
use std::fmt;
|
||||
use std::iter::ExactSizeIterator;
|
||||
use std::iter::IntoIterator;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
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.
|
||||
|
||||
#[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 {
|
||||
Self::U16(v) => v.fmt(f),
|
||||
Self::U8(v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a: 'b, 'b> IntoIterator for &'a StringView<'b> {
|
||||
type IntoIter = StringViewIterator<'a, 'b>;
|
||||
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 {
|
||||
f.write_str(&string::String::from_utf16_lossy(&*self))
|
||||
}
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct StringViewIterator<'a: 'b, 'b> {
|
||||
view: &'a StringView<'b>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a: 'b, 'b> Iterator for StringViewIterator<'a, 'b> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a: 'b, 'b> ExactSizeIterator for StringViewIterator<'a, 'b> {
|
||||
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(&[216u8, 222u8][..])));
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct V8Inspector(Opaque);
|
||||
|
||||
impl V8Inspector {
|
||||
pub fn create<T>(
|
||||
isolate: &mut impl InIsolate,
|
||||
client: &mut T,
|
||||
) -> UniqueRef<V8Inspector>
|
||||
where
|
||||
T: AsV8InspectorClient,
|
||||
{
|
||||
unsafe {
|
||||
UniqueRef::from_raw(v8_inspector__V8Inspector__create(
|
||||
isolate.isolate(),
|
||||
client.as_client_mut(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect<T>(
|
||||
&mut self,
|
||||
context_group_id: i32,
|
||||
channel: &mut T,
|
||||
state: &StringView,
|
||||
) -> UniqueRef<V8InspectorSession>
|
||||
where
|
||||
T: AsChannel,
|
||||
{
|
||||
unsafe {
|
||||
UniqueRef::from_raw(v8_inspector__V8Inspector__connect(
|
||||
self,
|
||||
context_group_id,
|
||||
channel.as_channel_mut(),
|
||||
state,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
mut context: Local<Context>,
|
||||
context_group_id: i32,
|
||||
human_readable_name: &StringView,
|
||||
) {
|
||||
unsafe {
|
||||
v8_inspector__V8Inspector__contextCreated(
|
||||
self,
|
||||
&mut *context,
|
||||
context_group_id,
|
||||
human_readable_name,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Delete for V8Inspector {
|
||||
fn delete(&'static mut self) {
|
||||
unsafe { v8_inspector__V8Inspector__DELETE(self) };
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct V8StackTrace {
|
||||
_cxx_vtable: CxxVTable,
|
||||
}
|
||||
|
||||
// TODO(bnoordhuis) This needs to be fleshed out more but that can wait
|
||||
// until it's actually needed.
|
|
@ -1,14 +0,0 @@
|
|||
Bindings to the V8 Inspector API
|
||||
|
||||
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
|
||||
|
|
@ -1,257 +0,0 @@
|
|||
use super::*;
|
||||
use crate::support::int;
|
||||
use crate::support::CxxVTable;
|
||||
use crate::support::FieldOffset;
|
||||
use crate::support::Opaque;
|
||||
use crate::support::RustVTable;
|
||||
use crate::support::UniquePtr;
|
||||
|
||||
extern "C" {
|
||||
fn v8_inspector__V8Inspector__Channel__BASE__CONSTRUCT(
|
||||
buf: &mut std::mem::MaybeUninit<Channel>,
|
||||
) -> ();
|
||||
|
||||
fn v8_inspector__V8Inspector__Channel__sendResponse(
|
||||
this: &mut Channel,
|
||||
call_id: int,
|
||||
message: UniquePtr<StringBuffer>,
|
||||
) -> ();
|
||||
fn v8_inspector__V8Inspector__Channel__sendNotification(
|
||||
this: &mut Channel,
|
||||
message: UniquePtr<StringBuffer>,
|
||||
) -> ();
|
||||
fn v8_inspector__V8Inspector__Channel__flushProtocolNotifications(
|
||||
this: &mut Channel,
|
||||
) -> ();
|
||||
}
|
||||
|
||||
#[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()
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
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;
|
||||
|
||||
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) -> ();
|
||||
}
|
||||
|
||||
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();
|
||||
FieldOffset::from_ptrs(buf.as_ptr(), unsafe { &(*buf.as_ptr()).cxx_base })
|
||||
}
|
||||
|
||||
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();
|
||||
let self_ptr: *const Self = unsafe { (*embedder_ptr).base() };
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
#[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)]
|
||||
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
|
||||
}
|
||||
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);
|
||||
channel.send_response(999, StringBuffer::create(&msg_view));
|
||||
assert_eq!(CALL_COUNT.swap(0, SeqCst), 1);
|
||||
channel.send_notification(StringBuffer::create(&msg_view));
|
||||
assert_eq!(CALL_COUNT.swap(0, SeqCst), 1);
|
||||
channel.flush_protocol_notifications();
|
||||
assert_eq!(CALL_COUNT.swap(0, SeqCst), 1);
|
||||
}
|
||||
}
|
|
@ -1,256 +0,0 @@
|
|||
use super::{StringView, V8StackTrace};
|
||||
use crate::support::int;
|
||||
use crate::support::CxxVTable;
|
||||
use crate::support::FieldOffset;
|
||||
use crate::support::Opaque;
|
||||
use crate::support::RustVTable;
|
||||
|
||||
extern "C" {
|
||||
fn v8_inspector__V8InspectorClient__BASE__CONSTRUCT(
|
||||
buf: &mut std::mem::MaybeUninit<V8InspectorClient>,
|
||||
) -> ();
|
||||
|
||||
fn v8_inspector__V8InspectorClient__runMessageLoopOnPause(
|
||||
this: &mut V8InspectorClient,
|
||||
context_group_id: int,
|
||||
) -> ();
|
||||
fn v8_inspector__V8InspectorClient__quitMessageLoopOnPause(
|
||||
this: &mut V8InspectorClient,
|
||||
) -> ();
|
||||
fn v8_inspector__V8InspectorClient__runIfWaitingForDebugger(
|
||||
this: &mut V8InspectorClient,
|
||||
context_group_id: int,
|
||||
) -> ();
|
||||
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,
|
||||
) -> ();
|
||||
}
|
||||
|
||||
#[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)]
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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) {}
|
||||
|
||||
#[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();
|
||||
FieldOffset::from_ptrs(buf.as_ptr(), unsafe { &(*buf.as_ptr()).cxx_base })
|
||||
}
|
||||
|
||||
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();
|
||||
let self_ptr: *const Self = unsafe { (*embedder_ptr).base() };
|
||||
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))
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
mod channel;
|
||||
mod client;
|
||||
mod session;
|
||||
mod string_buffer;
|
||||
mod string_view;
|
||||
mod v8_inspector;
|
||||
mod v8_stack_trace;
|
||||
|
||||
pub use channel::{AsChannel, Channel, ChannelBase, ChannelImpl};
|
||||
pub use client::AsV8InspectorClient;
|
||||
pub use client::V8InspectorClient;
|
||||
pub use client::V8InspectorClientBase;
|
||||
pub use client::V8InspectorClientImpl;
|
||||
pub use session::V8InspectorSession;
|
||||
pub use string_buffer::StringBuffer;
|
||||
pub use string_view::StringView;
|
||||
pub use v8_inspector::V8Inspector;
|
||||
pub use v8_stack_trace::V8StackTrace;
|
|
@ -1,47 +0,0 @@
|
|||
use super::StringView;
|
||||
use crate::support::Delete;
|
||||
use crate::support::Opaque;
|
||||
|
||||
extern "C" {
|
||||
fn v8_inspector__V8InspectorSession__DELETE(
|
||||
this: &'static mut V8InspectorSession,
|
||||
);
|
||||
fn v8_inspector__V8InspectorSession__dispatchProtocolMessage(
|
||||
session: *mut V8InspectorSession,
|
||||
message: &StringView,
|
||||
);
|
||||
fn v8_inspector__V8InspectorSession__schedulePauseOnNextStatement(
|
||||
session: *mut V8InspectorSession,
|
||||
break_reason: &StringView,
|
||||
break_details: &StringView,
|
||||
);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct V8InspectorSession(Opaque);
|
||||
|
||||
impl V8InspectorSession {
|
||||
pub fn dispatch_protocol_message(&mut self, message: &StringView) {
|
||||
unsafe {
|
||||
v8_inspector__V8InspectorSession__dispatchProtocolMessage(self, message)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn schedule_pause_on_next_statement(
|
||||
&mut self,
|
||||
reason: &StringView,
|
||||
detail: &StringView,
|
||||
) {
|
||||
unsafe {
|
||||
v8_inspector__V8InspectorSession__schedulePauseOnNextStatement(
|
||||
self, reason, detail,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Delete for V8InspectorSession {
|
||||
fn delete(&'static mut self) {
|
||||
unsafe { v8_inspector__V8InspectorSession__DELETE(self) };
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
use super::string_view::StringView;
|
||||
use crate::support::CxxVTable;
|
||||
use crate::support::Delete;
|
||||
use crate::support::UniquePtr;
|
||||
|
||||
// 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()`.
|
||||
|
||||
extern "C" {
|
||||
fn v8_inspector__StringBuffer__DELETE(this: &'static mut StringBuffer) -> ();
|
||||
fn v8_inspector__StringBuffer__string(this: &mut StringBuffer)
|
||||
-> &StringView;
|
||||
fn v8_inspector__StringBuffer__create(
|
||||
source: &StringView,
|
||||
) -> UniquePtr<StringBuffer>;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
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>`.
|
||||
pub fn string(&mut self) -> &StringView {
|
||||
unsafe { v8_inspector__StringBuffer__string(self) }
|
||||
}
|
||||
|
||||
/// This method copies contents.
|
||||
pub fn create(source: &StringView) -> UniquePtr<StringBuffer> {
|
||||
unsafe { v8_inspector__StringBuffer__create(source) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Delete for StringBuffer {
|
||||
fn delete(&'static mut self) {
|
||||
unsafe { v8_inspector__StringBuffer__DELETE(self) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for StringBuffer {}
|
|
@ -1,211 +0,0 @@
|
|||
use std::fmt;
|
||||
use std::iter::ExactSizeIterator;
|
||||
use std::iter::IntoIterator;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
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.
|
||||
|
||||
#[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 {
|
||||
Self::U16(v) => v.fmt(f),
|
||||
Self::U8(v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a: 'b, 'b> IntoIterator for &'a StringView<'b> {
|
||||
type IntoIter = StringViewIterator<'a, 'b>;
|
||||
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 {
|
||||
f.write_str(&string::String::from_utf16_lossy(&*self))
|
||||
}
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct StringViewIterator<'a: 'b, 'b> {
|
||||
view: &'a StringView<'b>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a: 'b, 'b> Iterator for StringViewIterator<'a, 'b> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a: 'b, 'b> ExactSizeIterator for StringViewIterator<'a, 'b> {
|
||||
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(&[216u8, 222u8][..])));
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
use super::channel::AsChannel;
|
||||
use super::client::AsV8InspectorClient;
|
||||
use super::session::V8InspectorSession;
|
||||
use super::Channel;
|
||||
use super::StringView;
|
||||
use super::V8InspectorClient;
|
||||
use crate::scope_traits::InIsolate;
|
||||
use crate::support::int;
|
||||
use crate::support::Delete;
|
||||
use crate::support::Opaque;
|
||||
use crate::support::UniqueRef;
|
||||
use crate::Context;
|
||||
use crate::Isolate;
|
||||
use crate::Local;
|
||||
|
||||
extern "C" {
|
||||
fn v8_inspector__V8Inspector__DELETE(this: &'static mut V8Inspector);
|
||||
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,
|
||||
state: *const StringView,
|
||||
) -> *mut V8InspectorSession;
|
||||
fn v8_inspector__V8Inspector__contextCreated(
|
||||
inspector: *mut V8Inspector,
|
||||
context: *mut Context,
|
||||
context_group_id: int,
|
||||
human_readable_name: *const StringView,
|
||||
);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct V8Inspector(Opaque);
|
||||
|
||||
impl V8Inspector {
|
||||
pub fn create<T>(
|
||||
isolate: &mut impl InIsolate,
|
||||
client: &mut T,
|
||||
) -> UniqueRef<V8Inspector>
|
||||
where
|
||||
T: AsV8InspectorClient,
|
||||
{
|
||||
unsafe {
|
||||
UniqueRef::from_raw(v8_inspector__V8Inspector__create(
|
||||
isolate.isolate(),
|
||||
client.as_client_mut(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect<T>(
|
||||
&mut self,
|
||||
context_group_id: i32,
|
||||
channel: &mut T,
|
||||
state: &StringView,
|
||||
) -> UniqueRef<V8InspectorSession>
|
||||
where
|
||||
T: AsChannel,
|
||||
{
|
||||
unsafe {
|
||||
UniqueRef::from_raw(v8_inspector__V8Inspector__connect(
|
||||
self,
|
||||
context_group_id,
|
||||
channel.as_channel_mut(),
|
||||
state,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
mut context: Local<Context>,
|
||||
context_group_id: i32,
|
||||
human_readable_name: &StringView,
|
||||
) {
|
||||
unsafe {
|
||||
v8_inspector__V8Inspector__contextCreated(
|
||||
self,
|
||||
&mut *context,
|
||||
context_group_id,
|
||||
human_readable_name,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Delete for V8Inspector {
|
||||
fn delete(&'static mut self) {
|
||||
unsafe { v8_inspector__V8Inspector__DELETE(self) };
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
use crate::support::CxxVTable;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct V8StackTrace {
|
||||
_cxx_vtable: CxxVTable,
|
||||
}
|
||||
|
||||
// TODO(bnoordhuis) This needs to be fleshed out more but that can wait
|
||||
// until it's actually needed.
|
Loading…
Add table
Reference in a new issue