-
-
Notifications
You must be signed in to change notification settings - Fork 411
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Added example `jsarraybuffer.rs`
- Loading branch information
Showing
5 changed files
with
209 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
use crate::{ | ||
builtins::array_buffer::ArrayBuffer, | ||
context::intrinsics::StandardConstructors, | ||
object::{ | ||
internal_methods::get_prototype_from_constructor, JsObject, JsObjectType, ObjectData, | ||
}, | ||
Context, JsResult, JsValue, | ||
}; | ||
use boa_gc::{Finalize, Trace}; | ||
use std::ops::Deref; | ||
|
||
/// JavaScript `ArrayBuffer` rust object. | ||
#[derive(Debug, Clone, Trace, Finalize)] | ||
pub struct JsArrayBuffer { | ||
inner: JsObject, | ||
} | ||
|
||
impl JsArrayBuffer { | ||
/// Create a new array buffer with byte length. | ||
#[inline] | ||
pub fn new(byte_length: usize, context: &mut Context) -> JsResult<Self> { | ||
let inner = ArrayBuffer::allocate( | ||
&context | ||
.intrinsics() | ||
.constructors() | ||
.array_buffer() | ||
.constructor() | ||
.into(), | ||
byte_length, | ||
context, | ||
)?; | ||
|
||
Ok(Self { inner }) | ||
} | ||
|
||
/// Create a new array buffer from byte block. | ||
/// | ||
/// 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()`. | ||
#[inline] | ||
pub fn from_byte_block(byte_block: Vec<u8>, context: &mut Context) -> JsResult<Self> { | ||
let byte_length = byte_block.len(); | ||
|
||
let constructor = context | ||
.intrinsics() | ||
.constructors() | ||
.array_buffer() | ||
.constructor() | ||
.into(); | ||
|
||
// 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBuffer.prototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] »). | ||
let prototype = get_prototype_from_constructor( | ||
&constructor, | ||
StandardConstructors::array_buffer, | ||
context, | ||
)?; | ||
let obj = context.construct_object(); | ||
obj.set_prototype(prototype.into()); | ||
|
||
// 2. Let block be ? CreateByteDataBlock(byteLength). | ||
// | ||
// NOTE: We skip step 2. because we already have the block | ||
// that is passed to us as a function argument. | ||
let block = byte_block; | ||
|
||
// 3. Set obj.[[ArrayBufferData]] to block. | ||
// 4. Set obj.[[ArrayBufferByteLength]] to byteLength. | ||
obj.borrow_mut().data = ObjectData::array_buffer(ArrayBuffer { | ||
array_buffer_data: Some(block), | ||
array_buffer_byte_length: byte_length, | ||
array_buffer_detach_key: JsValue::Undefined, | ||
}); | ||
|
||
Ok(Self { inner: obj }) | ||
} | ||
|
||
/// 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. | ||
#[inline] | ||
pub fn from_object(object: JsObject, context: &mut Context) -> JsResult<Self> { | ||
if object.borrow().is_array_buffer() { | ||
Ok(Self { inner: object }) | ||
} else { | ||
context.throw_type_error("object is not an ArrayBuffer") | ||
} | ||
} | ||
|
||
/// Returns the byte length of the array buffer. | ||
#[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 | ||
} | ||
} | ||
|
||
impl From<JsArrayBuffer> for JsObject { | ||
#[inline] | ||
fn from(o: JsArrayBuffer) -> Self { | ||
o.inner.clone() | ||
} | ||
} | ||
|
||
impl From<JsArrayBuffer> for JsValue { | ||
#[inline] | ||
fn from(o: JsArrayBuffer) -> Self { | ||
o.inner.clone().into() | ||
} | ||
} | ||
|
||
impl Deref for JsArrayBuffer { | ||
type Target = JsObject; | ||
|
||
#[inline] | ||
fn deref(&self) -> &Self::Target { | ||
&self.inner | ||
} | ||
} | ||
|
||
impl JsObjectType for JsArrayBuffer {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// This example shows how to manipulate a Javascript array using Rust code. | ||
|
||
use boa_engine::{ | ||
object::{JsArrayBuffer, JsUint32Array, JsUint8Array}, | ||
property::Attribute, | ||
Context, JsResult, JsValue, | ||
}; | ||
|
||
fn main() -> JsResult<()> { | ||
// We create a new `Context` to create a new Javascript executor. | ||
let context = &mut Context::default(); | ||
|
||
// This create an array buffer of byte length 4 | ||
let array_buffer = JsArrayBuffer::new(4, context)?; | ||
|
||
// We can now create an typed array to access the data. | ||
let uint32_typed_array = JsUint32Array::from_array_buffer(array_buffer, context)?; | ||
|
||
let value = 0x12345678u32; | ||
uint32_typed_array.set(0, value, true, context)?; | ||
|
||
assert_eq!(uint32_typed_array.get(0, context)?, JsValue::new(value)); | ||
|
||
// We can also create array buffers from a user defined block of data. | ||
// | ||
// NOTE: The block data will not be cloned. | ||
let blob_of_data: Vec<u8> = (0..=255).collect(); | ||
let array_buffer = JsArrayBuffer::from_byte_block(blob_of_data, context)?; | ||
|
||
// This the byte length of the new array buffer will be the length of block of data. | ||
let byte_length = array_buffer.byte_length(context); | ||
assert_eq!(byte_length, 256); | ||
|
||
// We can now create an typed array to access the data. | ||
let uint8_typed_array = JsUint8Array::from_array_buffer(array_buffer.clone(), context)?; | ||
|
||
for i in 0..byte_length { | ||
assert_eq!(uint8_typed_array.get(i, context)?, JsValue::new(i)); | ||
} | ||
|
||
// We can also register it as a global property | ||
context.register_global_property( | ||
"myArrayBuffer", | ||
array_buffer, | ||
Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE, | ||
); | ||
|
||
Ok(()) | ||
} |