1use std::cell::{Cell, RefCell};
6use std::rc::Rc;
7
8use dom_struct::dom_struct;
9use js::context::JSContext;
10use js::jsapi::{HandleValueArray, Heap, NewArrayObject, Value};
11use js::jsval::ObjectValue;
12use js::rust::HandleValue as SafeHandleValue;
13use js::typedarray::ArrayBufferViewU8;
14use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
15
16use super::byteteereadintorequest::ByteTeeReadIntoRequest;
17use super::readablestream::ReaderType;
18use super::readablestreambyobreader::ReadIntoRequest;
19use crate::dom::bindings::buffer_source::HeapBufferSource;
20use crate::dom::bindings::error::{Error, Fallible};
21use crate::dom::bindings::reflector::DomGlobal;
22use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
23use crate::dom::globalscope::GlobalScope;
24use crate::dom::promise::Promise;
25use crate::dom::stream::byteteereadrequest::ByteTeeReadRequest;
26use crate::dom::stream::readablestreamdefaultreader::ReadRequest;
27use crate::dom::types::ReadableStream;
28
29#[derive(JSTraceable, MallocSizeOf)]
30pub(crate) enum ByteTeeCancelAlgorithm {
31 Cancel1Algorithm,
32 Cancel2Algorithm,
33}
34
35#[derive(Clone, JSTraceable, MallocSizeOf)]
36pub(crate) enum ByteTeePullAlgorithm {
37 Pull1Algorithm,
38 Pull2Algorithm,
39}
40
41#[dom_struct]
42pub(crate) struct ByteTeeUnderlyingSource {
44 reflector_: Reflector,
45 #[conditional_malloc_size_of]
46 reader: Rc<RefCell<ReaderType>>,
47 stream: Dom<ReadableStream>,
48 branch_1: MutNullableDom<ReadableStream>,
49 branch_2: MutNullableDom<ReadableStream>,
50 #[conditional_malloc_size_of]
51 read_again_for_branch_1: Rc<Cell<bool>>,
52 #[conditional_malloc_size_of]
53 read_again_for_branch_2: Rc<Cell<bool>>,
54 #[conditional_malloc_size_of]
55 reading: Rc<Cell<bool>>,
56 #[conditional_malloc_size_of]
57 canceled_1: Rc<Cell<bool>>,
58 #[conditional_malloc_size_of]
59 canceled_2: Rc<Cell<bool>>,
60 #[ignore_malloc_size_of = "Mozjs"]
61 reason_1: Rc<Heap<Value>>,
62 #[ignore_malloc_size_of = "Mozjs"]
63 reason_2: Rc<Heap<Value>>,
64 #[conditional_malloc_size_of]
65 cancel_promise: Rc<Promise>,
66 #[conditional_malloc_size_of]
67 reader_version: Rc<Cell<u64>>,
68 tee_cancel_algorithm: ByteTeeCancelAlgorithm,
69 byte_tee_pull_algorithm: ByteTeePullAlgorithm,
70}
71
72impl ByteTeeUnderlyingSource {
73 #[allow(clippy::too_many_arguments)]
74 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
75 pub(crate) fn new(
76 cx: &mut JSContext,
77 reader: Rc<RefCell<ReaderType>>,
78 stream: &ReadableStream,
79 reading: Rc<Cell<bool>>,
80 read_again_for_branch_1: Rc<Cell<bool>>,
81 read_again_for_branch_2: Rc<Cell<bool>>,
82 canceled_1: Rc<Cell<bool>>,
83 canceled_2: Rc<Cell<bool>>,
84 reason_1: Rc<Heap<Value>>,
85 reason_2: Rc<Heap<Value>>,
86 cancel_promise: Rc<Promise>,
87 reader_version: Rc<Cell<u64>>,
88 tee_cancel_algorithm: ByteTeeCancelAlgorithm,
89 byte_tee_pull_algorithm: ByteTeePullAlgorithm,
90 ) -> DomRoot<ByteTeeUnderlyingSource> {
91 reflect_dom_object_with_cx(
92 Box::new(ByteTeeUnderlyingSource {
93 reflector_: Reflector::new(),
94 reader,
95 stream: Dom::from_ref(stream),
96 branch_1: MutNullableDom::new(None),
97 branch_2: MutNullableDom::new(None),
98 read_again_for_branch_1,
99 read_again_for_branch_2,
100 reading,
101 canceled_1,
102 canceled_2,
103 reason_1,
104 reason_2,
105 cancel_promise,
106 reader_version,
107 tee_cancel_algorithm,
108 byte_tee_pull_algorithm,
109 }),
110 &*stream.global(),
111 cx,
112 )
113 }
114
115 pub(crate) fn set_branch_1(&self, stream: &ReadableStream) {
116 self.branch_1.set(Some(stream));
117 }
118
119 pub(crate) fn set_branch_2(&self, stream: &ReadableStream) {
120 self.branch_2.set(Some(stream));
121 }
122
123 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
124 pub(crate) fn forward_reader_error(
125 &self,
126 cx: &mut JSContext,
127 this_reader: Rc<RefCell<ReaderType>>,
128 ) {
129 let this_reader = this_reader.borrow();
130 match &*this_reader {
131 ReaderType::Default(reader) => {
132 let expected_version = self.reader_version.get();
133 reader
135 .get()
136 .expect("Reader should be set.")
137 .byte_tee_append_native_handler_to_closed_promise(
138 cx,
139 &self.branch_1.get().expect("Branch 1 should be set."),
140 &self.branch_2.get().expect("Branch 2 should be set."),
141 self.canceled_1.clone(),
142 self.canceled_2.clone(),
143 self.cancel_promise.clone(),
144 self.reader_version.clone(),
145 expected_version,
146 );
147 },
148 ReaderType::BYOB(reader) => {
149 let expected_version = self.reader_version.get();
150 reader
152 .get()
153 .expect("Reader should be set.")
154 .byte_tee_append_native_handler_to_closed_promise(
155 cx,
156 &self.branch_1.get().expect("Branch 1 should be set."),
157 &self.branch_2.get().expect("Branch 2 should be set."),
158 self.canceled_1.clone(),
159 self.canceled_2.clone(),
160 self.cancel_promise.clone(),
161 self.reader_version.clone(),
162 expected_version,
163 );
164 },
165 }
166 }
167
168 fn pull_with_default_reader(&self, cx: &mut JSContext, global: &GlobalScope) -> Fallible<()> {
169 rooted!(&in(cx) let mut reader_to_set = None);
170 {
171 let reader = self.reader.borrow();
172 match &*reader {
173 ReaderType::BYOB(byte_reader) => {
174 assert!(
176 byte_reader
177 .get()
178 .expect("Reader should be set.")
179 .get_num_read_into_requests() ==
180 0
181 );
182
183 byte_reader
185 .get()
186 .expect("Reader should be set.")
187 .release(cx)?;
188
189 let default_reader = self
191 .stream
192 .acquire_default_reader(cx)
193 .expect("AcquireReadableStreamDefaultReader should not fail");
194
195 reader_to_set.set(Some(ReaderType::Default(MutNullableDom::new(Some(
196 &default_reader,
197 )))));
198 },
200 ReaderType::Default(reader) => {
201 let byte_tee_read_request = ByteTeeReadRequest::new(
202 cx,
203 &self.branch_1.get().expect("Branch 1 should be set."),
204 &self.branch_2.get().expect("Branch 2 should be set."),
205 &self.stream,
206 self.read_again_for_branch_1.clone(),
207 self.read_again_for_branch_2.clone(),
208 self.reading.clone(),
209 self.canceled_1.clone(),
210 self.canceled_2.clone(),
211 self.cancel_promise.clone(),
212 self,
213 global,
214 );
215
216 let read_request = ReadRequest::ByteTee {
217 byte_tee_read_request: Dom::from_ref(&byte_tee_read_request),
218 };
219
220 reader
221 .get()
222 .expect("Reader should be set.")
223 .read(cx, &read_request);
224 },
225 }
226 }
227
228 if reader_to_set.is_some() {
229 *self.reader.borrow_mut() = reader_to_set.take().unwrap();
230 self.reader_version
231 .set(self.reader_version.get().wrapping_add(1));
232
233 self.forward_reader_error(cx, self.reader.clone());
235
236 return self.pull_with_default_reader(cx, global);
238 }
239
240 Ok(())
241 }
242
243 fn pull_with_byob_reader(
244 &self,
245 cx: &mut JSContext,
246 view: &HeapBufferSource<ArrayBufferViewU8>,
247 for_branch2: bool,
248 global: &GlobalScope,
249 ) {
250 rooted!(&in(cx) let mut reader_to_set = None);
251 {
252 let reader = self.reader.borrow();
253 match &*reader {
254 ReaderType::BYOB(reader) => {
255 let byob_branch = if for_branch2 {
257 self.branch_2.get().expect("Branch 2 should be set.")
258 } else {
259 self.branch_1.get().expect("Branch 1 should be set.")
260 };
261
262 let other_branch = if for_branch2 {
264 self.branch_1.get().expect("Branch 1 should be set.")
265 } else {
266 self.branch_2.get().expect("Branch 2 should be set.")
267 };
268
269 let byte_tee_read_into_request = ByteTeeReadIntoRequest::new(
271 cx,
272 for_branch2,
273 &byob_branch,
274 &other_branch,
275 &self.stream,
276 self.read_again_for_branch_1.clone(),
277 self.read_again_for_branch_2.clone(),
278 self.reading.clone(),
279 self.canceled_1.clone(),
280 self.canceled_2.clone(),
281 self.cancel_promise.clone(),
282 self,
283 global,
284 );
285
286 let read_into_request = ReadIntoRequest::ByteTee {
287 byte_tee_read_into_request: Dom::from_ref(&byte_tee_read_into_request),
288 };
289
290 reader.get().expect("Reader should be set.").read(
292 cx,
293 view,
294 1,
295 &read_into_request,
296 );
297 },
298 ReaderType::Default(default_reader) => {
299 assert!(
302 default_reader
303 .get()
304 .expect("Reader should be set.")
305 .get_num_read_requests() ==
306 0
307 );
308
309 default_reader
311 .get()
312 .expect("Reader should be set.")
313 .release(cx)
314 .expect("Release should be successful.");
315
316 let byob_reader = self
318 .stream
319 .acquire_byob_reader(cx)
320 .expect("Reader should be set.");
321
322 reader_to_set.set(Some(ReaderType::BYOB(MutNullableDom::new(Some(
323 &byob_reader,
324 )))));
325 },
327 }
328 }
329
330 if reader_to_set.is_some() {
331 *self.reader.borrow_mut() = reader_to_set.take().unwrap();
332 self.reader_version
333 .set(self.reader_version.get().wrapping_add(1));
334
335 self.forward_reader_error(cx, self.reader.clone());
337
338 self.pull_with_byob_reader(cx, view, for_branch2, global);
340 }
341 }
342
343 pub(crate) fn pull_algorithm(
345 &self,
346 cx: &mut JSContext,
347 byte_tee_pull_algorithm: Option<ByteTeePullAlgorithm>,
348 ) -> Rc<Promise> {
349 let pull_algorithm =
350 byte_tee_pull_algorithm.unwrap_or(self.byte_tee_pull_algorithm.clone());
351
352 match pull_algorithm {
353 ByteTeePullAlgorithm::Pull1Algorithm => {
354 if self.reading.get() {
356 self.read_again_for_branch_1.set(true);
358 return Promise::new_resolved(cx, &self.stream.global(), ());
360 }
361
362 self.reading.set(true);
364
365 let byob_branch_controller = self
367 .branch_1
368 .get()
369 .expect("Branch 1 should be set.")
370 .get_byte_controller();
371 let byob_request = byob_branch_controller
372 .get_byob_request(cx)
373 .expect("Byob request should be set.");
374
375 match byob_request {
376 None => {
378 self.pull_with_default_reader(cx, &self.stream.global())
379 .expect("Pull with default reader should be successful.");
380 },
381 Some(request) => {
382 let view = request.get_view();
384
385 self.pull_with_byob_reader(cx, &view, false, &self.stream.global());
386 },
387 }
388
389 Promise::new_resolved(cx, &self.stream.global(), ())
391 },
392 ByteTeePullAlgorithm::Pull2Algorithm => {
393 if self.reading.get() {
395 self.read_again_for_branch_2.set(true);
397
398 return Promise::new_resolved(cx, &self.stream.global(), ());
400 }
401
402 self.reading.set(true);
404
405 let byob_branch_controller = self
407 .branch_2
408 .get()
409 .expect("Branch 2 should be set.")
410 .get_byte_controller();
411 let byob_request = byob_branch_controller
412 .get_byob_request(cx)
413 .expect("Byob request should be set.");
414
415 match byob_request {
416 None => {
417 self.pull_with_default_reader(cx, &self.stream.global())
418 .expect("Pull with default reader should be successful.");
419 },
420 Some(request) => {
421 let view = request.get_view();
423
424 self.pull_with_byob_reader(cx, &view, true, &self.stream.global());
425 },
426 }
427
428 Promise::new_resolved(cx, &self.stream.global(), ())
430 },
431 }
432 }
433
434 pub(crate) fn cancel_algorithm(
439 &self,
440 cx: &mut JSContext,
441 reason: SafeHandleValue,
442 ) -> Option<Result<Rc<Promise>, Error>> {
443 match self.tee_cancel_algorithm {
444 ByteTeeCancelAlgorithm::Cancel1Algorithm => {
445 self.canceled_1.set(true);
447
448 self.reason_1.set(reason.get());
450
451 if self.canceled_2.get() {
453 self.resolve_cancel_promise(cx);
454 }
455
456 Some(Ok(self.cancel_promise.clone()))
458 },
459 ByteTeeCancelAlgorithm::Cancel2Algorithm => {
460 self.canceled_2.set(true);
462
463 self.reason_2.set(reason.get());
465
466 if self.canceled_1.get() {
468 self.resolve_cancel_promise(cx);
469 }
470 Some(Ok(self.cancel_promise.clone()))
472 },
473 }
474 }
475
476 #[expect(unsafe_code)]
477 fn resolve_cancel_promise(&self, cx: &mut JSContext) {
478 rooted_vec!(let mut reasons_values);
480 reasons_values.push(self.reason_1.get());
481 reasons_values.push(self.reason_2.get());
482
483 let reasons_values_array = HandleValueArray::from(&reasons_values);
484 rooted!(&in(cx) let reasons = unsafe { NewArrayObject(cx.raw_cx(), &reasons_values_array) });
485 rooted!(&in(cx) let reasons_value = ObjectValue(reasons.get()));
486
487 let cancel_result = self
489 .stream
490 .cancel(cx, &self.stream.global(), reasons_value.handle());
491
492 self.cancel_promise.resolve_native(cx, &cancel_result);
494 }
495}