diff options
author | Taym Haddadi <haddadi.taym@gmail.com> | 2025-01-27 16:52:54 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-27 15:52:54 +0000 |
commit | 9943e9772640073032a8828cef032a19730a369b (patch) | |
tree | 534e22f50a203ac9b491ff12bbc648982c1a7762 /components/script/dom/bindings/buffer_source.rs | |
parent | 177b5b2ceff86b89d87c4536ac4e33e382ffcc11 (diff) | |
download | servo-9943e9772640073032a8828cef032a19730a369b.tar.gz servo-9943e9772640073032a8828cef032a19730a369b.zip |
Script: implement `ReadableStreamBYOBReader::Read` (#35040)
* Script: implement ReadableStreamBYOBReader::Read
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
* fix ReadRequest::close_steps
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
* fix clippy
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
* implement viewed_buffer_array_byte_length and byte_length
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
* fix clippy
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
* Correct BufferSource implemntation
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
* Correct detach_buffer implemantation
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
* fix JS_IsArrayBufferViewObject usage
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
* Reduce BufferSource to two variants ArrayBuffer and ArrayBufferView
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
* Add more doc and use promise.reject_error
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
---------
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
Diffstat (limited to 'components/script/dom/bindings/buffer_source.rs')
-rw-r--r-- | components/script/dom/bindings/buffer_source.rs | 365 |
1 files changed, 165 insertions, 200 deletions
diff --git a/components/script/dom/bindings/buffer_source.rs b/components/script/dom/bindings/buffer_source.rs index 3e095a1e617..299b46a3c85 100644 --- a/components/script/dom/bindings/buffer_source.rs +++ b/components/script/dom/bindings/buffer_source.rs @@ -11,7 +11,9 @@ use std::ptr; use std::sync::Arc; use js::jsapi::{ - Heap, JSObject, JS_GetArrayBufferViewBuffer, JS_IsArrayBufferViewObject, NewExternalArrayBuffer, + GetArrayBufferByteLength, Heap, IsDetachedArrayBufferObject, JSObject, + JS_GetArrayBufferViewBuffer, JS_GetArrayBufferViewByteLength, JS_IsArrayBufferViewObject, + JS_IsTypedArrayObject, NewExternalArrayBuffer, }; use js::rust::wrappers::DetachArrayBuffer; use js::rust::{CustomAutoRooterGuard, Handle, MutableHandleObject}; @@ -23,52 +25,24 @@ use js::typedarray::{ use crate::dom::globalscope::GlobalScope; use crate::script_runtime::JSContext; -/// <https://webidl.spec.whatwg.org/#BufferSource> -#[allow(dead_code)] +// Represents a `BufferSource` as defined in the WebIDL specification. +/// +/// A `BufferSource` is either an `ArrayBuffer` or an `ArrayBufferView`, which +/// provides a view onto an `ArrayBuffer`. +/// +/// See: <https://webidl.spec.whatwg.org/#BufferSource> pub(crate) enum BufferSource { - Int8Array(Box<Heap<*mut JSObject>>), - Int16Array(Box<Heap<*mut JSObject>>), - Int32Array(Box<Heap<*mut JSObject>>), - Uint8Array(Box<Heap<*mut JSObject>>), - Uint16Array(Box<Heap<*mut JSObject>>), - Uint32Array(Box<Heap<*mut JSObject>>), - Uint8ClampedArray(Box<Heap<*mut JSObject>>), - BigInt64Array(Box<Heap<*mut JSObject>>), - BigUint64Array(Box<Heap<*mut JSObject>>), - Float32Array(Box<Heap<*mut JSObject>>), - Float64Array(Box<Heap<*mut JSObject>>), - DataView(Box<Heap<*mut JSObject>>), - ArrayBuffer(Box<Heap<*mut JSObject>>), - Default(Box<Heap<*mut JSObject>>), -} + /// Represents an `ArrayBufferView` (e.g., `Uint8Array`, `DataView`). + /// See: <https://webidl.spec.whatwg.org/#ArrayBufferView> + ArrayBufferView(Box<Heap<*mut JSObject>>), -pub(crate) struct HeapBufferSource<T> { - buffer_source: BufferSource, - phantom: PhantomData<T>, -} + /// Represents an `ArrayBuffer`, a fixed-length binary data buffer. + /// See: <https://webidl.spec.whatwg.org/#idl-ArrayBuffer> + #[allow(dead_code)] + ArrayBuffer(Box<Heap<*mut JSObject>>), -unsafe impl<T> crate::dom::bindings::trace::JSTraceable for HeapBufferSource<T> { - #[inline] - unsafe fn trace(&self, tracer: *mut js::jsapi::JSTracer) { - match &self.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | - BufferSource::ArrayBuffer(buffer) | - BufferSource::Default(buffer) => { - buffer.trace(tracer); - }, - } - } + /// Default variant, used as a placeholder in initialization. + Default(Box<Heap<*mut JSObject>>), } pub(crate) fn new_initialized_heap_buffer_source<T>( @@ -93,18 +67,7 @@ where let heap_buffer_source = HeapBufferSource::<T>::default(); match &heap_buffer_source.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | + BufferSource::ArrayBufferView(buffer) | BufferSource::ArrayBuffer(buffer) | BufferSource::Default(buffer) => { buffer.set(*array); @@ -121,11 +84,22 @@ pub(crate) enum HeapTypedArrayInit { Info { len: u32, cx: JSContext }, } +pub(crate) struct HeapBufferSource<T> { + buffer_source: BufferSource, + phantom: PhantomData<T>, +} + impl<T> HeapBufferSource<T> where - T: TypedArrayElement + TypedArrayElementCreator, - T::Element: Clone + Copy, + T: TypedArrayElement, { + pub(crate) fn new(buffer_source: BufferSource) -> HeapBufferSource<T> { + HeapBufferSource { + buffer_source, + phantom: PhantomData, + } + } + pub(crate) fn default() -> HeapBufferSource<T> { HeapBufferSource { buffer_source: BufferSource::Default(Box::default()), @@ -133,47 +107,128 @@ where } } - pub(crate) fn set_data(&self, cx: JSContext, data: &[T::Element]) -> Result<(), ()> { - rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>()); - let _: TypedArray<T, *mut JSObject> = create_buffer_source(cx, data, array.handle_mut())?; - + pub(crate) fn is_initialized(&self) -> bool { match &self.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | + BufferSource::ArrayBufferView(buffer) | BufferSource::ArrayBuffer(buffer) | - BufferSource::Default(buffer) => { - buffer.set(*array); + BufferSource::Default(buffer) => !buffer.get().is_null(), + } + } + + pub(crate) fn get_buffer(&self) -> Result<TypedArray<T, *mut JSObject>, ()> { + TypedArray::from(match &self.buffer_source { + BufferSource::ArrayBufferView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => buffer.get(), + }) + } + + /// <https://tc39.es/ecma262/#sec-detacharraybuffer> + pub(crate) fn detach_buffer(&self, cx: JSContext) -> bool { + assert!(self.is_initialized()); + match &self.buffer_source { + BufferSource::ArrayBufferView(buffer) | BufferSource::Default(buffer) => { + let mut is_shared = false; + unsafe { + // assert buffer is an ArrayBuffer view + assert!(JS_IsArrayBufferViewObject(*buffer.handle())); + rooted!(in (*cx) let view_buffer = + JS_GetArrayBufferViewBuffer(*cx, buffer.handle(), &mut is_shared)); + // This buffer is always created unshared + debug_assert!(!is_shared); + // Detach the ArrayBuffer + DetachArrayBuffer(*cx, view_buffer.handle()) + } + }, + BufferSource::ArrayBuffer(buffer) => unsafe { + DetachArrayBuffer(*cx, Handle::from_raw(buffer.handle())) }, } - Ok(()) } + pub(crate) fn buffer_to_option(&self) -> Option<TypedArray<T, *mut JSObject>> { + if self.is_initialized() { + self.get_buffer().ok() + } else { + warn!("Buffer not initialized."); + None + } + } + + pub(crate) fn is_detached_buffer(&self, cx: JSContext) -> bool { + assert!(self.is_initialized()); + match &self.buffer_source { + BufferSource::ArrayBufferView(buffer) | BufferSource::Default(buffer) => { + let mut is_shared = false; + unsafe { + assert!(JS_IsArrayBufferViewObject(*buffer.handle())); + rooted!(in (*cx) let view_buffer = + JS_GetArrayBufferViewBuffer(*cx, buffer.handle(), &mut is_shared)); + debug_assert!(!is_shared); + IsDetachedArrayBufferObject(*view_buffer.handle()) + } + }, + BufferSource::ArrayBuffer(buffer) => unsafe { + IsDetachedArrayBufferObject(*buffer.handle()) + }, + } + } + + pub(crate) fn viewed_buffer_array_byte_length(&self, cx: JSContext) -> usize { + assert!(self.is_initialized()); + match &self.buffer_source { + BufferSource::ArrayBufferView(buffer) | BufferSource::Default(buffer) => { + let mut is_shared = false; + unsafe { + assert!(JS_IsArrayBufferViewObject(*buffer.handle())); + rooted!(in (*cx) let view_buffer = + JS_GetArrayBufferViewBuffer(*cx, buffer.handle(), &mut is_shared)); + debug_assert!(!is_shared); + GetArrayBufferByteLength(*view_buffer.handle()) + } + }, + BufferSource::ArrayBuffer(buffer) => unsafe { + GetArrayBufferByteLength(*buffer.handle()) + }, + } + } + + pub(crate) fn byte_length(&self) -> usize { + match &self.buffer_source { + BufferSource::ArrayBufferView(buffer) | BufferSource::Default(buffer) => unsafe { + JS_GetArrayBufferViewByteLength(*buffer.handle()) + }, + BufferSource::ArrayBuffer(buffer) => unsafe { + GetArrayBufferByteLength(*buffer.handle()) + }, + } + } + + pub(crate) fn array_length(&self) -> usize { + self.get_buffer().unwrap().len() + } + + /// <https://tc39.es/ecma262/#typedarray> + pub(crate) fn has_typed_array_name(&self) -> bool { + match &self.buffer_source { + BufferSource::ArrayBufferView(buffer) | BufferSource::Default(buffer) => unsafe { + JS_IsTypedArrayObject(*buffer.handle()) + }, + BufferSource::ArrayBuffer(_) => false, + } + } +} + +impl<T> HeapBufferSource<T> +where + T: TypedArrayElement + TypedArrayElementCreator, + T::Element: Clone + Copy, +{ pub(crate) fn acquire_data(&self, cx: JSContext) -> Result<Vec<T::Element>, ()> { assert!(self.is_initialized()); typedarray!(in(*cx) let array: TypedArray = match &self.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | + BufferSource::ArrayBufferView(buffer) | BufferSource::ArrayBuffer(buffer) | BufferSource::Default(buffer) => { buffer.get() @@ -190,18 +245,7 @@ where }; match &self.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | + BufferSource::ArrayBufferView(buffer) | BufferSource::ArrayBuffer(buffer) | BufferSource::Default(buffer) => { buffer.set(ptr::null_mut()); @@ -210,43 +254,6 @@ where data } - /// <https://tc39.es/ecma262/#sec-detacharraybuffer> - pub(crate) fn detach_buffer(&self, cx: JSContext) -> bool { - match &self.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | - BufferSource::ArrayBuffer(buffer) | - BufferSource::Default(buffer) => { - assert!(self.is_initialized()); - let mut is_shared = false; - unsafe { - if JS_IsArrayBufferViewObject(*buffer.handle()) { - // If it is an ArrayBuffer view, get the buffer using JS_GetArrayBufferViewBuffer - rooted!(in (*cx) let view_buffer = - JS_GetArrayBufferViewBuffer(*cx, buffer.handle(), &mut is_shared)); - // This buffer is always created unshared - debug_assert!(!is_shared); - // Detach the ArrayBuffer - DetachArrayBuffer(*cx, view_buffer.handle()) - } else { - // If it's not an ArrayBuffer view, Detach the buffer directly - DetachArrayBuffer(*cx, Handle::from_raw(buffer.handle())) - } - } - }, - } - } - pub(crate) fn copy_data_to( &self, cx: JSContext, @@ -256,18 +263,7 @@ where ) -> Result<(), ()> { assert!(self.is_initialized()); typedarray!(in(*cx) let array: TypedArray = match &self.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | + BufferSource::ArrayBufferView(buffer) | BufferSource::ArrayBuffer(buffer) | BufferSource::Default(buffer) => { buffer.get() @@ -294,18 +290,7 @@ where ) -> Result<(), ()> { assert!(self.is_initialized()); typedarray!(in(*cx) let mut array: TypedArray = match &self.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | + BufferSource::ArrayBufferView(buffer) | BufferSource::ArrayBuffer(buffer) | BufferSource::Default(buffer) => { buffer.get() @@ -324,50 +309,30 @@ where Ok(()) } - pub(crate) fn is_initialized(&self) -> bool { + pub(crate) fn set_data(&self, cx: JSContext, data: &[T::Element]) -> Result<(), ()> { + rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>()); + let _: TypedArray<T, *mut JSObject> = create_buffer_source(cx, data, array.handle_mut())?; + match &self.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | + BufferSource::ArrayBufferView(buffer) | BufferSource::ArrayBuffer(buffer) | - BufferSource::Default(buffer) => !buffer.get().is_null(), + BufferSource::Default(buffer) => { + buffer.set(*array); + }, } + Ok(()) } +} - pub(crate) fn get_buffer(&self) -> Result<TypedArray<T, *mut JSObject>, ()> { - TypedArray::from(match &self.buffer_source { - BufferSource::Int8Array(buffer) | - BufferSource::Int16Array(buffer) | - BufferSource::Int32Array(buffer) | - BufferSource::Uint8Array(buffer) | - BufferSource::Uint16Array(buffer) | - BufferSource::Uint32Array(buffer) | - BufferSource::Uint8ClampedArray(buffer) | - BufferSource::BigInt64Array(buffer) | - BufferSource::BigUint64Array(buffer) | - BufferSource::Float32Array(buffer) | - BufferSource::Float64Array(buffer) | - BufferSource::DataView(buffer) | +unsafe impl<T> crate::dom::bindings::trace::JSTraceable for HeapBufferSource<T> { + #[inline] + unsafe fn trace(&self, tracer: *mut js::jsapi::JSTracer) { + match &self.buffer_source { + BufferSource::ArrayBufferView(buffer) | BufferSource::ArrayBuffer(buffer) | - BufferSource::Default(buffer) => buffer.get(), - }) - } - - pub(crate) fn buffer_to_option(&self) -> Option<TypedArray<T, *mut JSObject>> { - if self.is_initialized() { - Some(self.get_buffer().expect("Failed to get buffer.")) - } else { - warn!("Buffer not initialized."); - None + BufferSource::Default(buffer) => { + buffer.trace(tracer); + }, } } } |