0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2025-01-11 08:34:01 -05:00
This commit is contained in:
Bert Belder 2019-10-22 22:58:11 -07:00
parent 5b9b9bcea1
commit edebd3b10d
No known key found for this signature in database
GPG key ID: 7A77887B2E2ED461
17 changed files with 454 additions and 79 deletions

View file

@ -6,4 +6,3 @@ edition = "2018"
[build-dependencies]
cc = "1.0.45"

View file

@ -5,10 +5,10 @@ fn main() {
.cpp(true)
.flag("-std:c++17")
.debug(true)
.file("src/v8/inspector/channel.cpp")
.file("src/v8/inspector/client.cpp")
.file("src/v8/platform/task.cpp")
.file("src/v8/string_buffer.cpp")
.file("src/inspector/channel.cpp")
.file("src/inspector/client.cpp")
.file("src/platform/task.cpp")
.file("src/string_buffer.cpp")
.compile("v8-bindings");
println!("cargo:rustc-link-lib=static=v8_monolith");

View file

@ -1,5 +1,5 @@
#include "../../../v8/include/v8-inspector.h"
#include "../../support.h"
#include "../../v8/include/v8-inspector.h"
#include "../support.h"
using namespace v8_inspector;
using namespace support;

268
src/inspector/channel.rs Normal file
View file

@ -0,0 +1,268 @@
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::StringBuffer;
// class Channel {
// public:
// virtual ~Channel() = default;
// virtual void sendResponse(int callId,
// std::unique_ptr<StringBuffer> message) = 0;
// virtual void sendNotification(std::unique_ptr<StringBuffer> message) = 0;
// virtual void flushProtocolNotifications() = 0;
// };
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: int,
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: int,
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 crate::StringView;
use crate::*;
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);
}
}

View file

@ -1,5 +1,5 @@
#include "../../../v8/include/v8-inspector.h"
#include "../../support.h"
#include "../../v8/include/v8-inspector.h"
#include "../support.h"
using namespace v8_inspector;
using namespace support;

View file

@ -1,7 +1,11 @@
#![warn(clippy::all)]
#![allow(dead_code)]
pub mod inspector;
pub mod platform;
pub mod string_buffer;
pub mod string_view;
pub mod support;
pub use string_buffer::StringBuffer;
pub use string_view::StringView;

View file

@ -1,64 +0,0 @@
#![warn(clippy::all)]
#![allow(dead_code)]
mod support;
mod v8;
mod example {
use crate::support::UniquePtr;
use crate::v8::inspector::channel::*;
use crate::v8::*;
// 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: f64,
}
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>,
) {
println!(
"call_id: {:?}, message: '{:?}'",
call_id,
message.as_mut().unwrap().string().characters16().unwrap()
);
}
fn send_notification(&mut self, _message: UniquePtr<StringBuffer>) {}
fn flush_protocol_notifications(&mut self) {}
}
impl TestChannel {
pub fn new() -> Self {
Self {
base: ChannelBase::new::<Self>(),
field1: -42,
field2: 4.2,
}
}
}
}
fn main() {
use crate::v8::inspector::channel::*;
use crate::v8::*;
use example::*;
let mut ex = TestChannel::new();
let chan = ex.as_channel_mut();
let message: &[u8] = b"hello";
let message = StringView::from(message);
let message = StringBuffer::create(&message);
chan.send_response(3, message);
}

View file

@ -1,5 +1,5 @@
#include "../../../v8/include/v8-platform.h"
#include "../../support.h"
#include "../../v8/include/v8-platform.h"
#include "../support.h"
#include <iostream>

View file

@ -1,5 +1,5 @@
#include "../../v8/include/v8-inspector.h"
#include "../support.h"
#include "../v8/include/v8-inspector.h"
#include "support.h"
using namespace v8_inspector;

76
src/string_buffer.rs Normal file
View file

@ -0,0 +1,76 @@
use crate::support::CxxVTable;
use crate::support::Delete;
use crate::support::UniquePtr;
use crate::StringView;
// class StringBuffer {
// public:
// virtual ~StringBuffer() = default;
// virtual const StringView& string() = 0;
// // This method copies contents.
// static std::unique_ptr<StringBuffer> create(const StringView&);
// };
// 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)]
#[derive(Debug)]
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) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_string_buffer() {
let chars = b"Hello Venus!";
let mut buf = {
let src_view = StringView::from(&chars[..]);
StringBuffer::create(&src_view)
};
let view = buf.as_mut().unwrap().string();
assert_eq!(chars.len(), view.into_iter().len());
assert_eq!(chars.len(), view.len());
for (c1, c2) in chars.iter().copied().map(u16::from).zip(view) {
assert_eq!(c1, c2);
}
}
}

View file

@ -71,6 +71,10 @@ impl<'a> StringView<'a> {
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn len(&self) -> usize {
match self {
Self::U16(v) => v.len(),
@ -139,6 +143,9 @@ where
}
}
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<'a, T> From<&'a [T]> for CharacterArray<'a, T> {
fn from(v: &'a [T]) -> Self {
Self {

View file

@ -4,7 +4,7 @@ use crate::support::FieldOffset;
use crate::support::Opaque;
use crate::support::RustVTable;
use crate::support::UniquePtr;
use crate::v8::StringBuffer;
use crate::StringBuffer;
// class Channel {
// public:
@ -191,3 +191,78 @@ impl ChannelBase {
std::mem::transmute((embedder, vtable))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::UniquePtr;
use crate::StringView;
use crate::*;
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);
}
}

View file

@ -1,7 +1,7 @@
use crate::support::CxxVTable;
use crate::support::Delete;
use crate::support::UniquePtr;
use crate::v8::StringView;
use crate::StringView;
// class StringBuffer {
// public:
@ -11,6 +11,11 @@ use crate::v8::StringView;
// static std::unique_ptr<StringBuffer> create(const StringView&);
// };
// 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)
@ -26,13 +31,18 @@ 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) }
}