1use std::collections::VecDeque;
2
3use crate::utils::{
4 error_messages::ERROR_MSG_ARRAY_BUFFER_DETACHED,
5 option::{Null, Undefined},
6 primordials::{BasePrimordials, Primordial},
7 result::ResultExt,
8};
9use rquickjs::{
10 class::{OwnedBorrow, OwnedBorrowMut, Trace, Tracer},
11 function::Constructor,
12 methods,
13 prelude::{Opt, This},
14 ArrayBuffer, Class, Ctx, Error, Exception, Function, IntoJs, JsLifetime, Object, Promise,
15 Result, TypedArray, Value,
16};
17
18use crate::stream_web::{
19 readable::{
20 byob_reader::{ArrayConstructorPrimordials, ReadableStreamReadIntoRequest, ViewBytes},
21 controller::{
22 ReadableStreamController, ReadableStreamControllerClass, ReadableStreamControllerOwned,
23 },
24 default_controller::ReadableStreamDefaultControllerOwned,
25 default_reader::ReadableStreamReadRequest,
26 objects::{
27 ReadableByteStreamObjects, ReadableStreamBYOBObjects, ReadableStreamClassObjects,
28 ReadableStreamDefaultReaderObjects, ReadableStreamObjects,
29 },
30 reader::ReadableStreamReader,
31 stream::{
32 algorithms::{CancelAlgorithm, PullAlgorithm, StartAlgorithm},
33 source::UnderlyingSource,
34 ReadableStream, ReadableStreamClass, ReadableStreamOwned, ReadableStreamState,
35 },
36 },
37 utils::{
38 class_from_owned_borrow_mut,
39 promise::{promise_resolved_with, upon_promise},
40 UnwrapOrUndefined,
41 },
42};
43
44#[derive(JsLifetime)]
45#[rquickjs::class]
46pub struct ReadableByteStreamController<'js> {
47 auto_allocate_chunk_size: Option<usize>,
48 byob_request: Option<Class<'js, ReadableStreamBYOBRequest<'js>>>,
49 cancel_algorithm: Option<CancelAlgorithm<'js>>,
50 close_requested: bool,
51 pull_again: bool,
52 pull_algorithm: Option<PullAlgorithm<'js>>,
53 pulling: bool,
54 pub(super) pending_pull_intos: VecDeque<PullIntoDescriptor<'js>>,
55 queue: VecDeque<ReadableByteStreamQueueEntry<'js>>,
56 queue_total_size: usize,
57 started: bool,
58 strategy_hwm: f64,
59 pub(super) stream: ReadableStreamClass<'js>,
60
61 pub(super) array_constructor_primordials: ArrayConstructorPrimordials<'js>,
62 constructor_array_buffer: Constructor<'js>,
63 pub(super) function_array_buffer_is_view: Function<'js>,
64}
65
66impl<'js> Trace<'js> for ReadableByteStreamController<'js> {
67 fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {
68 self.auto_allocate_chunk_size.trace(tracer);
69 self.byob_request.trace(tracer);
70 self.cancel_algorithm.trace(tracer);
71 self.pull_algorithm.trace(tracer);
72 self.pending_pull_intos.trace(tracer);
73 self.queue.trace(tracer);
74 self.queue_total_size.trace(tracer);
75 self.started.trace(tracer);
76 self.strategy_hwm.trace(tracer);
77 self.stream.trace(tracer);
78 self.array_constructor_primordials.trace(tracer);
79 self.constructor_array_buffer.trace(tracer);
80 self.function_array_buffer_is_view.trace(tracer);
81 }
82}
83
84pub type ReadableByteStreamControllerClass<'js> = Class<'js, ReadableByteStreamController<'js>>;
85pub(crate) type ReadableByteStreamControllerOwned<'js> =
86 OwnedBorrowMut<'js, ReadableByteStreamController<'js>>;
87
88impl<'js> ReadableByteStreamController<'js> {
89 pub(super) fn set_up_readable_byte_stream_controller_from_underlying_source(
91 ctx: &Ctx<'js>,
92 stream: ReadableStreamOwned<'js>,
93 underlying_source: Null<Undefined<Object<'js>>>,
94 underlying_source_dict: UnderlyingSource<'js>,
95 high_water_mark: f64,
96 ) -> Result<()> {
97 let (start_algorithm, pull_algorithm, cancel_algorithm, auto_allocate_chunk_size) = (
98 underlying_source_dict
101 .start
102 .map(|f| StartAlgorithm::Function {
103 f,
104 underlying_source: underlying_source.clone(),
105 })
106 .unwrap_or(StartAlgorithm::ReturnUndefined),
107 underlying_source_dict
110 .pull
111 .map(|f| PullAlgorithm::Function {
112 f,
113 underlying_source: underlying_source.clone(),
114 })
115 .unwrap_or(PullAlgorithm::ReturnPromiseUndefined),
116 underlying_source_dict
119 .cancel
120 .map(|f| CancelAlgorithm::Function {
121 f,
122 underlying_source,
123 })
124 .unwrap_or(CancelAlgorithm::ReturnPromiseUndefined),
125 underlying_source_dict.auto_allocate_chunk_size,
127 );
128
129 if auto_allocate_chunk_size == Some(0) {
131 return Err(Exception::throw_type(
132 ctx,
133 "autoAllocateChunkSize must be greater than 0",
134 ));
135 }
136
137 Self::set_up_readable_byte_stream_controller(
138 ctx.clone(),
139 stream,
140 start_algorithm,
141 pull_algorithm,
142 cancel_algorithm,
143 high_water_mark,
144 auto_allocate_chunk_size,
145 )?;
146
147 Ok(())
148 }
149
150 pub(super) fn set_up_readable_byte_stream_controller(
151 ctx: Ctx<'js>,
152 stream: ReadableStreamOwned<'js>,
153 start_algorithm: StartAlgorithm<'js>,
154 pull_algorithm: PullAlgorithm<'js>,
155 cancel_algorithm: CancelAlgorithm<'js>,
156 high_water_mark: f64,
157 auto_allocate_chunk_size: Option<usize>,
158 ) -> Result<Class<'js, Self>> {
159 let (stream_class, mut stream) = class_from_owned_borrow_mut(stream);
160
161 let array_constructor_primordials = ArrayConstructorPrimordials::get(&ctx)?.clone();
162 let BasePrimordials {
163 constructor_array_buffer,
164 function_array_buffer_is_view,
165 ..
166 } = &*BasePrimordials::get(&ctx)?;
167
168 let controller = Self {
169 stream: stream_class,
171
172 pull_again: false,
174 pulling: false,
175
176 byob_request: None,
178
179 queue: VecDeque::new(),
181 queue_total_size: 0,
182
183 close_requested: false,
185 started: false,
186
187 strategy_hwm: high_water_mark,
189
190 pull_algorithm: Some(pull_algorithm),
192 cancel_algorithm: Some(cancel_algorithm),
193
194 auto_allocate_chunk_size,
196
197 pending_pull_intos: VecDeque::new(),
198
199 array_constructor_primordials,
200 constructor_array_buffer: constructor_array_buffer.clone(),
201 function_array_buffer_is_view: function_array_buffer_is_view.clone(),
202 };
203
204 let controller_class = Class::instance(ctx.clone(), controller)?;
205
206 stream.controller =
208 ReadableStreamControllerClass::ReadableStreamByteController(controller_class.clone());
209
210 let objects =
211 ReadableStreamObjects::new_byte(stream, OwnedBorrowMut::from_class(controller_class))
212 .refresh_reader();
213
214 let promise_primordials = objects.stream.promise_primordials.clone();
215
216 let (start_result, objects_class) =
218 Self::start_algorithm(ctx.clone(), objects, start_algorithm)?;
219
220 let start_promise = promise_resolved_with(&ctx, &promise_primordials, Ok(start_result))?;
222
223 let _ = upon_promise::<Value<'js>, _>(ctx.clone(), start_promise, {
224 let objects_class = objects_class.clone();
225 move |ctx, result| {
226 let mut objects =
227 ReadableStreamObjects::from_class_no_reader(objects_class).refresh_reader();
228 match result {
229 Ok(_) => {
231 objects.controller.started = true;
233 Self::readable_byte_stream_controller_call_pull_if_needed(ctx, objects)?;
235 Ok(())
236 },
237 Err(r) => {
239 Self::readable_byte_stream_controller_error(objects, r)?;
241 Ok(())
242 },
243 }
244 }
245 })?;
246
247 Ok(objects_class.controller)
248 }
249
250 fn readable_byte_stream_controller_call_pull_if_needed<R: ReadableStreamReader<'js>>(
251 ctx: Ctx<'js>,
252 objects: ReadableByteStreamObjects<'js, R>,
253 ) -> Result<ReadableByteStreamObjects<'js, R>> {
254 let (should_pull, mut objects) =
256 Self::readable_byte_stream_controller_should_call_pull(objects);
257
258 if !should_pull {
260 return Ok(objects);
261 }
262
263 if objects.controller.pulling {
265 objects.controller.pull_again = true;
267
268 return Ok(objects);
270 }
271
272 objects.controller.pulling = true;
274
275 let (pull_promise, objects_class) = Self::pull_algorithm(ctx.clone(), objects)?;
277
278 upon_promise::<Value<'js>, ()>(ctx, pull_promise, {
279 let objects_class = objects_class.clone();
280 move |ctx, result| {
281 let mut objects =
282 ReadableStreamObjects::from_class_no_reader(objects_class).refresh_reader();
283 match result {
284 Ok(_) => {
286 objects.controller.pulling = false;
288 if objects.controller.pull_again {
290 objects.controller.pull_again = false;
292 Self::readable_byte_stream_controller_call_pull_if_needed(
294 ctx, objects,
295 )?;
296 };
297 Ok(())
298 },
299 Err(e) => {
301 Self::readable_byte_stream_controller_error(objects, e)?;
303 Ok(())
304 },
305 }
306 }
307 })?;
308
309 Ok(ReadableStreamObjects::from_class(objects_class))
310 }
311
312 fn readable_byte_stream_controller_should_call_pull<R: ReadableStreamReader<'js>>(
313 mut objects: ReadableByteStreamObjects<'js, R>,
314 ) -> (bool, ReadableByteStreamObjects<'js, R>) {
315 match objects.stream.state {
317 ReadableStreamState::Readable => {},
318 _ => return (false, objects),
320 }
321
322 if objects.controller.close_requested {
324 return (false, objects);
325 }
326
327 if !objects.controller.started {
329 return (false, objects);
330 }
331
332 let (mut has_read_requests, mut has_read_into_requests) = (false, false);
333 objects = objects
334 .with_reader(
335 |objects| {
336 if ReadableStream::readable_stream_get_num_read_requests(&objects.reader) > 0 {
338 has_read_requests = true;
339 }
340 Ok(objects)
341 },
342 |objects| {
343 if ReadableStream::readable_stream_get_num_read_into_requests(&objects.reader)
345 > 0
346 {
347 has_read_into_requests = true;
348 }
349 Ok(objects)
350 },
351 Ok,
352 )
353 .unwrap();
354
355 if has_read_requests || has_read_into_requests {
356 return (true, objects);
357 }
358
359 let desired_size = objects
361 .controller
362 .readable_byte_stream_controller_get_desired_size(&objects.stream);
363
364 if desired_size.0.expect("desired_size must not be null") > 0.0 {
366 return (true, objects);
368 }
369
370 (false, objects)
372 }
373
374 pub(super) fn readable_byte_stream_controller_error<R: ReadableStreamReader<'js>>(
375 mut objects: ReadableByteStreamObjects<'js, R>,
377 e: Value<'js>,
378 ) -> Result<ReadableByteStreamObjects<'js, R>> {
379 if !matches!(objects.stream.state, ReadableStreamState::Readable) {
381 return Ok(objects);
382 };
383
384 objects
386 .controller
387 .readable_byte_stream_controller_clear_pending_pull_intos();
388
389 objects.controller.reset_queue();
391
392 objects
394 .controller
395 .readable_byte_stream_controller_clear_algorithms();
396
397 ReadableStream::readable_stream_error(objects, e)
399 }
400
401 fn readable_byte_stream_controller_clear_pending_pull_intos(&mut self) {
402 self.readable_byte_stream_controller_invalidate_byob_request();
404
405 self.pending_pull_intos.clear();
407 }
408
409 fn readable_byte_stream_controller_invalidate_byob_request(&mut self) {
410 let byob_request = match self.byob_request {
411 None => return,
413 Some(ref byob_request) => byob_request.clone(),
414 };
415 let mut byob_request = OwnedBorrowMut::from_class(byob_request);
416 byob_request.controller = None;
417 byob_request.view = None;
418
419 self.byob_request = None;
420 }
421
422 fn readable_byte_stream_controller_clear_algorithms(&mut self) {
423 self.pull_algorithm = None;
424 self.cancel_algorithm = None;
425 }
426
427 pub(super) fn readable_byte_stream_controller_get_byob_request(
428 ctx: Ctx<'js>,
429 controller: OwnedBorrowMut<'js, Self>,
430 ) -> Result<(
431 Null<Class<'js, ReadableStreamBYOBRequest<'js>>>,
432 OwnedBorrowMut<'js, Self>,
433 )> {
434 if controller.byob_request.is_none() && !controller.pending_pull_intos.is_empty() {
436 let first_descriptor = &controller.pending_pull_intos[0];
438
439 let view = ViewBytes::from_value(
441 &ctx,
442 &controller.function_array_buffer_is_view,
443 Some(
444 &controller
445 .array_constructor_primordials
446 .constructor_uint8array
447 .construct((
448 first_descriptor.buffer.clone(),
449 first_descriptor.byte_offset + first_descriptor.bytes_filled,
450 first_descriptor.byte_length - first_descriptor.bytes_filled,
451 ))?,
452 ),
453 )?;
454
455 let (controller_class, mut controller) = class_from_owned_borrow_mut(controller);
456
457 let byob_request = ReadableStreamBYOBRequest {
459 controller: Some(controller_class),
461 view: Some(view),
463 };
464
465 controller.byob_request = Some(Class::instance(ctx, byob_request)?);
467
468 Ok((Null(controller.byob_request.clone()), controller))
469 } else {
470 Ok((Null(controller.byob_request.clone()), controller))
472 }
473 }
474
475 fn readable_byte_stream_controller_get_desired_size(
476 &self,
477 stream: &ReadableStream<'js>,
478 ) -> Null<f64> {
479 match stream.state {
481 ReadableStreamState::Errored(_) => Null(None),
483 ReadableStreamState::Closed => Null(Some(0.0)),
485 _ => Null(Some(self.strategy_hwm - self.queue_total_size as f64)),
487 }
488 }
489
490 fn reset_queue(&mut self) {
491 self.queue.clear();
493 self.queue_total_size = 0;
495 }
496
497 pub(super) fn readable_byte_stream_controller_close<R: ReadableStreamReader<'js>>(
498 ctx: Ctx<'js>,
499 mut objects: ReadableByteStreamObjects<'js, R>,
501 ) -> Result<ReadableByteStreamObjects<'js, R>> {
502 if objects.controller.close_requested
504 || !matches!(objects.stream.state, ReadableStreamState::Readable)
505 {
506 return Ok(objects);
507 }
508
509 if objects.controller.queue_total_size > 0 {
511 objects.controller.close_requested = true;
513 return Ok(objects);
515 }
516
517 if let Some(first_pending_pull_into) = objects.controller.pending_pull_intos.front() {
520 if first_pending_pull_into.bytes_filled % first_pending_pull_into.element_size != 0 {
522 let e: Value = objects
524 .stream
525 .constructor_type_error
526 .call(("Insufficient bytes to fill elements in the given buffer",))?;
527 Self::readable_byte_stream_controller_error(objects, e.clone())?;
528 return Err(ctx.throw(e));
529 }
530 }
531
532 objects
534 .controller
535 .readable_byte_stream_controller_clear_algorithms();
536
537 ReadableStream::readable_stream_close(ctx, objects)
539 }
540
541 pub(super) fn readable_byte_stream_controller_enqueue<R: ReadableStreamReader<'js>>(
542 ctx: &Ctx<'js>,
543 objects: ReadableByteStreamObjects<'js, R>,
545 chunk: ViewBytes<'js>,
546 ) -> Result<ReadableByteStreamObjects<'js, R>> {
547 Self::readable_byte_stream_controller_enqueue_impl(
548 ctx, objects, chunk, false,
549 )
550 }
551
552 pub(super) fn readable_byte_stream_controller_enqueue_borrowed<R: ReadableStreamReader<'js>>(
567 ctx: &Ctx<'js>,
568 objects: ReadableByteStreamObjects<'js, R>,
569 chunk: ViewBytes<'js>,
570 ) -> Result<ReadableByteStreamObjects<'js, R>> {
571 Self::readable_byte_stream_controller_enqueue_impl(
572 ctx, objects, chunk, true,
573 )
574 }
575
576 fn readable_byte_stream_controller_enqueue_impl<R: ReadableStreamReader<'js>>(
577 ctx: &Ctx<'js>,
578 mut objects: ReadableByteStreamObjects<'js, R>,
579 chunk: ViewBytes<'js>,
580 skip_transfer: bool,
581 ) -> Result<ReadableByteStreamObjects<'js, R>> {
582 if objects.controller.close_requested
584 || !matches!(objects.stream.state, ReadableStreamState::Readable)
585 {
586 return Ok(objects);
587 };
588
589 let (buffer, byte_length, byte_offset) = chunk.get_array_buffer()?;
593
594 buffer.as_raw().ok_or(Exception::throw_type(
596 ctx,
597 "chunk's buffer is detached and so cannot be enqueued",
598 ))?;
599
600 let transferred_buffer = if skip_transfer {
606 buffer
607 } else {
608 transfer_array_buffer(buffer)?
609 };
610
611 if !objects.controller.pending_pull_intos.is_empty() {
614 objects.controller.pending_pull_intos[0]
616 .buffer
617 .as_raw()
618 .or_throw_type(
619 ctx,
620 "The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk",
621 )?;
622
623 objects
625 .controller
626 .readable_byte_stream_controller_invalidate_byob_request();
627
628 objects.controller.pending_pull_intos[0].buffer =
630 transfer_array_buffer(objects.controller.pending_pull_intos[0].buffer.clone())?;
631
632 if let PullIntoDescriptorReaderType::None =
634 objects.controller.pending_pull_intos[0].reader_type
635 {
636 objects = Self::readable_byte_stream_enqueue_detached_pull_into_to_queue(
637 ctx.clone(),
638 objects,
639 0,
640 )?;
641 }
642 }
643
644 objects = objects.with_reader(
645 |mut objects| {
647 objects = Self::readable_byte_stream_controller_process_read_requests_using_queue(
649 objects, ctx,
650 )?;
651
652 if ReadableStream::readable_stream_get_num_read_requests(&objects.reader) == 0 {
654 objects
656 .controller
657 .readable_byte_stream_controller_enqueue_chunk_to_queue(
658 transferred_buffer.clone(),
659 byte_offset,
660 byte_length,
661 )
662 } else {
663 if !objects.controller.pending_pull_intos.is_empty() {
666 objects
668 .controller
669 .readable_byte_stream_controller_shift_pending_pull_into();
670 }
671
672 let transferred_view = ViewBytes::from_value(
674 ctx,
675 &objects.controller.function_array_buffer_is_view,
676 Some(
677 &objects
678 .controller
679 .array_constructor_primordials
680 .constructor_uint8array
681 .construct((
682 transferred_buffer.clone(),
683 byte_offset,
684 byte_length,
685 ))?,
686 ),
687 );
688
689 objects = ReadableStream::readable_stream_fulfill_read_request(
691 ctx,
692 objects,
693 transferred_view.into_js(ctx)?,
694 false,
695 )?;
696 }
697
698 Ok(objects)
699 },
700 |mut objects| {
701 objects
704 .controller
705 .readable_byte_stream_controller_enqueue_chunk_to_queue(
706 transferred_buffer.clone(),
707 byte_offset,
708 byte_length,
709 );
710 Self::readable_byte_stream_controller_process_pull_into_descriptors_using_queue(
713 ctx, objects,
714 )
715 },
716 |mut objects| {
717 objects
720 .controller
721 .readable_byte_stream_controller_enqueue_chunk_to_queue(
722 transferred_buffer.clone(),
723 byte_offset,
724 byte_length,
725 );
726
727 Ok(objects)
728 },
729 )?;
730
731 Self::readable_byte_stream_controller_call_pull_if_needed(ctx.clone(), objects)
733 }
734
735 fn readable_byte_stream_enqueue_detached_pull_into_to_queue<R: ReadableStreamReader<'js>>(
736 ctx: Ctx<'js>,
737 mut objects: ReadableByteStreamObjects<'js, R>,
738 pull_into_descriptor_index: usize,
739 ) -> Result<ReadableByteStreamObjects<'js, R>> {
740 let pull_into_descriptor =
741 &objects.controller.pending_pull_intos[pull_into_descriptor_index];
742 if pull_into_descriptor.bytes_filled > 0 {
744 let buffer = pull_into_descriptor.buffer.clone();
745 let byte_offset = pull_into_descriptor.byte_offset;
746 let bytes_filled = pull_into_descriptor.bytes_filled;
747 objects = Self::readable_byte_stream_controller_enqueue_cloned_chunk_to_queue(
748 ctx,
749 objects,
750 &buffer,
751 byte_offset,
752 bytes_filled,
753 )?;
754 }
755
756 objects
758 .controller
759 .readable_byte_stream_controller_shift_pending_pull_into();
760
761 Ok(objects)
762 }
763
764 fn readable_byte_stream_controller_process_read_requests_using_queue(
765 mut objects: ReadableStreamDefaultReaderObjects<'js, OwnedBorrowMut<'js, Self>>,
766 ctx: &Ctx<'js>,
767 ) -> Result<ReadableStreamDefaultReaderObjects<'js, OwnedBorrowMut<'js, Self>>> {
768 while !objects.reader.read_requests.is_empty() {
770 if objects.controller.queue_total_size == 0 {
772 return Ok(objects);
773 }
774
775 let read_request = objects.reader.read_requests.pop_front().unwrap();
778 objects = Self::readable_byte_stream_controller_fill_read_request_from_queue(
780 ctx,
781 objects,
782 read_request,
783 )?;
784 }
785
786 Ok(objects)
787 }
788
789 fn readable_byte_stream_controller_shift_pending_pull_into(
790 &mut self,
791 ) -> PullIntoDescriptor<'js> {
792 self.readable_byte_stream_controller_invalidate_byob_request();
794 self.pending_pull_intos.pop_front().expect(
798 "ReadableByteStreamControllerShiftPendingPullInto called on empty pendingPullIntos",
799 )
800 }
801
802 fn readable_byte_stream_controller_enqueue_chunk_to_queue(
803 &mut self,
804 buffer: ArrayBuffer<'js>,
805 byte_offset: usize,
806 byte_length: usize,
807 ) {
808 self.queue.push_back(ReadableByteStreamQueueEntry {
810 buffer,
811 byte_offset,
812 byte_length,
813 });
814
815 self.queue_total_size += byte_length;
817 }
818
819 fn readable_byte_stream_controller_process_pull_into_descriptors_using_queue<
820 R: ReadableStreamReader<'js>,
821 >(
822 ctx: &Ctx<'js>,
823 mut objects: ReadableByteStreamObjects<'js, R>,
824 ) -> Result<ReadableByteStreamObjects<'js, R>> {
825 while !objects.controller.pending_pull_intos.is_empty() {
827 if objects.controller.queue_total_size == 0 {
829 return Ok(objects);
830 }
831
832 let mut pull_into_descriptor_ref = PullIntoDescriptorRefMut::Index(0);
834
835 if objects
837 .controller
838 .readable_byte_stream_controller_fill_pull_into_descriptor_from_queue(
839 ctx,
840 &mut pull_into_descriptor_ref,
841 )?
842 {
843 let pull_into_descriptor = objects
845 .controller
846 .readable_byte_stream_controller_shift_pending_pull_into();
847
848 objects = Self::readable_byte_stream_controller_commit_pull_into_descriptor(
850 ctx.clone(),
851 objects,
852 pull_into_descriptor,
853 )?;
854 }
855 }
856 Ok(objects)
857 }
858
859 fn readable_byte_stream_controller_enqueue_cloned_chunk_to_queue<
860 R: ReadableStreamReader<'js>,
861 >(
862 ctx: Ctx<'js>,
863 mut objects: ReadableByteStreamObjects<'js, R>,
864 buffer: &ArrayBuffer<'js>,
865 byte_offset: usize,
866 byte_length: usize,
867 ) -> Result<ReadableByteStreamObjects<'js, R>> {
868 let clone_result = match ArrayBuffer::new_copy(
870 ctx.clone(),
871 &buffer.as_bytes().expect(
872 "ReadableByteStreamControllerEnqueueClonedChunkToQueue called on detached buffer",
873 )[byte_offset..byte_offset + byte_length],
874 ) {
875 Ok(clone_result) => clone_result,
876 Err(Error::Exception) => {
877 let err = ctx.catch();
878 Self::readable_byte_stream_controller_error(objects, err.clone())?;
879 return Err(ctx.throw(err));
880 },
881 Err(err) => return Err(err),
882 };
883
884 objects
886 .controller
887 .readable_byte_stream_controller_enqueue_chunk_to_queue(clone_result, 0, byte_length);
888
889 Ok(objects)
890 }
891
892 fn readable_byte_stream_controller_fill_read_request_from_queue(
893 ctx: &Ctx<'js>,
894 mut objects: ReadableStreamDefaultReaderObjects<'js, OwnedBorrowMut<'js, Self>>,
895 read_request: impl ReadableStreamReadRequest<'js>,
896 ) -> Result<ReadableStreamDefaultReaderObjects<'js, OwnedBorrowMut<'js, Self>>> {
897 let entry = {
898 let entry = objects.controller.queue.pop_front().expect(
902 "ReadableByteStreamControllerFillReadRequestFromQueue called with empty queue",
903 );
904
905 objects.controller.queue_total_size -= entry.byte_length;
907
908 entry
909 };
910
911 objects = Self::readable_byte_stream_controller_handle_queue_drain(ctx.clone(), objects)?;
913
914 let view: TypedArray<u8> = objects
916 .controller
917 .array_constructor_primordials
918 .constructor_uint8array
919 .construct((entry.buffer, entry.byte_offset, entry.byte_length))?;
920
921 read_request.chunk_steps_typed(objects, view.into_value())
923 }
924
925 fn readable_byte_stream_controller_fill_pull_into_descriptor_from_queue<'a>(
926 &'a mut self,
927 ctx: &Ctx<'js>,
928 pull_into_descriptor_ref: &mut PullIntoDescriptorRefMut<'js, 'a>,
929 ) -> Result<bool> {
930 let (mut total_bytes_to_copy_remaining, ready) = {
931 let pull_into_descriptor = match pull_into_descriptor_ref {
932 PullIntoDescriptorRefMut::Index(i) => &mut self.pending_pull_intos[*i],
933 PullIntoDescriptorRefMut::Owned(r) => r,
934 };
935 let max_bytes_to_copy: usize = std::cmp::min(
937 self.queue_total_size,
938 pull_into_descriptor.byte_length - pull_into_descriptor.bytes_filled,
939 );
940
941 let max_bytes_filled = pull_into_descriptor.bytes_filled + max_bytes_to_copy;
943
944 let mut total_bytes_to_copy_remaining = max_bytes_to_copy;
946
947 let mut ready = false;
949
950 let remainder_bytes = max_bytes_filled % pull_into_descriptor.element_size;
952
953 let max_aligned_bytes = max_bytes_filled - remainder_bytes;
955
956 if max_aligned_bytes >= pull_into_descriptor.minimum_fill {
958 total_bytes_to_copy_remaining =
960 max_aligned_bytes - pull_into_descriptor.bytes_filled;
961 ready = true
963 }
964
965 (total_bytes_to_copy_remaining, ready)
966 };
967
968 while total_bytes_to_copy_remaining > 0 {
971 let bytes_to_copy = {
972 let pull_into_descriptor = match pull_into_descriptor_ref {
973 PullIntoDescriptorRefMut::Index(i) => &mut self.pending_pull_intos[*i],
974 PullIntoDescriptorRefMut::Owned(r) => r,
975 };
976
977 let head_of_queue = self
979 .queue
980 .front_mut()
981 .expect("empty queue with bytes to copy");
982 let bytes_to_copy: usize =
984 std::cmp::min(total_bytes_to_copy_remaining, head_of_queue.byte_length);
985 let dest_start: usize =
987 pull_into_descriptor.byte_offset + pull_into_descriptor.bytes_filled;
988 copy_data_block_bytes(
990 ctx,
991 &pull_into_descriptor.buffer,
992 dest_start,
993 &head_of_queue.buffer,
994 head_of_queue.byte_offset,
995 bytes_to_copy,
996 )?;
997 if head_of_queue.byte_length == bytes_to_copy {
998 self.queue.pop_front();
1001 } else {
1002 head_of_queue.byte_offset += bytes_to_copy;
1005 head_of_queue.byte_length -= bytes_to_copy
1007 }
1008
1009 self.queue_total_size -= bytes_to_copy;
1011
1012 bytes_to_copy
1013 };
1014
1015 self.readable_byte_stream_controller_fill_head_pull_into_descriptor(
1017 bytes_to_copy,
1018 pull_into_descriptor_ref,
1019 );
1020
1021 total_bytes_to_copy_remaining -= bytes_to_copy
1023 }
1024
1025 Ok(ready)
1026 }
1027
1028 fn readable_byte_stream_controller_commit_pull_into_descriptor<R: ReadableStreamReader<'js>>(
1029 ctx: Ctx<'js>,
1030 objects: ReadableByteStreamObjects<'js, R>,
1031 pull_into_descriptor: PullIntoDescriptor<'js>,
1032 ) -> Result<ReadableByteStreamObjects<'js, R>> {
1033 let mut done = false;
1035 if matches!(objects.stream.state, ReadableStreamState::Closed) {
1037 done = true
1039 }
1040
1041 let reader_type = pull_into_descriptor.reader_type;
1042
1043 let filled_view = Self::readable_byte_stream_controller_convert_pull_into_descriptor(
1045 ctx.clone(),
1046 &objects.stream.function_array_buffer_is_view,
1047 pull_into_descriptor,
1048 )?;
1049
1050 if let PullIntoDescriptorReaderType::Default = reader_type {
1051 objects.with_assert_default_reader(|objects| {
1053 ReadableStream::readable_stream_fulfill_read_request(
1055 &ctx,
1056 objects,
1057 filled_view.into_js(&ctx)?,
1058 done,
1059 )
1060 })
1061 } else {
1062 objects.with_assert_byob_reader(|objects| {
1064 ReadableStream::readable_stream_fulfill_read_into_request(
1066 &ctx,
1067 objects,
1068 filled_view,
1069 done,
1070 )
1071 })
1072 }
1073 }
1074
1075 fn readable_byte_stream_controller_handle_queue_drain<R: ReadableStreamReader<'js>>(
1076 ctx: Ctx<'js>,
1077 mut objects: ReadableByteStreamObjects<'js, R>,
1078 ) -> Result<ReadableByteStreamObjects<'js, R>> {
1079 if objects.controller.queue_total_size == 0 && objects.controller.close_requested {
1081 objects
1083 .controller
1084 .readable_byte_stream_controller_clear_algorithms();
1085 ReadableStream::readable_stream_close(ctx, objects)
1087 } else {
1088 Self::readable_byte_stream_controller_call_pull_if_needed(ctx.clone(), objects)
1091 }
1092 }
1093
1094 fn readable_byte_stream_controller_convert_pull_into_descriptor(
1095 ctx: Ctx<'js>,
1096 function_array_buffer_is_view: &Function<'js>,
1097 pull_into_descriptor: PullIntoDescriptor<'js>,
1098 ) -> Result<ViewBytes<'js>> {
1099 let PullIntoDescriptor {
1100 bytes_filled,
1102 element_size,
1104 byte_offset,
1105 buffer,
1106 ..
1107 } = pull_into_descriptor;
1108 let buffer = transfer_array_buffer(buffer);
1110 let view: Object = pull_into_descriptor.view_constructor.construct((
1112 buffer,
1113 byte_offset,
1114 bytes_filled / element_size,
1115 ))?;
1116 ViewBytes::from_object(&ctx, function_array_buffer_is_view, &view)
1117 }
1118
1119 pub(super) fn readable_byte_stream_controller_pull_into(
1120 ctx: &Ctx<'js>,
1121 mut objects: ReadableStreamBYOBObjects<'js>,
1123 view: ViewBytes<'js>,
1124 min: u64,
1125 read_into_request: impl ReadableStreamReadIntoRequest<'js> + 'js,
1126 ) -> Result<ReadableStreamBYOBObjects<'js>> {
1127 let (element_size, ctor) = (
1130 view.element_size(),
1131 objects
1132 .controller
1133 .array_constructor_primordials
1134 .for_view_bytes(&view),
1135 );
1136
1137 let minimum_fill: usize = (min as usize) * element_size;
1139
1140 let (buffer, byte_length, byte_offset) = view.get_array_buffer()?;
1143
1144 let buffer_result = transfer_array_buffer(buffer);
1146 let buffer = match buffer_result {
1147 Err(Error::Exception) => {
1149 objects = read_into_request.error_steps(objects, ctx.catch())?;
1151 return Ok(objects);
1153 },
1154 Err(err) => return Err(err),
1155 Ok(buffer) => buffer,
1157 };
1158
1159 let buffer_byte_length = buffer.len();
1160 let mut pull_into_descriptor = PullIntoDescriptor {
1162 buffer,
1163 buffer_byte_length,
1164 byte_offset,
1165 byte_length,
1166 bytes_filled: 0,
1167 minimum_fill,
1168 element_size,
1169 view_constructor: ctor.clone(),
1170 reader_type: PullIntoDescriptorReaderType::Byob,
1171 };
1172
1173 if !objects.controller.pending_pull_intos.is_empty() {
1175 objects
1177 .controller
1178 .pending_pull_intos
1179 .push_back(pull_into_descriptor);
1180
1181 ReadableStream::readable_stream_add_read_into_request(
1183 &mut objects.reader,
1184 read_into_request,
1185 );
1186
1187 return Ok(objects);
1189 }
1190
1191 if matches!(objects.stream.state, ReadableStreamState::Closed) {
1193 let empty_view: Value<'js> = ctor.construct((
1195 pull_into_descriptor.buffer,
1196 pull_into_descriptor.byte_offset,
1197 0,
1198 ))?;
1199
1200 objects = read_into_request.close_steps(objects, empty_view)?;
1202
1203 return Ok(objects);
1205 }
1206
1207 if objects.controller.queue_total_size > 0 {
1209 if objects
1211 .controller
1212 .readable_byte_stream_controller_fill_pull_into_descriptor_from_queue(
1213 ctx,
1214 &mut PullIntoDescriptorRefMut::Owned(&mut pull_into_descriptor),
1215 )?
1216 {
1217 let filled_view = objects
1219 .controller
1220 .readable_byte_steam_controller_convert_pull_into_descriptor(
1221 pull_into_descriptor,
1222 )?;
1223
1224 objects =
1226 Self::readable_byte_stream_controller_handle_queue_drain(ctx.clone(), objects)?;
1227
1228 return read_into_request.chunk_steps(objects, filled_view);
1231 }
1232
1233 if objects.controller.close_requested {
1235 let e: Value = objects
1237 .stream
1238 .constructor_type_error
1239 .call(("Insufficient bytes to fill elements in the given buffer",))?;
1240
1241 objects = Self::readable_byte_stream_controller_error(objects, e.clone())?;
1243
1244 return read_into_request.error_steps(objects, e);
1247 }
1248 }
1249
1250 objects
1252 .controller
1253 .pending_pull_intos
1254 .push_back(pull_into_descriptor);
1255
1256 ReadableStream::readable_stream_add_read_into_request(
1258 &mut objects.reader,
1259 read_into_request,
1260 );
1261
1262 Self::readable_byte_stream_controller_call_pull_if_needed(ctx.clone(), objects)
1264 }
1265
1266 fn readable_byte_steam_controller_convert_pull_into_descriptor(
1267 &mut self,
1268 pull_into_descriptor: PullIntoDescriptor<'js>,
1269 ) -> Result<Value<'js>> {
1270 let bytes_filled = pull_into_descriptor.bytes_filled;
1272
1273 let element_size = pull_into_descriptor.element_size;
1275
1276 let buffer = transfer_array_buffer(pull_into_descriptor.buffer)?;
1278
1279 pull_into_descriptor.view_constructor.construct((
1281 buffer,
1282 pull_into_descriptor.byte_offset,
1283 bytes_filled / element_size,
1284 ))
1285 }
1286
1287 pub(super) fn readable_byte_stream_controller_respond<R: ReadableStreamReader<'js>>(
1288 ctx: Ctx<'js>,
1289 mut objects: ReadableByteStreamObjects<'js, R>,
1290 bytes_written: usize,
1291 ) -> Result<()> {
1292 let first_descriptor = &mut objects.controller.pending_pull_intos[0];
1294
1295 match objects.stream.state {
1297 ReadableStreamState::Closed => {
1299 if bytes_written != 0 {
1301 return Err(Exception::throw_type(
1302 &ctx,
1303 "bytesWritten must be 0 when calling respond() on a closed stream",
1304 ));
1305 }
1306 },
1307 _ => {
1309 if bytes_written == 0 {
1311 return Err(Exception::throw_type(
1312 &ctx,
1313 "bytesWritten must be greater than 0 when calling respond() on a readable stream",
1314 ));
1315 }
1316
1317 if first_descriptor.bytes_filled + bytes_written > first_descriptor.byte_length {
1319 return Err(Exception::throw_range(&ctx, "bytesWritten out of range'"));
1320 }
1321 },
1322 };
1323
1324 first_descriptor.buffer = transfer_array_buffer(first_descriptor.buffer.clone())?;
1326
1327 Self::readable_byte_stream_controller_respond_internal(ctx, objects, bytes_written)
1329 }
1330
1331 fn readable_byte_stream_controller_respond_internal<R: ReadableStreamReader<'js>>(
1332 ctx: Ctx<'js>,
1333 mut objects: ReadableByteStreamObjects<'js, R>,
1334 bytes_written: usize,
1335 ) -> Result<()> {
1336 let first_descriptor_index = 0;
1338
1339 objects
1341 .controller
1342 .readable_byte_stream_controller_invalidate_byob_request();
1343
1344 match objects.stream.state {
1346 ReadableStreamState::Closed => {
1348 objects = Self::readable_byte_stream_controller_respond_in_closed_state(
1350 ctx.clone(),
1351 objects,
1352 first_descriptor_index,
1353 )?;
1354 },
1355 _ => {
1357 objects = Self::readable_byte_stream_controller_respond_in_readable_state(
1359 ctx.clone(),
1360 objects,
1361 bytes_written,
1362 first_descriptor_index,
1363 )?
1364 },
1365 };
1366
1367 _ = Self::readable_byte_stream_controller_call_pull_if_needed(ctx, objects)?;
1368 Ok(())
1369 }
1370
1371 fn readable_byte_stream_controller_respond_in_closed_state<R: ReadableStreamReader<'js>>(
1372 ctx: Ctx<'js>,
1373 mut objects: ReadableByteStreamObjects<'js, R>,
1375 first_descriptor_index: usize,
1376 ) -> Result<ReadableByteStreamObjects<'js, R>> {
1377 if let PullIntoDescriptorReaderType::None =
1379 objects.controller.pending_pull_intos[first_descriptor_index].reader_type
1380 {
1381 objects
1382 .controller
1383 .readable_byte_stream_controller_shift_pending_pull_into();
1384 }
1385
1386 objects.with_reader(
1388 Ok,
1389 |mut objects| {
1390 while ReadableStream::readable_stream_get_num_read_into_requests(&objects.reader)
1392 > 0
1393 {
1394 let pull_into_descriptor = objects
1396 .controller
1397 .readable_byte_stream_controller_shift_pending_pull_into();
1398
1399 objects = Self::readable_byte_stream_controller_commit_pull_into_descriptor(
1401 ctx.clone(),
1402 objects,
1403 pull_into_descriptor,
1404 )?;
1405 }
1406
1407 Ok(objects)
1408 },
1409 Ok,
1410 )
1411 }
1412
1413 fn readable_byte_stream_controller_respond_in_readable_state<R: ReadableStreamReader<'js>>(
1414 ctx: Ctx<'js>,
1415 mut objects: ReadableByteStreamObjects<'js, R>,
1417 bytes_written: usize,
1418 pull_into_descriptor_index: usize,
1419 ) -> Result<ReadableByteStreamObjects<'js, R>> {
1420 objects
1422 .controller
1423 .readable_byte_stream_controller_fill_head_pull_into_descriptor(
1424 bytes_written,
1425 &mut PullIntoDescriptorRefMut::Index(pull_into_descriptor_index),
1426 );
1427
1428 if let PullIntoDescriptorReaderType::None =
1430 objects.controller.pending_pull_intos[pull_into_descriptor_index].reader_type
1431 {
1432 objects = Self::readable_byte_stream_enqueue_detached_pull_into_to_queue(
1434 ctx.clone(),
1435 objects,
1436 pull_into_descriptor_index,
1437 )?;
1438 return Self::readable_byte_stream_controller_process_pull_into_descriptors_using_queue(
1441 &ctx, objects,
1442 );
1443 }
1444
1445 if objects.controller.pending_pull_intos[pull_into_descriptor_index].bytes_filled
1447 < objects.controller.pending_pull_intos[pull_into_descriptor_index].minimum_fill
1448 {
1449 return Ok(objects);
1450 }
1451
1452 let mut pull_into_descriptor = objects
1454 .controller
1455 .readable_byte_stream_controller_shift_pending_pull_into();
1456
1457 let remainder_size = pull_into_descriptor.bytes_filled % pull_into_descriptor.element_size;
1459
1460 if remainder_size > 0 {
1462 let end = pull_into_descriptor.byte_offset + pull_into_descriptor.bytes_filled;
1464
1465 let buffer = pull_into_descriptor.buffer.clone();
1466
1467 objects = Self::readable_byte_stream_controller_enqueue_cloned_chunk_to_queue(
1469 ctx.clone(),
1470 objects,
1471 &buffer,
1472 end - remainder_size,
1473 remainder_size,
1474 )?;
1475 }
1476
1477 pull_into_descriptor.bytes_filled -= remainder_size;
1479
1480 objects = Self::readable_byte_stream_controller_commit_pull_into_descriptor(
1482 ctx.clone(),
1483 objects,
1484 pull_into_descriptor,
1485 )?;
1486
1487 Self::readable_byte_stream_controller_process_pull_into_descriptors_using_queue(
1489 &ctx, objects,
1490 )
1491 }
1492
1493 pub(super) fn readable_byte_stream_controller_respond_with_new_view<
1494 R: ReadableStreamReader<'js>,
1495 >(
1496 ctx: Ctx<'js>,
1497 mut objects: ReadableByteStreamObjects<'js, R>,
1498 view: ViewBytes<'js>,
1499 ) -> Result<()> {
1500 let first_descriptor_index = 0;
1502
1503 let (buffer, byte_length, byte_offset) = view.get_array_buffer()?;
1504
1505 match objects.stream.state {
1507 ReadableStreamState::Closed => {
1509 if byte_length != 0 {
1511 return Err(Exception::throw_type(&ctx, "The view's length must be 0 when calling respondWithNewView() on a closed stream"));
1512 }
1513 },
1514 _ => {
1516 if byte_length == 0 {
1518 return Err(Exception::throw_type(&ctx, "The view's length must be greater than 0 when calling respondWithNewView() on a readable stream"));
1519 }
1520 },
1521 };
1522
1523 {
1524 let first_descriptor =
1525 &mut objects.controller.pending_pull_intos[first_descriptor_index];
1526
1527 if first_descriptor.byte_offset + first_descriptor.bytes_filled != byte_offset {
1529 return Err(Exception::throw_range(
1530 &ctx,
1531 "The region specified by view does not match byobRequest",
1532 ));
1533 };
1534
1535 if first_descriptor.buffer_byte_length != buffer.len() {
1537 return Err(Exception::throw_range(
1538 &ctx,
1539 "The buffer of view has different capacity than byobRequest",
1540 ));
1541 };
1542
1543 if first_descriptor.bytes_filled + byte_length > first_descriptor.byte_length {
1545 return Err(Exception::throw_range(
1546 &ctx,
1547 "The region specified by view is larger than byobRequest",
1548 ));
1549 }
1550
1551 first_descriptor.buffer = transfer_array_buffer(buffer)?;
1553 }
1554
1555 Self::readable_byte_stream_controller_respond_internal(ctx, objects, byte_length)
1557 }
1558
1559 fn readable_byte_stream_controller_fill_head_pull_into_descriptor<'a>(
1560 &mut self,
1561 size: usize,
1562 pull_into_descriptor_ref: &mut PullIntoDescriptorRefMut<'js, 'a>,
1563 ) {
1564 let pull_into_descriptor = match pull_into_descriptor_ref {
1565 PullIntoDescriptorRefMut::Index(i) => &mut self.pending_pull_intos[*i],
1566 PullIntoDescriptorRefMut::Owned(r) => *r,
1567 };
1568
1569 pull_into_descriptor.bytes_filled += size;
1571 }
1572
1573 fn start_algorithm<R: ReadableStreamReader<'js>>(
1574 ctx: Ctx<'js>,
1575 objects: ReadableByteStreamObjects<'js, R>,
1576 start_algorithm: StartAlgorithm<'js>,
1577 ) -> Result<(
1578 Value<'js>,
1579 ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,
1580 )> {
1581 let objects_class = objects.into_inner();
1582
1583 Ok((
1584 start_algorithm.call(
1585 ctx,
1586 ReadableStreamControllerClass::ReadableStreamByteController(
1587 objects_class.controller.clone(),
1588 ),
1589 )?,
1590 objects_class,
1591 ))
1592 }
1593
1594 fn pull_algorithm<R: ReadableStreamReader<'js>>(
1595 ctx: Ctx<'js>,
1596 objects: ReadableByteStreamObjects<'js, R>,
1597 ) -> Result<(
1598 Promise<'js>,
1599 ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,
1600 )> {
1601 let pull_algorithm = objects
1602 .controller
1603 .pull_algorithm
1604 .clone()
1605 .expect("pull algorithm used after ReadableStreamDefaultControllerClearAlgorithms");
1606 let promise_primordials = objects.stream.promise_primordials.clone();
1607 let objects_class = objects.into_inner();
1608
1609 Ok((
1610 pull_algorithm.call(
1611 ctx,
1612 &promise_primordials,
1613 ReadableStreamControllerClass::ReadableStreamByteController(
1614 objects_class.controller.clone(),
1615 ),
1616 )?,
1617 objects_class,
1618 ))
1619 }
1620
1621 fn cancel_algorithm<R: ReadableStreamReader<'js>>(
1622 ctx: Ctx<'js>,
1623 objects: ReadableByteStreamObjects<'js, R>,
1624 reason: Value<'js>,
1625 ) -> Result<(
1626 Promise<'js>,
1627 ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,
1628 )> {
1629 let cancel_algorithm =
1630 objects.controller.cancel_algorithm.clone().expect(
1631 "cancel algorithm used after ReadableStreamDefaultControllerClearAlgorithms",
1632 );
1633 let promise_primordials = objects.stream.promise_primordials.clone();
1634 let objects_class = objects.into_inner();
1635
1636 Ok((
1637 cancel_algorithm.call(ctx, &promise_primordials, reason)?,
1638 objects_class,
1639 ))
1640 }
1641}
1642
1643#[methods(rename_all = "camelCase")]
1644impl<'js> ReadableByteStreamController<'js> {
1645 #[qjs(constructor)]
1646 fn new(ctx: Ctx<'js>) -> Result<Class<'js, Self>> {
1647 Err(Exception::throw_type(&ctx, "Illegal constructor"))
1648 }
1649
1650 #[qjs(get, rename = "byobRequest")]
1652 fn byob_request_getter(
1653 ctx: Ctx<'js>,
1654 controller: This<Class<'js, Self>>,
1655 ) -> Result<Null<Class<'js, ReadableStreamBYOBRequest<'js>>>> {
1656 if let Ok(owned) = rquickjs::class::OwnedBorrowMut::try_from_class(controller.0.clone()) {
1664 let (request, _) = Self::readable_byte_stream_controller_get_byob_request(ctx, owned)?;
1665 return Ok(request);
1666 }
1667 Ok(Null(None))
1673 }
1674
1675 #[qjs(get)]
1677 fn desired_size(&self) -> Null<f64> {
1678 let stream = OwnedBorrow::from_class(self.stream.clone());
1679 self.readable_byte_stream_controller_get_desired_size(&stream)
1680 }
1681
1682 fn close(ctx: Ctx<'js>, controller: This<OwnedBorrowMut<'js, Self>>) -> Result<()> {
1684 if controller.close_requested {
1686 return Err(Exception::throw_type(&ctx, "close() called more than once"));
1687 }
1688
1689 let objects = ReadableStreamObjects::from_byte_controller(controller.0).refresh_reader();
1690
1691 if !matches!(objects.stream.state, ReadableStreamState::Readable) {
1692 return Err(Exception::throw_type(
1693 &ctx,
1694 "close() called when stream is not readable",
1695 ));
1696 };
1697
1698 Self::readable_byte_stream_controller_close(ctx, objects)?;
1700 Ok(())
1701 }
1702
1703 fn enqueue(
1705 this: This<OwnedBorrowMut<'js, Self>>,
1706 ctx: Ctx<'js>,
1707 chunk: Value<'js>,
1708 ) -> Result<()> {
1709 let chunk = ViewBytes::from_value(&ctx, &this.function_array_buffer_is_view, Some(&chunk))?;
1710
1711 let (array_buffer, byte_length, _) = chunk.get_array_buffer()?;
1712
1713 if byte_length == 0 {
1715 return Err(Exception::throw_type(
1716 &ctx,
1717 "chunk must have non-zero byteLength",
1718 ));
1719 }
1720
1721 if array_buffer.is_empty() {
1723 return Err(Exception::throw_type(
1724 &ctx,
1725 "chunk must have non-zero buffer byteLength",
1726 ));
1727 }
1728
1729 if this.close_requested {
1731 return Err(Exception::throw_type(&ctx, "stream is closed or draining"));
1732 }
1733
1734 let objects = ReadableStreamObjects::from_byte_controller(this.0).refresh_reader();
1735
1736 if !matches!(objects.stream.state, ReadableStreamState::Readable) {
1738 return Err(Exception::throw_type(
1739 &ctx,
1740 "The stream is not in the readable state and cannot be enqueued to",
1741 ));
1742 };
1743
1744 Self::readable_byte_stream_controller_enqueue(&ctx, objects, chunk)?;
1746 Ok(())
1747 }
1748
1749 fn error(
1751 ctx: Ctx<'js>,
1752 controller: This<OwnedBorrowMut<'js, Self>>,
1753 e: Opt<Value<'js>>,
1754 ) -> Result<()> {
1755 let objects = ReadableStreamObjects::from_byte_controller(controller.0).refresh_reader();
1756
1757 Self::readable_byte_stream_controller_error(objects, e.0.unwrap_or_undefined(&ctx))?;
1759 Ok(())
1760 }
1761}
1762
1763impl<'js> ReadableStreamController<'js> for ReadableByteStreamControllerOwned<'js> {
1764 type Class = ReadableByteStreamControllerClass<'js>;
1765
1766 fn with_controller<C, O>(
1767 self,
1768 ctx: C,
1769 _: impl FnOnce(
1770 C,
1771 ReadableStreamDefaultControllerOwned<'js>,
1772 ) -> Result<(O, ReadableStreamDefaultControllerOwned<'js>)>,
1773 byte: impl FnOnce(
1774 C,
1775 ReadableByteStreamControllerOwned<'js>,
1776 ) -> Result<(O, ReadableByteStreamControllerOwned<'js>)>,
1777 ) -> Result<(O, Self)> {
1778 let (ctx, reader) = byte(ctx, self)?;
1779 Ok((ctx, reader))
1780 }
1781
1782 fn into_inner(self) -> Self::Class {
1783 OwnedBorrowMut::into_inner(self)
1784 }
1785
1786 fn from_class(class: Self::Class) -> Self {
1787 OwnedBorrowMut::from_class(class)
1788 }
1789
1790 fn into_erased(self) -> ReadableStreamControllerOwned<'js> {
1791 ReadableStreamControllerOwned::ReadableStreamByteController(self)
1792 }
1793
1794 fn try_from_erased(erased: ReadableStreamControllerOwned<'js>) -> Option<Self> {
1795 match erased {
1796 ReadableStreamControllerOwned::ReadableStreamDefaultController(_) => None,
1797 ReadableStreamControllerOwned::ReadableStreamByteController(r) => Some(r),
1798 }
1799 }
1800
1801 fn pull_steps(
1802 ctx: &Ctx<'js>,
1803 mut objects: ReadableStreamDefaultReaderObjects<'js, Self>,
1804 read_request: impl ReadableStreamReadRequest<'js> + 'js,
1805 ) -> Result<ReadableStreamDefaultReaderObjects<'js, Self>> {
1806 if objects.controller.queue_total_size > 0 {
1808 return ReadableByteStreamController::readable_byte_stream_controller_fill_read_request_from_queue(
1811 ctx,
1812 objects,
1813 read_request,
1814 );
1815 }
1816
1817 let auto_allocate_chunk_size = objects.controller.auto_allocate_chunk_size;
1819
1820 if let Some(auto_allocate_chunk_size) = auto_allocate_chunk_size {
1822 let buffer: ArrayBuffer = match objects
1824 .controller
1825 .constructor_array_buffer
1826 .construct((auto_allocate_chunk_size,))
1827 {
1828 Err(Error::Exception) => {
1830 return read_request.error_steps_typed(objects, ctx.catch());
1832 },
1833 Err(err) => return Err(err),
1834 Ok(buffer) => buffer,
1835 };
1836
1837 let pull_into_descriptor = PullIntoDescriptor {
1839 buffer,
1840 buffer_byte_length: auto_allocate_chunk_size,
1841 byte_offset: 0,
1842 byte_length: auto_allocate_chunk_size,
1843 bytes_filled: 0,
1844 minimum_fill: 1,
1845 element_size: 1,
1846 view_constructor: objects
1847 .controller
1848 .array_constructor_primordials
1849 .constructor_uint8array
1850 .clone(),
1851 reader_type: PullIntoDescriptorReaderType::Default,
1852 };
1853
1854 objects
1856 .controller
1857 .pending_pull_intos
1858 .push_back(pull_into_descriptor);
1859 }
1860
1861 objects
1863 .stream
1864 .readable_stream_add_read_request(&mut objects.reader, read_request);
1865
1866 ReadableByteStreamController::readable_byte_stream_controller_call_pull_if_needed(
1868 ctx.clone(),
1869 objects,
1870 )
1871 }
1872
1873 fn cancel_steps<R: ReadableStreamReader<'js>>(
1874 ctx: &Ctx<'js>,
1875 mut objects: ReadableStreamObjects<'js, Self, R>,
1876 reason: Value<'js>,
1877 ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, Self, R>)> {
1878 objects
1880 .controller
1881 .readable_byte_stream_controller_clear_pending_pull_intos();
1882
1883 objects.controller.reset_queue();
1885
1886 let (result, objects_class) =
1888 ReadableByteStreamController::cancel_algorithm(ctx.clone(), objects, reason)?;
1889
1890 objects = ReadableStreamObjects::from_class(objects_class);
1891
1892 objects
1894 .controller
1895 .readable_byte_stream_controller_clear_algorithms();
1896
1897 Ok((result, objects))
1899 }
1900
1901 fn release_steps(&mut self) {
1902 if !self.pending_pull_intos.is_empty() {
1904 let first_pending_pull_into = &mut self.pending_pull_intos[0];
1906
1907 first_pending_pull_into.reader_type = PullIntoDescriptorReaderType::None;
1909
1910 _ = self.pending_pull_intos.split_off(1);
1912 }
1913 }
1914}
1915
1916#[derive(JsLifetime, Trace, Clone)]
1917#[rquickjs::class]
1918pub(crate) struct ReadableStreamBYOBRequest<'js> {
1919 pub(super) view: Option<ViewBytes<'js>>,
1920 controller: Option<ReadableByteStreamControllerClass<'js>>,
1921}
1922
1923#[methods(rename_all = "camelCase")]
1924impl<'js> ReadableStreamBYOBRequest<'js> {
1925 #[qjs(constructor)]
1926 fn new(ctx: Ctx<'js>) -> Result<Class<'js, Self>> {
1927 Err(Exception::throw_type(&ctx, "Illegal constructor"))
1928 }
1929
1930 #[qjs(get)]
1931 fn view(&self) -> Null<ViewBytes<'js>> {
1932 Null(self.view.clone())
1933 }
1934
1935 fn respond(
1936 ctx: Ctx<'js>,
1937 byob_request: This<OwnedBorrowMut<'js, Self>>,
1938 bytes_written: usize,
1939 ) -> Result<()> {
1940 let (controller, view) = match (&byob_request.controller, &byob_request.view) {
1942 (Some(controller), Some(view)) => (controller.clone(), view),
1943 _ => {
1944 return Err(Exception::throw_type(
1945 &ctx,
1946 "This BYOB request has been invalidated",
1947 ));
1948 },
1949 };
1950 let (buffer, _, _) = view.get_array_buffer()?;
1951 drop(byob_request);
1952
1953 if buffer.as_bytes().is_none() {
1955 return Err(Exception::throw_type(
1956 &ctx,
1957 "The BYOB request's buffer has been detached and so cannot be used as a response",
1958 ));
1959 }
1960
1961 let objects =
1962 ReadableStreamObjects::from_byte_controller(OwnedBorrowMut::from_class(controller))
1963 .refresh_reader();
1964
1965 ReadableByteStreamController::readable_byte_stream_controller_respond(
1967 ctx,
1968 objects,
1969 bytes_written,
1970 )
1971 }
1972
1973 fn respond_with_new_view(
1974 ctx: Ctx<'js>,
1975 byob_request: This<OwnedBorrowMut<'js, Self>>,
1976 view: Opt<Value<'js>>,
1977 ) -> Result<()> {
1978 let controller = match &byob_request.controller {
1980 Some(controller) => controller.clone(),
1981 _ => {
1982 return Err(Exception::throw_type(
1983 &ctx,
1984 "This BYOB request has been invalidated",
1985 ));
1986 },
1987 };
1988 drop(byob_request);
1989
1990 let controller = OwnedBorrowMut::from_class(controller);
1991
1992 let view = ViewBytes::from_value(
1993 &ctx,
1994 &controller.function_array_buffer_is_view,
1995 view.0.as_ref(),
1996 )?;
1997
1998 let (buffer, _, _) = view.get_array_buffer()?;
1999
2000 if buffer.as_bytes().is_none() {
2002 return Err(Exception::throw_type(
2003 &ctx,
2004 "The given view's buffer has been detached and so cannot be used as a response",
2005 ));
2006 }
2007
2008 let objects = ReadableStreamObjects::from_byte_controller(controller).refresh_reader();
2009
2010 ReadableByteStreamController::readable_byte_stream_controller_respond_with_new_view(
2012 ctx, objects, view,
2013 )
2014 }
2015}
2016
2017#[derive(JsLifetime)]
2018pub(super) struct PullIntoDescriptor<'js> {
2019 buffer: ArrayBuffer<'js>,
2020 buffer_byte_length: usize,
2021 byte_offset: usize,
2022 byte_length: usize,
2023 bytes_filled: usize,
2024 minimum_fill: usize,
2025 element_size: usize,
2026 view_constructor: Constructor<'js>,
2027 reader_type: PullIntoDescriptorReaderType,
2028}
2029
2030impl<'js> Trace<'js> for PullIntoDescriptor<'js> {
2031 fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {
2032 self.buffer.trace(tracer);
2033 self.buffer_byte_length.trace(tracer);
2034 self.byte_offset.trace(tracer);
2035 self.byte_length.trace(tracer);
2036 self.bytes_filled.trace(tracer);
2037 self.minimum_fill.trace(tracer);
2038 self.element_size.trace(tracer);
2039 self.view_constructor.trace(tracer);
2040 self.reader_type.trace(tracer);
2041 }
2042}
2043
2044enum PullIntoDescriptorRefMut<'js, 'a> {
2045 Index(usize),
2046 Owned(&'a mut PullIntoDescriptor<'js>),
2047}
2048
2049#[derive(Trace, Clone, Copy)]
2050enum PullIntoDescriptorReaderType {
2051 Default,
2052 Byob,
2053 None,
2054}
2055
2056#[derive(JsLifetime)]
2057struct ReadableByteStreamQueueEntry<'js> {
2058 buffer: ArrayBuffer<'js>,
2059 byte_offset: usize,
2060 byte_length: usize,
2061}
2062
2063impl<'js> Trace<'js> for ReadableByteStreamQueueEntry<'js> {
2064 fn trace<'a>(&self, tracer: Tracer<'a, 'js>) {
2065 self.buffer.trace(tracer);
2066 self.byte_offset.trace(tracer);
2067 self.byte_length.trace(tracer)
2068 }
2069}
2070
2071fn transfer_array_buffer(buffer: ArrayBuffer<'_>) -> Result<ArrayBuffer<'_>> {
2072 buffer.get::<_, Function>("transfer")?.call((This(buffer),))
2073}
2074
2075fn copy_data_block_bytes(
2076 ctx: &Ctx<'_>,
2077 to_block: &ArrayBuffer,
2078 to_index: usize,
2079 from_block: &ArrayBuffer,
2080 from_index: usize,
2081 count: usize,
2082) -> Result<()> {
2083 let to_raw = to_block
2084 .as_raw()
2085 .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)
2086 .or_throw(ctx)?;
2087 let to_slice = unsafe { std::slice::from_raw_parts_mut(to_raw.ptr.as_ptr(), to_raw.len) };
2088 let from_raw = from_block
2089 .as_raw()
2090 .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED)
2091 .or_throw(ctx)?;
2092 let from_slice = unsafe { std::slice::from_raw_parts(from_raw.ptr.as_ptr(), from_raw.len) };
2093
2094 to_slice[to_index..to_index + count]
2095 .copy_from_slice(&from_slice[from_index..from_index + count]);
2096 Ok(())
2097}
2098
2099pub fn readable_byte_stream_controller_enqueue_bytes<'js>(
2103 ctx: Ctx<'js>,
2104 controller: ReadableByteStreamControllerClass<'js>,
2105 buffer: ArrayBuffer<'js>,
2106) -> Result<()> {
2107 readable_byte_stream_controller_enqueue_bytes_inner(ctx, controller, buffer, false)
2108}
2109
2110pub fn readable_byte_stream_controller_enqueue_bytes_borrowed<'js>(
2122 ctx: Ctx<'js>,
2123 controller: ReadableByteStreamControllerClass<'js>,
2124 buffer: ArrayBuffer<'js>,
2125) -> Result<()> {
2126 readable_byte_stream_controller_enqueue_bytes_inner(ctx, controller, buffer, true)
2127}
2128
2129fn readable_byte_stream_controller_enqueue_bytes_inner<'js>(
2130 ctx: Ctx<'js>,
2131 controller: ReadableByteStreamControllerClass<'js>,
2132 buffer: ArrayBuffer<'js>,
2133 skip_transfer: bool,
2134) -> Result<()> {
2135 let byte_length = buffer.len();
2136 if byte_length == 0 {
2137 return Ok(());
2138 }
2139 let view = rquickjs::TypedArray::<u8>::from_arraybuffer(buffer)?;
2140 let borrow = OwnedBorrowMut::from_class(controller);
2141 let chunk = ViewBytes::from_value(
2142 &ctx,
2143 &borrow.function_array_buffer_is_view,
2144 Some(&view.into_value()),
2145 )?;
2146 let objects = ReadableStreamObjects::from_byte_controller(borrow).refresh_reader();
2147 if skip_transfer {
2148 ReadableByteStreamController::readable_byte_stream_controller_enqueue_borrowed(
2149 &ctx, objects, chunk,
2150 )?;
2151 } else {
2152 ReadableByteStreamController::readable_byte_stream_controller_enqueue(
2153 &ctx, objects, chunk,
2154 )?;
2155 }
2156 Ok(())
2157}
2158
2159pub fn readable_byte_stream_controller_close_stream<'js>(
2161 ctx: Ctx<'js>,
2162 controller: ReadableByteStreamControllerClass<'js>,
2163) -> Result<()> {
2164 let borrow = OwnedBorrowMut::from_class(controller);
2165 let objects = ReadableStreamObjects::from_byte_controller(borrow).refresh_reader();
2166 ReadableByteStreamController::readable_byte_stream_controller_close(ctx, objects)?;
2167 Ok(())
2168}