diff --git a/src/array_buffer_view.rs b/src/array_buffer_view.rs new file mode 100644 index 00000000..4927e413 --- /dev/null +++ b/src/array_buffer_view.rs @@ -0,0 +1,64 @@ +use std::convert::TryInto; +use std::ops::Deref; + +use crate::support::int; +use crate::support::Opaque; +use crate::ArrayBuffer; +use crate::Local; +use crate::Object; + +extern "C" { + fn v8__ArrayBufferView__Buffer( + this: *const ArrayBufferView, + ) -> *mut ArrayBuffer; + fn v8__ArrayBufferView__ByteLength(this: *const ArrayBufferView) -> usize; + fn v8__ArrayBufferView__ByteOffset(this: *const ArrayBufferView) -> usize; + fn v8__ArrayBufferView__CopyContents( + this: *const ArrayBufferView, + dest: *mut u8, + byte_length: int, + ) -> usize; +} + +/// A base class for an instance of one of "views" over ArrayBuffer, +/// including TypedArrays and DataView (ES6 draft 15.13). +#[repr(C)] +pub struct ArrayBufferView(Opaque); + +impl ArrayBufferView { + /// Returns underlying ArrayBuffer. + pub fn buffer<'sc>(&self) -> Option> { + unsafe { Local::from_raw(v8__ArrayBufferView__Buffer(self)) } + } + + /// Size of a view in bytes. + pub fn byte_length(&self) -> usize { + unsafe { v8__ArrayBufferView__ByteLength(self) } + } + + /// Byte offset in |Buffer|. + pub fn byte_offset(&self) -> usize { + unsafe { v8__ArrayBufferView__ByteOffset(self) } + } + + /// Copy the contents of the ArrayBufferView's buffer to an embedder defined + /// memory without additional overhead that calling ArrayBufferView::Buffer + /// might incur. + /// Returns the number of bytes actually written. + pub fn copy_contents(&self, dest: &mut [u8]) -> usize { + unsafe { + v8__ArrayBufferView__CopyContents( + self, + dest.as_mut_ptr(), + dest.len().try_into().unwrap(), + ) + } + } +} + +impl Deref for ArrayBufferView { + type Target = Object; + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const _ as *const Object) } + } +} diff --git a/src/binding.cc b/src/binding.cc index 6f44da4b..2fefb8ca 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -313,6 +313,22 @@ v8::Integer* v8__Integer__NewFromUnsigned(v8::Isolate* isolate, int64_t v8__Integer__Value(const v8::Integer& self) { return self.Value(); } +v8::ArrayBuffer* v8__ArrayBufferView__Buffer(v8::ArrayBufferView& self) { + return local_to_ptr(self.Buffer()); +} + +size_t v8__ArrayBufferView__ByteLength(v8::ArrayBufferView& self) { + return self.ByteLength(); +} + +size_t v8__ArrayBufferView__ByteOffset(v8::ArrayBufferView& self) { + return self.ByteOffset(); +} + +size_t v8__ArrayBufferView__CopyContents(v8::ArrayBufferView& self, void* dest, int byte_length) { + return self.CopyContents(dest, byte_length); +} + v8::ArrayBuffer::Allocator* v8__ArrayBuffer__Allocator__NewDefaultAllocator() { return v8::ArrayBuffer::Allocator::NewDefaultAllocator(); } diff --git a/src/lib.rs b/src/lib.rs index 229fe917..6e493759 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ mod support; mod try_catch; mod value; +pub mod array_buffer_view; pub mod inspector; pub mod json; pub mod platform; diff --git a/tests/test_api.rs b/tests/test_api.rs index 71084f1b..11da729d 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -993,3 +993,38 @@ fn equality() { isolate.exit(); drop(g); } + +#[test] +fn array_buffer_view() { + let g = setup(); + let mut params = v8::Isolate::create_params(); + params.set_array_buffer_allocator(v8::Allocator::new_default_allocator()); + let mut isolate = v8::Isolate::new(params); + isolate.enter(); + let mut locker = v8::Locker::new(&isolate); + v8::HandleScope::enter(&mut locker, |s| { + let mut context = v8::Context::new(s); + context.enter(); + let source = v8::String::new(s, "new Uint8Array([23,23,23,23])").unwrap(); + let mut script = v8::Script::compile(s, context, source, None).unwrap(); + source.to_rust_string_lossy(s); + let result = script.run(s, context).unwrap(); + // TODO: safer casts. + let result: v8::Local = + unsafe { std::mem::transmute_copy(&result) }; + assert_eq!(result.byte_length(), 4); + assert_eq!(result.byte_offset(), 0); + let mut dest = [0; 4]; + let copy_bytes = result.copy_contents(&mut dest); + assert_eq!(copy_bytes, 4); + assert_eq!(dest, [23, 23, 23, 23]); + let maybe_ab = result.buffer(); + assert!(maybe_ab.is_some()); + let ab = maybe_ab.unwrap(); + assert_eq!(ab.byte_length(), 4); + context.exit(); + }); + drop(locker); + isolate.exit(); + drop(g); +}