Skip to content

Commit

Permalink
Allow resizing of underlying ArrayBuffer from Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
hansl committed Dec 11, 2024
1 parent 67f6d56 commit c96c8fb
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 2 deletions.
35 changes: 33 additions & 2 deletions core/engine/src/builtins/array_buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,11 @@ impl ArrayBuffer {
self.data.as_mut()
}

/// Sets the maximum byte length of the buffer, returning the previous value if present.
pub(crate) fn set_max_byte_length(&mut self, max_byte_len: u64) -> Option<u64> {
self.max_byte_len.replace(max_byte_len)
}

/// Gets the inner bytes of the buffer without accessing the current atomic length.
#[track_caller]
pub(crate) fn bytes_with_len(&self, len: usize) -> Option<&[u8]> {
Expand All @@ -252,6 +257,32 @@ impl ArrayBuffer {
}
}

/// Resizes the buffer to the new size, clamped to the maximum byte length if present.
pub fn resize(&mut self, new_byte_length: u64) -> JsResult<()> {
let Some(max_byte_len) = self.max_byte_len else {
return Err(JsNativeError::typ()
.with_message("ArrayBuffer.resize: cannot resize a fixed-length buffer")
.into());
};

let Some(buf) = self.vec_mut() else {
return Err(JsNativeError::typ()
.with_message("ArrayBuffer.resize: cannot resize a detached buffer")
.into());
};

if new_byte_length > max_byte_len {
return Err(JsNativeError::range()
.with_message(
"ArrayBuffer.resize: new byte length exceeds buffer's maximum byte length",
)
.into());
}

buf.resize(new_byte_length as usize, 0);
Ok(())
}

/// Detaches the inner data of this `ArrayBuffer`, returning the original buffer if still
/// present.
///
Expand Down Expand Up @@ -338,7 +369,7 @@ impl IntrinsicObject for ArrayBuffer {
None,
flag_attributes,
)
.method(Self::resize, js_string!("resize"), 1)
.method(Self::js_resize, js_string!("resize"), 1)
.method(Self::slice, js_string!("slice"), 2)
.property(
JsSymbol::to_string_tag(),
Expand Down Expand Up @@ -554,7 +585,7 @@ impl ArrayBuffer {
/// [`ArrayBuffer.prototype.resize ( newLength )`][spec].
///
/// [spec]: https://tc39.es/ecma262/#sec-arraybuffer.prototype.resize
pub(crate) fn resize(
pub(crate) fn js_resize(
this: &JsValue,
args: &[JsValue],
context: &mut Context,
Expand Down
17 changes: 17 additions & 0 deletions core/engine/src/builtins/array_buffer/tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::object::JsArrayBuffer;
use crate::Context;

#[test]
Expand All @@ -19,3 +20,19 @@ fn create_shared_byte_data_block() {
// Rainy day
assert!(super::shared::create_shared_byte_data_block(u64::MAX, context).is_err());
}

#[test]
fn resize() {
let context = &mut Context::default();
let data_block = super::create_byte_data_block(100, None, context).unwrap();
let js_arr = JsArrayBuffer::from_byte_block(data_block, context)
.unwrap()
.with_max_byte_length(100);
let mut arr = js_arr.borrow_mut();

// Sunny day
assert_eq!(arr.data_mut().resize(50), Ok(()));

// Rainy day
assert!(arr.data_mut().resize(u64::MAX).is_err());
}
11 changes: 11 additions & 0 deletions core/engine/src/object/builtins/jsarraybuffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,17 @@ impl JsArrayBuffer {
Ok(Self { inner: obj })
}

/// Set a maximum length for the underlying array buffer.
#[inline]
#[must_use]
pub fn with_max_byte_length(self, max_byte_len: u64) -> Self {
self.inner
.borrow_mut()
.data
.set_max_byte_length(max_byte_len);
self
}

/// Create a [`JsArrayBuffer`] from a [`JsObject`], if the object is not an array buffer throw a `TypeError`.
///
/// This does not clone the fields of the array buffer, it only does a shallow clone of the object.
Expand Down

0 comments on commit c96c8fb

Please sign in to comment.