1use std::cell::Cell;
6use std::collections::VecDeque;
7use std::mem;
8use std::rc::Rc;
9
10use dom_struct::dom_struct;
11use js::context::JSContext;
12use js::gc::CustomAutoRooterGuard;
13use js::jsapi::Heap;
14use js::jsval::{JSVal, UndefinedValue};
15use js::realm::CurrentRealm;
16use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue};
17use js::typedarray::{ArrayBufferView, ArrayBufferViewU8};
18use script_bindings::cell::DomRefCell;
19use script_bindings::reflector::{Reflector, reflect_dom_object, reflect_dom_object_with_proto};
20use script_bindings::root::Dom;
21
22use super::byteteereadintorequest::ByteTeeReadIntoRequest;
23use super::readablebytestreamcontroller::ReadableByteStreamController;
24use super::readablestreamgenericreader::ReadableStreamGenericReader;
25use crate::dom::bindings::buffer_source::HeapBufferSource;
26use crate::dom::bindings::codegen::Bindings::ReadableStreamBYOBReaderBinding::{
27 ReadableStreamBYOBReaderMethods, ReadableStreamBYOBReaderReadOptions,
28};
29use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultReaderBinding::ReadableStreamReadResult;
30use crate::dom::bindings::error::{Error, ErrorToJsval, Fallible};
31use crate::dom::bindings::reflector::DomGlobal;
32use crate::dom::bindings::root::{DomRoot, MutNullableDom};
33use crate::dom::bindings::trace::RootedTraceableBox;
34use crate::dom::globalscope::GlobalScope;
35use crate::dom::promise::{Promise, RootedPromise, TracedPromise};
36use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler};
37use crate::dom::stream::readablestream::ReadableStream;
38use crate::realms::enter_auto_realm;
39
40#[derive(Clone, JSTraceable, MallocSizeOf)]
42#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
43pub enum ReadIntoRequest {
44 Read(TracedPromise),
46 ByteTee {
47 byte_tee_read_into_request: Dom<ByteTeeReadIntoRequest>,
48 },
49}
50
51impl js::gc::Rootable for ReadIntoRequest {}
52
53impl ReadIntoRequest {
54 pub fn chunk_steps(&self, cx: &mut JSContext, chunk: RootedTraceableBox<Heap<JSVal>>) {
56 match self {
57 ReadIntoRequest::Read(promise) => {
58 promise.resolve_native(
61 cx,
62 &ReadableStreamReadResult {
63 done: Some(false),
64 value: chunk.into_box(),
65 },
66 );
67 },
68 ReadIntoRequest::ByteTee {
69 byte_tee_read_into_request,
70 } => {
71 rooted!(&in(cx) let chunk_object = chunk.get().to_object());
72 byte_tee_read_into_request.enqueue_chunk_steps(
73 cx,
74 RootedTraceableBox::new(HeapBufferSource::<ArrayBufferViewU8>::new(
75 chunk_object.handle(),
76 )),
77 )
78 },
79 }
80 }
81
82 pub fn close_steps(&self, cx: &mut JSContext, chunk: Option<RootedTraceableBox<Heap<JSVal>>>) {
84 match self {
85 ReadIntoRequest::Read(promise) => match chunk {
86 Some(chunk) => promise.resolve_native(
89 cx,
90 &ReadableStreamReadResult {
91 done: Some(true),
92 value: chunk.into_box(),
93 },
94 ),
95 None => {
96 promise.resolve_native(
97 cx,
98 &ReadableStreamReadResult {
99 done: Some(true),
100 value: Heap::boxed(UndefinedValue()),
101 },
102 );
103 },
104 },
105 ReadIntoRequest::ByteTee {
106 byte_tee_read_into_request,
107 } => match chunk {
108 Some(chunk) => {
109 rooted!(&in(cx) let chunk_object = chunk.get().to_object());
110 byte_tee_read_into_request
111 .close_steps(
112 cx,
113 Some(RootedTraceableBox::new(
114 HeapBufferSource::<ArrayBufferViewU8>::new(chunk_object.handle()),
115 )),
116 )
117 .expect("close steps should not fail")
118 },
119 None => byte_tee_read_into_request
120 .close_steps(cx, None)
121 .expect("close steps should not fail"),
122 },
123 }
124 }
125
126 pub(crate) fn error_steps(&self, cx: &mut JSContext, e: SafeHandleValue) {
128 match self {
129 ReadIntoRequest::Read(promise) => {
130 promise.reject_native(cx, &e)
133 },
134 ReadIntoRequest::ByteTee {
135 byte_tee_read_into_request,
136 } => {
137 byte_tee_read_into_request.error_steps();
138 },
139 }
140 }
141}
142
143#[derive(Clone, JSTraceable, MallocSizeOf)]
146#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
147struct ByteTeeClosedPromiseRejectionHandler {
148 branch_1_controller: Dom<ReadableByteStreamController>,
149 branch_2_controller: Dom<ReadableByteStreamController>,
150 #[conditional_malloc_size_of]
151 canceled_1: Rc<Cell<bool>>,
152 #[conditional_malloc_size_of]
153 canceled_2: Rc<Cell<bool>>,
154 cancel_promise: TracedPromise,
155 #[conditional_malloc_size_of]
156 reader_version: Rc<Cell<u64>>,
157 expected_version: u64,
158}
159
160impl Callback for ByteTeeClosedPromiseRejectionHandler {
161 fn callback(&self, cx: &mut CurrentRealm, v: SafeHandleValue) {
164 if self.reader_version.get() != self.expected_version {
166 return;
167 }
168
169 self.branch_1_controller.error(cx, v);
171
172 self.branch_2_controller.error(cx, v);
174
175 if !self.canceled_1.get() || !self.canceled_2.get() {
177 self.cancel_promise.resolve_native(cx, &());
178 }
179 }
180}
181
182#[dom_struct]
184pub(crate) struct ReadableStreamBYOBReader {
185 reflector_: Reflector,
186
187 stream: MutNullableDom<ReadableStream>,
189
190 read_into_requests: DomRefCell<VecDeque<ReadIntoRequest>>,
191
192 closed_promise: DomRefCell<TracedPromise>,
194}
195
196impl ReadableStreamBYOBReader {
197 fn new_with_proto(
198 cx: &mut JSContext,
199 global: &GlobalScope,
200 proto: Option<SafeHandleObject>,
201 ) -> DomRoot<ReadableStreamBYOBReader> {
202 let closed_promise = Promise::new(cx, global);
203 reflect_dom_object_with_proto(
204 cx,
205 Box::new(ReadableStreamBYOBReader::new_inherited(&closed_promise)),
206 global,
207 proto,
208 )
209 }
210
211 fn new_inherited(promise: &RootedPromise) -> ReadableStreamBYOBReader {
212 ReadableStreamBYOBReader {
213 reflector_: Reflector::new(),
214 stream: MutNullableDom::new(None),
215 read_into_requests: DomRefCell::new(Default::default()),
216 closed_promise: DomRefCell::new(promise.to_traced()),
217 }
218 }
219
220 pub(crate) fn new(
221 cx: &mut JSContext,
222 global: &GlobalScope,
223 ) -> DomRoot<ReadableStreamBYOBReader> {
224 let closed_promise = Promise::new(cx, global);
225 reflect_dom_object(cx, Box::new(Self::new_inherited(&closed_promise)), global)
226 }
227
228 pub(crate) fn set_up(
230 &self,
231 cx: &mut JSContext,
232 stream: &ReadableStream,
233 global: &GlobalScope,
234 ) -> Fallible<()> {
235 if stream.is_locked() {
237 return Err(Error::Type(c"stream is locked".to_owned()));
238 }
239
240 if !stream.has_byte_controller() {
242 return Err(Error::Type(
243 c"stream controller is not a byte stream controller".to_owned(),
244 ));
245 }
246
247 self.generic_initialize(cx, global, stream);
249
250 self.read_into_requests.borrow_mut().clear();
252
253 Ok(())
254 }
255
256 pub(crate) fn release(&self, cx: &mut JSContext) -> Fallible<()> {
258 self.generic_release(cx).expect("Generic release failed");
260 rooted!(&in(cx) let mut error = UndefinedValue());
262 Error::Type(c"Reader is released".to_owned()).to_jsval(
263 cx,
264 &self.global(),
265 error.handle_mut(),
266 );
267
268 self.error_read_into_requests(cx, error.handle());
270 Ok(())
271 }
272
273 pub(crate) fn error_read_into_requests(&self, cx: &mut JSContext, e: SafeHandleValue) {
275 self.closed_promise.borrow().reject_native(cx, &e);
277
278 self.closed_promise.borrow().set_promise_is_handled(cx);
280
281 rooted!(&in(cx) let read_into_requests = self.take_read_into_requests());
283
284 for request in read_into_requests.iter() {
286 request.error_steps(cx, e);
288 }
289 }
290
291 fn take_read_into_requests(&self) -> VecDeque<ReadIntoRequest> {
292 mem::take(&mut *self.read_into_requests.borrow_mut())
293 }
294
295 pub(crate) fn add_read_into_request(&self, read_request: &ReadIntoRequest) {
297 self.read_into_requests
298 .borrow_mut()
299 .push_back(read_request.clone());
300 }
301
302 pub(crate) fn cancel(&self, cx: &mut JSContext) {
304 rooted!(&in(cx) let read_into_requests = self.take_read_into_requests());
307 for request in read_into_requests.iter() {
310 request.close_steps(cx, None);
312 }
313 }
314
315 pub(crate) fn close(&self, cx: &mut JSContext) {
316 self.closed_promise.borrow().resolve_native(cx, &());
318 }
319
320 pub(crate) fn read(
322 &self,
323 cx: &mut JSContext,
324 view: &HeapBufferSource<ArrayBufferViewU8>,
325 min: u64,
326 read_into_request: &ReadIntoRequest,
327 ) {
328 assert!(self.stream.get().is_some());
332
333 let stream = self.stream.get().unwrap();
334
335 stream.set_is_disturbed(true);
337 if stream.is_errored() {
339 rooted!(&in(cx) let mut error = UndefinedValue());
340 stream.get_stored_error(error.handle_mut());
341
342 read_into_request.error_steps(cx, error.handle());
343 } else {
344 stream.perform_pull_into(cx, read_into_request, view, min);
347 }
348 }
349
350 pub(crate) fn get_num_read_into_requests(&self) -> usize {
351 self.read_into_requests.borrow().len()
352 }
353
354 pub(crate) fn remove_read_into_request(&self) -> ReadIntoRequest {
355 self.read_into_requests
356 .borrow_mut()
357 .pop_front()
358 .expect("read into requests is empty")
359 }
360
361 #[allow(clippy::too_many_arguments)]
362 pub(crate) fn byte_tee_append_native_handler_to_closed_promise(
363 &self,
364 cx: &mut JSContext,
365 branch_1: &ReadableStream,
366 branch_2: &ReadableStream,
367 canceled_1: Rc<Cell<bool>>,
368 canceled_2: Rc<Cell<bool>>,
369 cancel_promise: &RootedPromise,
370 reader_version: Rc<Cell<u64>>,
371 expected_version: u64,
372 ) {
373 let branch_1_controller = branch_1.get_byte_controller();
374
375 let branch_2_controller = branch_2.get_byte_controller();
376
377 let global = self.global();
378 let handler = PromiseNativeHandler::new(
379 cx,
380 &global,
381 None,
382 Some(Box::new(ByteTeeClosedPromiseRejectionHandler {
383 branch_1_controller: Dom::from_ref(&branch_1_controller),
384 branch_2_controller: Dom::from_ref(&branch_2_controller),
385 canceled_1,
386 canceled_2,
387 cancel_promise: cancel_promise.to_traced(),
388 reader_version,
389 expected_version,
390 })),
391 );
392
393 let mut realm = enter_auto_realm(cx, &*global);
394 let cx = &mut realm.current_realm();
395
396 self.closed_promise
397 .borrow()
398 .append_native_handler(cx, &handler);
399 }
400}
401
402impl ReadableStreamBYOBReaderMethods<crate::DomTypeHolder> for ReadableStreamBYOBReader {
403 fn Constructor(
405 cx: &mut JSContext,
406 global: &GlobalScope,
407 proto: Option<SafeHandleObject>,
408 stream: &ReadableStream,
409 ) -> Fallible<DomRoot<Self>> {
410 let reader = Self::new_with_proto(cx, global, proto);
411
412 reader.set_up(cx, stream, global)?;
414
415 Ok(reader)
416 }
417
418 fn Read(
420 &self,
421 cx: &mut JSContext,
422 view: CustomAutoRooterGuard<ArrayBufferView>,
423 options: &ReadableStreamBYOBReaderReadOptions,
424 ) -> RootedPromise {
425 let view = HeapBufferSource::<ArrayBufferViewU8>::from_view(cx, view);
426 let min = options.min;
427 let promise = Promise::new(cx, &self.global());
429
430 if view.byte_length() == 0 {
432 promise.reject_error(cx, Error::Type(c"view byte length is 0".to_owned()));
433 return promise;
434 }
435 if view.viewed_buffer_array_byte_length(cx) == 0 {
438 promise.reject_error(
439 cx,
440 Error::Type(c"viewed buffer byte length is 0".to_owned()),
441 );
442 return promise;
443 }
444
445 if view.is_detached_buffer(cx) {
448 promise.reject_error(cx, Error::Type(c"view is detached".to_owned()));
449 return promise;
450 }
451
452 if min == 0 {
454 promise.reject_error(cx, Error::Type(c"min is 0".to_owned()));
455 return promise;
456 }
457
458 if view.has_typed_array_name() {
460 if min > (view.get_typed_array_length() as u64) {
462 promise.reject_error(
463 cx,
464 Error::Range(c"min is greater than array length".to_owned()),
465 );
466 return promise;
467 }
468 } else {
469 if min > (view.byte_length() as u64) {
472 promise.reject_error(
473 cx,
474 Error::Range(c"min is greater than byte length".to_owned()),
475 );
476 return promise;
477 }
478 }
479
480 if self.stream.get().is_none() {
482 promise.reject_error(
483 cx,
484 Error::Type(c"min is greater than byte length".to_owned()),
485 );
486 return promise;
487 }
488
489 rooted!(&in(cx) let read_into_request = ReadIntoRequest::Read(promise.to_traced()));
500
501 self.read(cx, &view, min, &read_into_request);
503
504 promise
506 }
507
508 fn ReleaseLock(&self, cx: &mut JSContext) -> Fallible<()> {
510 if self.stream.get().is_none() {
511 return Ok(());
513 }
514
515 self.release(cx)
517 }
518
519 fn Closed(&self, cx: &JSContext) -> RootedPromise {
521 self.closed(cx)
522 }
523
524 fn Cancel(&self, cx: &mut JSContext, reason: SafeHandleValue) -> RootedPromise {
526 self.generic_cancel(cx, &self.global(), reason)
527 }
528}
529
530impl ReadableStreamGenericReader for ReadableStreamBYOBReader {
531 fn get_closed_promise(&self, cx: &JSContext) -> RootedPromise {
532 self.closed_promise.borrow().root(cx)
533 }
534
535 fn set_closed_promise(&self, promise: &RootedPromise) {
536 *self.closed_promise.borrow_mut() = promise.to_traced();
537 }
538
539 fn set_stream(&self, stream: Option<&ReadableStream>) {
540 self.stream.set(stream);
541 }
542
543 fn get_stream(&self) -> Option<DomRoot<ReadableStream>> {
544 self.stream.get()
545 }
546
547 fn as_byob_reader(&self) -> Option<&ReadableStreamBYOBReader> {
548 Some(self)
549 }
550}