2022-09-21 19:27:13 -03:00
/*
* Copyright ( c ) 2022 , Linus Groh < linusg @ serenityos . org >
2023-03-28 21:43:34 -03:00
* Copyright ( c ) 2023 , Matthew Olsson < mattco @ serenityos . org >
2025-01-17 08:43:11 -03:00
* Copyright ( c ) 2023 - 2025 , Shannon Booth < shannon @ serenityos . org >
2024-04-06 13:56:42 -03:00
* Copyright ( c ) 2023 - 2024 , Kenneth Myhra < kennethmyhra @ serenityos . org >
2025-04-17 16:47:53 -03:00
* Copyright ( c ) 2025 , Tim Flynn < trflynn89 @ ladybird . org >
2022-09-21 19:27:13 -03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2023-06-12 16:26:59 -03:00
# include <LibJS/Runtime/ArrayBuffer.h>
2023-11-18 20:31:20 -03:00
# include <LibJS/Runtime/TypedArray.h>
2024-01-28 12:22:52 -03:00
# include <LibWeb/HTML/StructuredSerialize.h>
2022-09-21 19:27:13 -03:00
# include <LibWeb/Streams/AbstractOperations.h>
2023-06-18 06:45:39 -03:00
# include <LibWeb/Streams/QueuingStrategy.h>
2023-03-28 23:11:22 -03:00
# include <LibWeb/WebIDL/AbstractOperations.h>
2023-11-23 05:48:28 -03:00
# include <LibWeb/WebIDL/Buffers.h>
2022-09-21 19:27:13 -03:00
namespace Web : : Streams {
2025-04-17 16:47:53 -03: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 11:08:46 -03:00
{
2025-04-17 16:47:53 -03:00
// 1. If strategy["highWaterMark"] does not exist, return defaultHWM.
if ( ! strategy . high_water_mark . has_value ( ) )
return default_hwm ;
2024-01-27 11:08:46 -03:00
2025-04-17 16:47:53 -03:00
// 2. Let highWaterMark be strategy["highWaterMark"].
auto high_water_mark = strategy . high_water_mark . value ( ) ;
2024-01-27 11:08:46 -03:00
2025-04-17 16:47:53 -03: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 11:08:46 -03:00
2025-04-17 16:47:53 -03:00
// 4. Return highWaterMark.
return high_water_mark ;
2024-01-27 11:08:46 -03:00
}
2025-04-17 21:09:43 -03: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-12 16:26:59 -03:00
{
2025-04-17 21:09:43 -03: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-12 16:26:59 -03:00
2025-04-17 21:09:43 -03: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-12 16:26:59 -03:00
2025-04-17 21:09:43 -03: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-12 16:26:59 -03:00
2025-04-17 21:09:43 -03:00
// 3. If ! IsDetachedBuffer(O) is true, return false.
if ( array_buffer . is_detached ( ) )
return false ;
2023-06-12 16:26:59 -03:00
2025-04-17 21:09:43 -03: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-12 16:26:59 -03:00
}
2023-04-09 19:21:54 -03:00
// https://streams.spec.whatwg.org/#is-non-negative-number
bool is_non_negative_number ( JS : : Value value )
{
2024-10-31 08:34:22 -03:00
// 1. If v is not a Number, return false.
2023-04-09 19:21:54 -03: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 21:09:43 -03: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 17:36:06 -03:00
{
2025-04-17 21:09:43 -03:00
auto & vm = realm . vm ( ) ;
2024-12-01 17:36:06 -03:00
2025-04-17 21:09:43 -03:00
// 1. Assert: ! IsDetachedBuffer(O) is false.
VERIFY ( ! buffer . is_detached ( ) ) ;
2023-12-02 04:28:17 -03:00
2025-04-17 21:09:43 -03:00
// 2. Let arrayBufferData be O.[[ArrayBufferData]].
// 3. Let arrayBufferByteLength be O.[[ArrayBufferByteLength]].
auto array_buffer = buffer . buffer ( ) ;
2023-12-02 04:28:17 -03:00
2025-04-17 21:09:43 -03:00
// 4. Perform ? DetachArrayBuffer(O).
TRY ( JS : : detach_array_buffer ( vm , buffer ) ) ;
2023-12-02 04:28:17 -03:00
2025-04-17 21:09:43 -03: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 04:28:17 -03:00
}
2024-01-28 14:20:55 -03: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 08:34:22 -03:00
// 1. Assert: O is an Object.
2024-01-28 14:20:55 -03: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 12:22:52 -03: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 03:24:57 -03:00
return TRY ( HTML : : structured_deserialize ( vm , serialized , realm ) ) ;
2024-01-28 12:22:52 -03:00
}
2025-04-17 21:09:43 -03: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 19:27:13 -03:00
}