2022-09-21 23:27:13 +01:00
/*
* Copyright ( c ) 2022 , Linus Groh < linusg @ serenityos . org >
2023-03-28 17:43:34 -07:00
* Copyright ( c ) 2023 , Matthew Olsson < mattco @ serenityos . org >
2025-01-18 00:43:11 +13:00
* Copyright ( c ) 2023 - 2025 , Shannon Booth < shannon @ serenityos . org >
2024-04-06 18:56:42 +02:00
* Copyright ( c ) 2023 - 2024 , Kenneth Myhra < kennethmyhra @ serenityos . org >
2025-04-17 15:47:53 -04:00
* Copyright ( c ) 2025 , Tim Flynn < trflynn89 @ ladybird . org >
2022-09-21 23:27:13 +01:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2023-06-13 07:26:59 +12:00
# include <LibJS/Runtime/ArrayBuffer.h>
2023-11-19 12:31:20 +13:00
# include <LibJS/Runtime/TypedArray.h>
2024-01-28 10:22:52 -05:00
# include <LibWeb/HTML/StructuredSerialize.h>
2022-09-21 23:27:13 +01:00
# include <LibWeb/Streams/AbstractOperations.h>
2023-06-18 21:45:39 +12:00
# include <LibWeb/Streams/QueuingStrategy.h>
2023-03-28 19:11:22 -07:00
# include <LibWeb/WebIDL/AbstractOperations.h>
2023-11-23 21:48:28 +13:00
# include <LibWeb/WebIDL/Buffers.h>
2022-09-21 23:27:13 +01:00
namespace Web : : Streams {
2025-04-17 15:47:53 -04:00
// https://streams.spec.whatwg.org/#validate-and-normalize-high-water-mark
WebIDL : : ExceptionOr < double > extract_high_water_mark ( QueuingStrategy const & strategy , double default_hwm )
2024-01-27 09:08:46 -05:00
{
2025-04-17 15:47:53 -04:00
// 1. If strategy["highWaterMark"] does not exist, return defaultHWM.
if ( ! strategy . high_water_mark . has_value ( ) )
return default_hwm ;
2024-01-27 09:08:46 -05:00
2025-04-17 15:47:53 -04:00
// 2. Let highWaterMark be strategy["highWaterMark"].
auto high_water_mark = strategy . high_water_mark . value ( ) ;
2024-01-27 09:08:46 -05:00
2025-04-17 15:47:53 -04:00
// 3. If highWaterMark is NaN or highWaterMark < 0, throw a RangeError exception.
if ( isnan ( high_water_mark ) | | high_water_mark < 0 )
return WebIDL : : SimpleException { WebIDL : : SimpleExceptionType : : RangeError , " Invalid value for high water mark " sv } ;
2024-01-27 09:08:46 -05:00
2025-04-17 15:47:53 -04:00
// 4. Return highWaterMark.
return high_water_mark ;
2024-01-27 09:08:46 -05:00
}
2025-04-17 20:09:43 -04:00
// https://streams.spec.whatwg.org/#make-size-algorithm-from-size-function
GC : : Ref < SizeAlgorithm > extract_size_algorithm ( JS : : VM & vm , QueuingStrategy const & strategy )
2023-06-13 07:26:59 +12:00
{
2025-04-17 20:09:43 -04:00
// 1. If strategy["size"] does not exist, return an algorithm that returns 1.
if ( ! strategy . size )
return GC : : create_function ( vm . heap ( ) , [ ] ( JS : : Value ) { return JS : : normal_completion ( JS : : Value ( 1 ) ) ; } ) ;
2023-06-13 07:26:59 +12:00
2025-04-17 20:09:43 -04:00
// 2. Return an algorithm that performs the following steps, taking a chunk argument:
return GC : : create_function ( vm . heap ( ) , [ size = strategy . size ] ( JS : : Value chunk ) {
// 1. Return the result of invoking strategy["size"] with argument list « chunk ».
return WebIDL : : invoke_callback ( * size , { } , { { chunk } } ) ;
} ) ;
}
2023-06-13 07:26:59 +12:00
2025-04-17 20:09:43 -04:00
// https://streams.spec.whatwg.org/#can-transfer-array-buffer
bool can_transfer_array_buffer ( JS : : ArrayBuffer const & array_buffer )
{
// 1. Assert: O is an Object.
// 2. Assert: O has an [[ArrayBufferData]] internal slot.
2023-06-13 07:26:59 +12:00
2025-04-17 20:09:43 -04:00
// 3. If ! IsDetachedBuffer(O) is true, return false.
if ( array_buffer . is_detached ( ) )
return false ;
2023-06-13 07:26:59 +12:00
2025-04-17 20:09:43 -04:00
// 4. If SameValue(O.[[ArrayBufferDetachKey]], undefined) is false, return false.
if ( ! JS : : same_value ( array_buffer . detach_key ( ) , JS : : js_undefined ( ) ) )
return false ;
// 5. Return true.
return true ;
2023-06-13 07:26:59 +12:00
}
2023-04-09 15:21:54 -07:00
// https://streams.spec.whatwg.org/#is-non-negative-number
bool is_non_negative_number ( JS : : Value value )
{
2024-10-31 11:34:22 +00:00
// 1. If v is not a Number, return false.
2023-04-09 15:21:54 -07:00
if ( ! value . is_number ( ) )
return false ;
// 2. If v is NaN, return false.
if ( value . is_nan ( ) )
return false ;
// 3. If v < 0, return false.
if ( value . as_double ( ) < 0.0 )
return false ;
// 4. Return true.
return true ;
}
2025-04-17 20:09:43 -04:00
// https://streams.spec.whatwg.org/#transfer-array-buffer
WebIDL : : ExceptionOr < GC : : Ref < JS : : ArrayBuffer > > transfer_array_buffer ( JS : : Realm & realm , JS : : ArrayBuffer & buffer )
2024-12-01 21:36:06 +01:00
{
2025-04-17 20:09:43 -04:00
auto & vm = realm . vm ( ) ;
2024-12-01 21:36:06 +01:00
2025-04-17 20:09:43 -04:00
// 1. Assert: ! IsDetachedBuffer(O) is false.
VERIFY ( ! buffer . is_detached ( ) ) ;
2023-12-02 20:28:17 +13:00
2025-04-17 20:09:43 -04:00
// 2. Let arrayBufferData be O.[[ArrayBufferData]].
// 3. Let arrayBufferByteLength be O.[[ArrayBufferByteLength]].
auto array_buffer = buffer . buffer ( ) ;
2023-12-02 20:28:17 +13:00
2025-04-17 20:09:43 -04:00
// 4. Perform ? DetachArrayBuffer(O).
TRY ( JS : : detach_array_buffer ( vm , buffer ) ) ;
2023-12-02 20:28:17 +13:00
2025-04-17 20:09:43 -04:00
// 5. Return a new ArrayBuffer object, created in the current Realm, whose [[ArrayBufferData]] internal slot value is arrayBufferData and whose [[ArrayBufferByteLength]] internal slot value is arrayBufferByteLength.
return JS : : ArrayBuffer : : create ( realm , move ( array_buffer ) ) ;
2023-12-02 20:28:17 +13:00
}
2024-01-28 12:20:55 -05:00
// https://streams.spec.whatwg.org/#abstract-opdef-cloneasuint8array
WebIDL : : ExceptionOr < JS : : Value > clone_as_uint8_array ( JS : : Realm & realm , WebIDL : : ArrayBufferView & view )
{
auto & vm = realm . vm ( ) ;
2024-10-31 11:34:22 +00:00
// 1. Assert: O is an Object.
2024-01-28 12:20:55 -05:00
// 2. Assert: O has an [[ViewedArrayBuffer]] internal slot.
// 3. Assert: ! IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is false.
VERIFY ( ! view . viewed_array_buffer ( ) - > is_detached ( ) ) ;
// 4. Let buffer be ? CloneArrayBuffer(O.[[ViewedArrayBuffer]], O.[[ByteOffset]], O.[[ByteLength]], %ArrayBuffer%).
auto * buffer = TRY ( JS : : clone_array_buffer ( vm , * view . viewed_array_buffer ( ) , view . byte_offset ( ) , view . byte_length ( ) ) ) ;
// 5. Let array be ! Construct(%Uint8Array%, « buffer »).
auto array = MUST ( JS : : construct ( vm , * realm . intrinsics ( ) . uint8_array_constructor ( ) , buffer ) ) ;
// 5. Return array.
return array ;
}
2024-01-28 10:22:52 -05:00
// https://streams.spec.whatwg.org/#abstract-opdef-structuredclone
WebIDL : : ExceptionOr < JS : : Value > structured_clone ( JS : : Realm & realm , JS : : Value value )
{
auto & vm = realm . vm ( ) ;
// 1. Let serialized be ? StructuredSerialize(v).
auto serialized = TRY ( HTML : : structured_serialize ( vm , value ) ) ;
// 2. Return ? StructuredDeserialize(serialized, the current Realm).
2024-11-23 19:24:57 +13:00
return TRY ( HTML : : structured_deserialize ( vm , serialized , realm ) ) ;
2024-01-28 10:22:52 -05:00
}
2025-04-17 20:09:43 -04:00
// https://streams.spec.whatwg.org/#abstract-opdef-cancopydatablockbytes
bool can_copy_data_block_bytes_buffer ( JS : : ArrayBuffer const & to_buffer , u64 to_index , JS : : ArrayBuffer const & from_buffer , u64 from_index , u64 count )
{
// 1. Assert: toBuffer is an Object.
// 2. Assert: toBuffer has an [[ArrayBufferData]] internal slot.
// 3. Assert: fromBuffer is an Object.
// 4. Assert: fromBuffer has an [[ArrayBufferData]] internal slot.
// 5. If toBuffer is fromBuffer, return false.
if ( & to_buffer = = & from_buffer )
return false ;
// 6. If ! IsDetachedBuffer(toBuffer) is true, return false.
if ( to_buffer . is_detached ( ) )
return false ;
// 7. If ! IsDetachedBuffer(fromBuffer) is true, return false.
if ( from_buffer . is_detached ( ) )
return false ;
// 8. If toIndex + count > toBuffer.[[ArrayBufferByteLength]], return false.
if ( to_index + count > to_buffer . byte_length ( ) )
return false ;
// 9. If fromIndex + count > fromBuffer.[[ArrayBufferByteLength]], return false.
if ( from_index + count > from_buffer . byte_length ( ) )
return false ;
// 10. Return true.
return true ;
}
2022-09-21 23:27:13 +01:00
}