1use crate::utils::option::{Null, Undefined};
2use rquickjs::{
3 class::{OwnedBorrow, OwnedBorrowMut, Trace},
4 methods,
5 prelude::{Opt, This},
6 Class, Ctx, Error, Exception, JsLifetime, Object, Promise, Result, Value,
7};
8use std::{future, pin::Pin, rc::Rc};
9
10pub enum NativePullResult<'js> {
13 Ready(Value<'js>),
15 Eof,
17 Pending(Pin<Box<dyn future::Future<Output = Result<Option<Value<'js>>>> + 'js>>),
19}
20
21pub type NativePullFn<'js> = dyn Fn(&Ctx<'js>) -> Result<NativePullResult<'js>> + 'js;
22
23pub struct NativePull<'js>(pub Rc<NativePullFn<'js>>);
25impl<'js> Clone for NativePull<'js> {
26 fn clone(&self) -> Self {
27 Self(self.0.clone())
28 }
29}
30unsafe impl<'js> JsLifetime<'js> for NativePull<'js> {
31 type Changed<'to> = NativePull<'to>;
32}
33impl<'js> Trace<'js> for NativePull<'js> {
34 fn trace<'a>(&self, _: rquickjs::class::Tracer<'a, 'js>) {}
35}
36
37use crate::stream_web::{
38 queuing_strategy::{SizeAlgorithm, SizeValue},
39 readable::{
40 byte_controller::ReadableByteStreamControllerOwned,
41 controller::{
42 ReadableStreamController, ReadableStreamControllerClass, ReadableStreamControllerOwned,
43 },
44 default_reader::{ReadableStreamDefaultReaderOrUndefined, ReadableStreamReadRequest},
45 objects::{
46 ReadableStreamClassObjects, ReadableStreamDefaultControllerObjects,
47 ReadableStreamDefaultReaderObjects, ReadableStreamObjects,
48 },
49 reader::ReadableStreamReader,
50 stream::{
51 algorithms::{CancelAlgorithm, PullAlgorithm, StartAlgorithm},
52 source::UnderlyingSource,
53 ReadableStream, ReadableStreamClass, ReadableStreamOwned, ReadableStreamState,
54 },
55 },
56 utils::{
57 class_from_owned_borrow_mut,
58 promise::{promise_resolved_with, upon_promise},
59 queue::QueueWithSizes,
60 UnwrapOrUndefined,
61 },
62};
63
64#[derive(JsLifetime, Trace)]
65#[rquickjs::class]
66pub struct ReadableStreamDefaultController<'js> {
67 cancel_algorithm: Option<CancelAlgorithm<'js>>,
68 pub(super) close_requested: bool,
69 pull_again: bool,
70 pull_algorithm: Option<PullAlgorithm<'js>>,
71 pub(crate) pulling: bool,
72 pub(crate) container: QueueWithSizes<'js>,
73 started: bool,
74 strategy_hwm: f64,
75 strategy_size_algorithm: Option<SizeAlgorithm<'js>>,
76 pub(super) stream: ReadableStreamClass<'js>,
77 pub native_pull: Option<NativePull<'js>>,
78 #[qjs(skip_trace)]
83 pub(super) is_owning_type: bool,
84}
85
86impl<'js> Drop for ReadableStreamDefaultController<'js> {
87 fn drop(&mut self) {
88 self.native_pull = None;
89 }
90}
91
92pub type ReadableStreamDefaultControllerClass<'js> =
93 Class<'js, ReadableStreamDefaultController<'js>>;
94pub(super) type ReadableStreamDefaultControllerOwned<'js> =
95 OwnedBorrowMut<'js, ReadableStreamDefaultController<'js>>;
96
97impl<'js> ReadableStreamDefaultController<'js> {
98 pub(super) fn set_up_readable_stream_default_controller_from_underlying_source(
99 ctx: Ctx<'js>,
100 stream: ReadableStreamOwned<'js>,
101 underlying_source: Null<Undefined<Object<'js>>>,
102 underlying_source_dict: UnderlyingSource<'js>,
103 high_water_mark: f64,
104 size_algorithm: SizeAlgorithm<'js>,
105 is_owning_type: bool,
106 ) -> Result<()> {
107 let (start_algorithm, pull_algorithm, cancel_algorithm) = (
108 underlying_source_dict
111 .start
112 .map(|f| StartAlgorithm::Function {
113 f,
114 underlying_source: underlying_source.clone(),
115 })
116 .unwrap_or(StartAlgorithm::ReturnUndefined),
117 underlying_source_dict
120 .pull
121 .map(|f| PullAlgorithm::Function {
122 f,
123 underlying_source: underlying_source.clone(),
124 })
125 .unwrap_or(PullAlgorithm::ReturnPromiseUndefined),
126 underlying_source_dict
129 .cancel
130 .map(|f| CancelAlgorithm::Function {
131 f,
132 underlying_source,
133 })
134 .unwrap_or(CancelAlgorithm::ReturnPromiseUndefined),
135 );
136
137 Self::set_up_readable_stream_default_controller(
139 ctx.clone(),
140 stream,
141 start_algorithm,
142 pull_algorithm,
143 cancel_algorithm,
144 high_water_mark,
145 size_algorithm,
146 is_owning_type,
147 )?;
148
149 Ok(())
150 }
151
152 #[allow(clippy::too_many_arguments)]
153 pub(super) fn set_up_readable_stream_default_controller(
154 ctx: Ctx<'js>,
155 stream: ReadableStreamOwned<'js>,
156 start_algorithm: StartAlgorithm<'js>,
157 pull_algorithm: PullAlgorithm<'js>,
158 cancel_algorithm: CancelAlgorithm<'js>,
159 high_water_mark: f64,
160 size_algorithm: SizeAlgorithm<'js>,
161 is_owning_type: bool,
162 ) -> Result<Class<'js, Self>> {
163 let (stream_class, mut stream) = class_from_owned_borrow_mut(stream);
164
165 let controller = ReadableStreamDefaultController {
166 stream: stream_class.clone(),
168
169 container: QueueWithSizes::new(),
171
172 started: false,
174 close_requested: false,
175 pull_again: false,
176 pulling: false,
177
178 strategy_size_algorithm: Some(size_algorithm),
180 strategy_hwm: high_water_mark,
181
182 pull_algorithm: Some(pull_algorithm),
184 cancel_algorithm: Some(cancel_algorithm),
186 native_pull: None,
187 is_owning_type,
188 };
189
190 let controller_class = Class::instance(ctx.clone(), controller)?;
191
192 stream.controller = ReadableStreamControllerClass::ReadableStreamDefaultController(
194 controller_class.clone(),
195 );
196
197 let objects = ReadableStreamObjects::new_default(
198 stream,
199 OwnedBorrowMut::from_class(controller_class),
200 );
201
202 let promise_primordials = objects.stream.promise_primordials.clone();
203
204 let (start_result, objects_class) =
206 Self::start_algorithm(ctx.clone(), objects, start_algorithm)?;
207
208 let start_promise = promise_resolved_with(&ctx, &promise_primordials, Ok(start_result))?;
210
211 let _ = upon_promise::<Value<'js>, _>(ctx.clone(), start_promise, {
212 let objects_class = objects_class.clone();
213 move |ctx, result| {
214 let mut objects =
215 ReadableStreamObjects::from_class_no_reader(objects_class).refresh_reader();
216
217 match result {
218 Ok(_) => {
220 objects.controller.started = true;
222 Self::readable_stream_default_controller_call_pull_if_needed(ctx, objects)?;
224 },
225 Err(r) => {
227 Self::readable_stream_default_controller_error(objects, r)?;
229 },
230 }
231 Ok(())
232 }
233 })?;
234
235 Ok(objects_class.controller)
236 }
237
238 fn readable_stream_default_controller_call_pull_if_needed<
239 R: ReadableStreamDefaultReaderOrUndefined<'js>,
240 >(
241 ctx: Ctx<'js>,
242 objects: ReadableStreamDefaultControllerObjects<'js, R>,
243 ) -> Result<ReadableStreamDefaultControllerObjects<'js, R>> {
244 let (should_pull, mut objects) =
247 ReadableStreamDefaultController::readable_stream_default_controller_should_call_pull(
248 objects,
249 );
250
251 if !should_pull {
253 return Ok(objects);
254 }
255
256 if objects.controller.pulling {
258 objects.controller.pull_again = true;
260
261 return Ok(objects);
263 }
264
265 objects.controller.pulling = true;
267
268 let (pull_promise, objects_class) = Self::pull_algorithm(ctx.clone(), objects)?;
270
271 upon_promise::<Value<'js>, _>(ctx.clone(), pull_promise, {
272 let objects_class = objects_class.clone();
273 move |ctx, result| {
274 let mut objects =
275 ReadableStreamObjects::from_class_no_reader(objects_class).refresh_reader();
276 match result {
277 Ok(_) => {
279 objects.controller.pulling = false;
281 if objects.controller.pull_again {
283 objects.controller.pull_again = false;
285 Self::readable_stream_default_controller_call_pull_if_needed(
287 ctx, objects,
288 )?;
289 };
290 Ok(())
291 },
292 Err(e) => {
294 Self::readable_stream_default_controller_error(objects, e)?;
296 Ok(())
297 },
298 }
299 }
300 })?;
301
302 Ok(ReadableStreamObjects::from_class(objects_class))
303 }
304
305 pub(super) fn readable_stream_default_controller_error<R: ReadableStreamReader<'js>>(
306 mut objects: ReadableStreamDefaultControllerObjects<'js, R>,
308 e: Value<'js>,
309 ) -> Result<ReadableStreamDefaultControllerObjects<'js, R>> {
310 if !matches!(objects.stream.state, ReadableStreamState::Readable) {
312 return Ok(objects);
313 };
314
315 objects.controller.container.reset_queue();
317
318 objects
320 .controller
321 .readable_stream_default_controller_clear_algorithms();
322
323 ReadableStream::readable_stream_error(objects, e)
325 }
326
327 fn readable_stream_default_controller_should_call_pull<
328 R: ReadableStreamDefaultReaderOrUndefined<'js>,
329 >(
330 mut objects: ReadableStreamDefaultControllerObjects<'js, R>,
331 ) -> (bool, ReadableStreamDefaultControllerObjects<'js, R>) {
332 if !objects
335 .controller
336 .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)
337 {
338 return (false, objects);
339 }
340
341 if !objects.controller.started {
343 return (false, objects);
344 }
345
346 {
347 let mut ret = false;
348 objects = objects
350 .with_some_reader(
351 |objects| {
352 if ReadableStream::readable_stream_get_num_read_requests(&objects.reader)
353 > 0
354 {
355 ret = true
356 }
357 Ok(objects)
358 },
359 Ok,
360 )
361 .unwrap();
362 if ret {
363 return (true, objects);
364 }
365 }
366
367 let desired_size = objects.controller
369 .readable_stream_default_controller_get_desired_size(&objects.stream)
370 .0
371 .expect(
372 "desiredSize should not be null during ReadableStreamDefaultControllerShouldCallPull",
373 );
374 if desired_size > 0.0 {
376 return (true, objects);
377 }
378
379 (false, objects)
381 }
382
383 fn readable_stream_default_controller_clear_algorithms(&mut self) {
384 self.pull_algorithm = None;
385 self.cancel_algorithm = None;
386 self.strategy_size_algorithm = None;
387 self.native_pull = None;
388 }
389
390 fn readable_stream_default_controller_can_close_or_enqueue(
391 &self,
392 stream: &ReadableStream<'js>,
393 ) -> bool {
394 match stream.state {
396 ReadableStreamState::Readable if !self.close_requested => true,
398 _ => false,
400 }
401 }
402
403 pub(crate) fn readable_stream_default_controller_get_desired_size(
404 &self,
405 stream: &ReadableStream<'js>,
406 ) -> Null<f64> {
407 match stream.state {
409 ReadableStreamState::Errored(_) => Null(None),
411 ReadableStreamState::Closed => Null(Some(0.0)),
413 ReadableStreamState::Readable => {
415 Null(Some(self.strategy_hwm - self.container.queue_total_size))
416 },
417 }
418 }
419
420 pub(super) fn readable_stream_default_controller_close<R: ReadableStreamReader<'js>>(
421 ctx: Ctx<'js>,
422 mut objects: ReadableStreamDefaultControllerObjects<'js, R>,
424 ) -> Result<ReadableStreamDefaultControllerObjects<'js, R>> {
425 if !objects
427 .controller
428 .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)
429 {
430 return Ok(objects);
431 }
432
433 objects.controller.close_requested = true;
435
436 if objects.controller.container.queue.is_empty() {
438 objects
440 .controller
441 .readable_stream_default_controller_clear_algorithms();
442 objects = ReadableStream::readable_stream_close(ctx, objects)?;
444 }
445
446 Ok(objects)
447 }
448
449 pub(super) fn readable_stream_default_controller_enqueue<
450 R: ReadableStreamDefaultReaderOrUndefined<'js>,
451 >(
452 ctx: Ctx<'js>,
453 mut objects: ReadableStreamDefaultControllerObjects<'js, R>,
455 chunk: Value<'js>,
456 ) -> Result<ReadableStreamDefaultControllerObjects<'js, R>> {
457 if !objects
459 .controller
460 .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)
461 {
462 return Ok(objects);
463 }
464
465 let mut els = true;
466 objects = objects.with_some_reader(
468 |objects| {
469 if ReadableStream::readable_stream_get_num_read_requests(&objects.reader) > 0 {
470 els = false;
471 ReadableStream::readable_stream_fulfill_read_request(
472 &ctx,
473 objects,
474 chunk.clone(),
475 false,
476 )
477 } else {
478 Ok(objects)
479 }
480 },
481 Ok,
482 )?;
483
484 if els {
485 let (result, objects_class) =
487 Self::strategy_size_algorithm(ctx.clone(), objects, chunk.clone());
488
489 objects = ReadableStreamObjects::from_class(objects_class);
490
491 match result {
492 Err(Error::Exception) => {
494 let err = ctx.catch();
495 Self::readable_stream_default_controller_error(objects, err.clone())?;
497
498 return Err(ctx.throw(err));
499 },
500 Ok(chunk_size) => {
502 let enqueue_result = objects
504 .controller
505 .container
506 .enqueue_value_with_size(&ctx, chunk, chunk_size);
507
508 match enqueue_result {
509 Err(Error::Exception) => {
511 let err = ctx.catch();
512 Self::readable_stream_default_controller_error(objects, err.clone())?;
514 return Err(ctx.throw(err));
515 },
516 Err(err) => return Err(err),
517 Ok(()) => {},
518 }
519 },
520 Err(err) => return Err(err),
521 }
522 }
523
524 Self::readable_stream_default_controller_call_pull_if_needed(ctx, objects)
526 }
527
528 fn start_algorithm<R: ReadableStreamReader<'js>>(
529 ctx: Ctx<'js>,
530 objects: ReadableStreamDefaultControllerObjects<'js, R>,
531 start_algorithm: StartAlgorithm<'js>,
532 ) -> Result<(
533 Value<'js>,
534 ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,
535 )> {
536 let objects_class = objects.into_inner();
537
538 Ok((
539 start_algorithm.call(
540 ctx,
541 ReadableStreamControllerClass::ReadableStreamDefaultController(
542 objects_class.controller.clone(),
543 ),
544 )?,
545 objects_class,
546 ))
547 }
548
549 fn pull_algorithm<R: ReadableStreamReader<'js>>(
550 ctx: Ctx<'js>,
551 objects: ReadableStreamDefaultControllerObjects<'js, R>,
552 ) -> Result<(
553 Promise<'js>,
554 ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,
555 )> {
556 let pull_algorithm = objects
557 .controller
558 .pull_algorithm
559 .clone()
560 .expect("pull algorithm used after ReadableStreamDefaultControllerClearAlgorithms");
561 let promise_primordials = objects.stream.promise_primordials.clone();
562 let objects_class = objects.into_inner();
563
564 Ok((
565 pull_algorithm.call(
566 ctx,
567 &promise_primordials,
568 ReadableStreamControllerClass::ReadableStreamDefaultController(
569 objects_class.controller.clone(),
570 ),
571 )?,
572 objects_class,
573 ))
574 }
575
576 fn strategy_size_algorithm<R: ReadableStreamReader<'js>>(
577 ctx: Ctx<'js>,
578 objects: ReadableStreamDefaultControllerObjects<'js, R>,
579 chunk: Value<'js>,
580 ) -> (
581 Result<SizeValue<'js>>,
582 ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,
583 ) {
584 let strategy_size_algorithm = objects
585 .controller
586 .strategy_size_algorithm
587 .clone()
588 .expect("size algorithm used after ReadableStreamDefaultControllerClearAlgorithms");
589 let objects_class = objects.into_inner();
590
591 (strategy_size_algorithm.call(ctx, chunk), objects_class)
592 }
593
594 pub(super) fn cancel_algorithm<R: ReadableStreamReader<'js>>(
595 ctx: Ctx<'js>,
596 objects: ReadableStreamDefaultControllerObjects<'js, R>,
597 reason: Value<'js>,
598 ) -> Result<(
599 Promise<'js>,
600 ReadableStreamClassObjects<'js, OwnedBorrowMut<'js, Self>, R>,
601 )> {
602 let cancel_algorithm =
603 objects.controller.cancel_algorithm.clone().expect(
604 "cancel algorithm used after ReadableStreamDefaultControllerClearAlgorithms",
605 );
606 let promise_primordials = objects.stream.promise_primordials.clone();
607 let objects_class = objects.into_inner();
608
609 Ok((
610 cancel_algorithm.call(ctx, &promise_primordials, reason)?,
611 objects_class,
612 ))
613 }
614}
615
616#[methods(rename_all = "camelCase")]
617impl<'js> ReadableStreamDefaultController<'js> {
618 fn constructor() -> Self {
620 unimplemented!()
621 }
622
623 #[qjs(constructor)]
624 fn new(ctx: Ctx<'js>) -> Result<Class<'js, Self>> {
625 Err(Exception::throw_type(&ctx, "Illegal constructor"))
626 }
627
628 #[qjs(get)]
630 fn desired_size(&self) -> Null<f64> {
631 let stream = OwnedBorrow::from_class(self.stream.clone());
632 self.readable_stream_default_controller_get_desired_size(&stream)
633 }
634
635 fn close(ctx: Ctx<'js>, controller: This<OwnedBorrowMut<'js, Self>>) -> Result<()> {
637 let objects = ReadableStreamObjects::from_default_controller(controller.0);
638
639 if !objects
641 .controller
642 .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)
643 {
644 return Err(Exception::throw_type(
645 &ctx,
646 "The stream is not in a state that permits close",
647 ));
648 }
649
650 Self::readable_stream_default_controller_close(ctx, objects)?;
652 Ok(())
653 }
654
655 fn enqueue(
657 ctx: Ctx<'js>,
658 controller: This<OwnedBorrowMut<'js, Self>>,
659 chunk: Opt<Value<'js>>,
660 options: Opt<Value<'js>>,
661 ) -> Result<()> {
662 let mut transfer_list: Option<rquickjs::Array<'js>> = None;
669 if let Some(opts) = options.0.as_ref().and_then(|v| v.as_object()) {
670 transfer_list = opts.get::<_, Option<rquickjs::Array<'js>>>("transfer")?;
671 }
672 let has_transfer_items = transfer_list.as_ref().is_some_and(|arr| !arr.is_empty());
673 if has_transfer_items && !controller.is_owning_type {
674 return Err(Exception::throw_type(&ctx, "transfer list is not empty"));
675 }
676 let chunk_value = chunk.0.clone().unwrap_or_undefined(&ctx);
681 let transferred_chunk = if has_transfer_items && controller.is_owning_type {
682 transfer_owning_chunk(&ctx, chunk_value.clone(), &transfer_list.unwrap())?
683 } else {
684 chunk_value
685 };
686
687 let objects = ReadableStreamObjects::from_default_controller(controller.0);
688
689 if !objects
691 .controller
692 .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)
693 {
694 return Err(Exception::throw_type(
695 &ctx,
696 "The stream is not in a state that permits enqueue",
697 ));
698 }
699
700 objects.with_reader(
701 |objects| {
702 Self::readable_stream_default_controller_enqueue(
704 ctx.clone(),
705 objects,
706 transferred_chunk.clone(),
707 )
708 },
709 |_| panic!("Default controller must not have byob reader"),
710 |objects| {
711 Self::readable_stream_default_controller_enqueue(
713 ctx.clone(),
714 objects,
715 transferred_chunk.clone(),
716 )
717 },
718 )?;
719
720 Ok(())
721 }
722
723 fn error(
725 ctx: Ctx<'js>,
726 controller: This<OwnedBorrowMut<'js, Self>>,
727 e: Opt<Value<'js>>,
728 ) -> Result<()> {
729 let objects = ReadableStreamObjects::from_default_controller(controller.0);
730
731 Self::readable_stream_default_controller_error(objects, e.0.unwrap_or_undefined(&ctx))?;
733 Ok(())
734 }
735}
736
737impl<'js> ReadableStreamController<'js> for ReadableStreamDefaultControllerOwned<'js> {
738 type Class = ReadableStreamDefaultControllerClass<'js>;
739
740 fn with_controller<C, O>(
741 self,
742 ctx: C,
743 default: impl FnOnce(
744 C,
745 ReadableStreamDefaultControllerOwned<'js>,
746 ) -> Result<(O, ReadableStreamDefaultControllerOwned<'js>)>,
747 _: impl FnOnce(
748 C,
749 ReadableByteStreamControllerOwned<'js>,
750 ) -> Result<(O, ReadableByteStreamControllerOwned<'js>)>,
751 ) -> Result<(O, Self)> {
752 let (ctx, reader) = default(ctx, self)?;
753 Ok((ctx, reader))
754 }
755
756 fn into_inner(self) -> Self::Class {
757 OwnedBorrowMut::into_inner(self)
758 }
759
760 fn from_class(class: Self::Class) -> Self {
761 OwnedBorrowMut::from_class(class)
762 }
763
764 fn into_erased(self) -> ReadableStreamControllerOwned<'js> {
765 ReadableStreamControllerOwned::ReadableStreamDefaultController(self)
766 }
767
768 fn try_from_erased(erased: ReadableStreamControllerOwned<'js>) -> Option<Self> {
769 match erased {
770 ReadableStreamControllerOwned::ReadableStreamDefaultController(r) => Some(r),
771 ReadableStreamControllerOwned::ReadableStreamByteController(_) => None,
772 }
773 }
774
775 fn pull_steps(
776 ctx: &Ctx<'js>,
777 mut objects: ReadableStreamDefaultReaderObjects<'js, Self>,
778 read_request: impl ReadableStreamReadRequest<'js> + 'js,
779 ) -> Result<ReadableStreamDefaultReaderObjects<'js, Self>> {
780 if !objects.controller.container.queue.is_empty() {
782 let chunk = objects.controller.container.dequeue_value();
784 if objects.controller.close_requested && objects.controller.container.queue.is_empty() {
786 objects
788 .controller
789 .readable_stream_default_controller_clear_algorithms();
790 objects = ReadableStream::readable_stream_close(ctx.clone(), objects)?;
792 } else {
793 objects =
795 ReadableStreamDefaultController::readable_stream_default_controller_call_pull_if_needed(
796 ctx.clone(),
797 objects,
798 )?;
799 }
800
801 read_request.chunk_steps_typed(objects, chunk)
803 } else {
804 objects
807 .stream
808 .readable_stream_add_read_request(&mut objects.reader, read_request);
809 ReadableStreamDefaultController::readable_stream_default_controller_call_pull_if_needed(
812 ctx.clone(),
813 objects,
814 )
815 }
816 }
817
818 fn cancel_steps<R: ReadableStreamReader<'js>>(
819 ctx: &Ctx<'js>,
820 mut objects: ReadableStreamObjects<'js, Self, R>,
821 reason: Value<'js>,
822 ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, Self, R>)> {
823 objects.controller.container.reset_queue();
825
826 let (result, objects_class) =
828 ReadableStreamDefaultController::cancel_algorithm(ctx.clone(), objects, reason)?;
829
830 objects = ReadableStreamObjects::from_class(objects_class);
831 objects
833 .controller
834 .readable_stream_default_controller_clear_algorithms();
835
836 Ok((result, objects))
838 }
839
840 fn release_steps(&mut self) {}
841}
842
843pub fn readable_stream_default_controller_enqueue_value<'js>(
845 ctx: Ctx<'js>,
846 controller: ReadableStreamDefaultControllerClass<'js>,
847 chunk: Value<'js>,
848) -> Result<()> {
849 let objects =
850 ReadableStreamObjects::from_default_controller(OwnedBorrowMut::from_class(controller));
851
852 if !objects
853 .controller
854 .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)
855 {
856 return Ok(()); }
858
859 objects.with_reader(
860 |objects| {
861 ReadableStreamDefaultController::readable_stream_default_controller_enqueue(
862 ctx.clone(),
863 objects,
864 chunk.clone(),
865 )
866 },
867 |_| panic!("Default controller must not have byob reader"),
868 |objects| {
869 ReadableStreamDefaultController::readable_stream_default_controller_enqueue(
870 ctx.clone(),
871 objects,
872 chunk.clone(),
873 )
874 },
875 )?;
876
877 Ok(())
878}
879
880pub fn readable_stream_default_controller_close_stream<'js>(
882 ctx: Ctx<'js>,
883 controller: ReadableStreamDefaultControllerClass<'js>,
884) -> Result<()> {
885 let objects =
886 ReadableStreamObjects::from_default_controller(OwnedBorrowMut::from_class(controller));
887
888 if !objects
889 .controller
890 .readable_stream_default_controller_can_close_or_enqueue(&objects.stream)
891 {
892 return Ok(());
893 }
894
895 ReadableStreamDefaultController::readable_stream_default_controller_close(ctx, objects)?;
896 Ok(())
897}
898
899pub fn readable_stream_default_controller_error_stream<'js>(
901 controller: ReadableStreamDefaultControllerClass<'js>,
902 error: Value<'js>,
903) -> Result<()> {
904 let objects =
905 ReadableStreamObjects::from_default_controller(OwnedBorrowMut::from_class(controller));
906
907 objects.with_reader(
908 |objects| {
909 ReadableStreamDefaultController::readable_stream_default_controller_error(
910 objects,
911 error.clone(),
912 )
913 },
914 |_| panic!("Default controller must not have byob reader"),
915 |objects| {
916 ReadableStreamDefaultController::readable_stream_default_controller_error(
917 objects,
918 error.clone(),
919 )
920 },
921 )?;
922
923 Ok(())
924}
925
926fn transfer_owning_chunk<'js>(
931 ctx: &Ctx<'js>,
932 chunk: Value<'js>,
933 transfer_list: &rquickjs::Array<'js>,
934) -> Result<Value<'js>> {
935 use rquickjs::ArrayBuffer;
936 let mut chunk_replacement: Option<Value<'js>> = None;
937 for v in transfer_list.iter::<Value<'js>>() {
938 let v = v?;
939 let Some(ab) = ArrayBuffer::from_value(v.clone()) else {
940 return Err(rquickjs::Exception::throw_type(
941 ctx,
942 "transfer list item is not an ArrayBuffer",
943 ));
944 };
945 let is_chunk = chunk == v;
950 let transfer_fn: rquickjs::Function<'js> = ab.as_object().get("transfer")?;
953 let new_buf: Value<'js> = transfer_fn.call((rquickjs::function::This(ab.clone()),))?;
954 if is_chunk && chunk_replacement.is_none() {
955 chunk_replacement = Some(new_buf);
956 }
957 }
958 Ok(chunk_replacement.unwrap_or(chunk))
959}