Skip to content

Commit

Permalink
JsArrayBuffer take method and docs (#2454)
Browse files Browse the repository at this point in the history
<!---
Thank you for contributing to Boa! Please fill out the template below, and remove or add any
information as you feel necessary.
--->

This Pull Request is related to the #2058 and the discussion in the discord chat.

It changes the following:

- Adds a `take` method to `JsArrayBuffer`
- Builds out `JsArrayBuffer` docs
- Adds a `JsArrayBuffer::take()` example to `jsarraybuffer.rs` in `boa_examples`
  • Loading branch information
nekevss committed Nov 24, 2022
1 parent 5435ae0 commit 8c88281
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
97 changes: 97 additions & 0 deletions boa_engine/src/object/builtins/jsarraybuffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ pub struct JsArrayBuffer {

impl JsArrayBuffer {
/// Create a new array buffer with byte length.
///
/// ```
/// # use boa_engine::{
/// # object::builtins::JsArrayBuffer,
/// # Context, JsResult
/// # };
/// # fn main() -> JsResult<()> {
/// # // Initialize context
/// # let context = &mut Context::default();
/// // Creates a blank array buffer of n bytes
/// let array_buffer = JsArrayBuffer::new(4, context)?;
///
/// assert_eq!(array_buffer.take()?, vec![0_u8; 4]);
///
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn new(byte_length: usize, context: &mut Context) -> JsResult<Self> {
let inner = ArrayBuffer::allocate(
Expand All @@ -40,6 +57,24 @@ impl JsArrayBuffer {
/// This uses the passed byte block as the internal storage, it does not clone it!
///
/// The `byte_length` will be set to `byte_block.len()`.
///
/// ```
/// # use boa_engine::{
/// # object::builtins::JsArrayBuffer,
/// # Context, JsResult,
/// # };
/// # fn main() -> JsResult<()> {
/// # // Initialize context
/// # let context = &mut Context::default();
///
/// // Create a buffer from a chunk of data
/// let data_block: Vec<u8> = (0..5).collect();
/// let array_buffer = JsArrayBuffer::from_byte_block(data_block, context)?;
///
/// assert_eq!(array_buffer.take()?, (0..5).collect::<Vec<u8>>());
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn from_byte_block(byte_block: Vec<u8>, context: &mut Context) -> JsResult<Self> {
let byte_length = byte_block.len();
Expand Down Expand Up @@ -92,13 +127,75 @@ impl JsArrayBuffer {
}

/// Returns the byte length of the array buffer.
///
/// ```
/// # use boa_engine::{
/// # object::builtins::JsArrayBuffer,
/// # Context, JsResult,
/// # };
/// # fn main() -> JsResult<()> {
/// # // Initialize context
/// # let context = &mut Context::default();
/// // Create a buffer from a chunk of data
/// let data_block: Vec<u8> = (0..5).collect();
/// let array_buffer = JsArrayBuffer::from_byte_block(data_block, context)?;
///
/// // Take the inner buffer
/// let buffer_length = array_buffer.byte_length(context);
///
/// assert_eq!(buffer_length, 5);
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn byte_length(&self, context: &mut Context) -> usize {
ArrayBuffer::get_byte_length(&self.inner.clone().into(), &[], context)
.expect("it should not throw")
.as_number()
.expect("expected a number") as usize
}

/// Take the inner `ArrayBuffer`'s `array_buffer_data` field and replace it with `None`
///
/// Note: This causes the pre-existing `JsArrayBuffer` to become detached.
///
/// ```
/// # use boa_engine::{
/// # object::builtins::JsArrayBuffer,
/// # Context, JsResult,
/// # };
/// # fn main() -> JsResult<()> {
/// # // Initialize context
/// # let context = &mut Context::default();
/// // Create a buffer from a chunk of data
/// let data_block: Vec<u8> = (0..5).collect();
/// let array_buffer = JsArrayBuffer::from_byte_block(data_block, context)?;
///
/// // Take the inner buffer
/// let internal_buffer = array_buffer.take()?;
///
/// assert_eq!(internal_buffer, (0..5).collect::<Vec<u8>>());
///
/// // Anymore interaction with the buffer will return an error
/// let detached_err = array_buffer.take();
/// assert!(detached_err.is_err());
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn take(&self) -> JsResult<Vec<u8>> {
self.inner
.borrow_mut()
.as_array_buffer_mut()
.expect("inner must be an ArrayBuffer")
.array_buffer_data
.take()
.ok_or_else(|| {
JsNativeError::typ()
.with_message("ArrayBuffer is detached")
.into()
})
}
}

impl From<JsArrayBuffer> for JsObject {
Expand Down
10 changes: 10 additions & 0 deletions boa_examples/src/bin/jsarraybuffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,15 @@ fn main() -> JsResult<()> {
Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE,
);

// We can also take the inner data from a JsArrayBuffer
let data_block: Vec<u8> = (0..5).collect();
let array_buffer = JsArrayBuffer::from_byte_block(data_block, context)?;

let internal_buffer = array_buffer.take()?;

assert_eq!(internal_buffer, (0..5).collect::<Vec<u8>>());
let detached_err = array_buffer.take();
assert!(detached_err.is_err());

Ok(())
}

0 comments on commit 8c88281

Please sign in to comment.