1use std::cell::Cell;
6use std::rc::Rc;
7
8use dom_struct::dom_struct;
9use js::jsapi::{HandleValueArray, Heap, NewArrayObject, Value};
10use js::jsval::{ObjectValue, UndefinedValue};
11use js::rust::HandleValue as SafeHandleValue;
12
13use super::bindings::root::{DomRoot, MutNullableDom};
14use super::types::{ReadableStream, ReadableStreamDefaultReader};
15use crate::dom::bindings::error::Error;
16use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
17use crate::dom::bindings::root::Dom;
18use crate::dom::defaultteereadrequest::DefaultTeeReadRequest;
19use crate::dom::globalscope::GlobalScope;
20use crate::dom::promise::Promise;
21use crate::dom::readablestreamdefaultreader::ReadRequest;
22use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
23
24#[derive(JSTraceable, MallocSizeOf)]
25pub(crate) enum TeeCancelAlgorithm {
26 Cancel1Algorithm,
27 Cancel2Algorithm,
28}
29
30#[dom_struct]
31pub(crate) struct DefaultTeeUnderlyingSource {
33 reflector_: Reflector,
34 reader: Dom<ReadableStreamDefaultReader>,
35 stream: Dom<ReadableStream>,
36 branch_1: MutNullableDom<ReadableStream>,
37 branch_2: MutNullableDom<ReadableStream>,
38 #[ignore_malloc_size_of = "Rc"]
39 reading: Rc<Cell<bool>>,
40 #[ignore_malloc_size_of = "Rc"]
41 read_again: Rc<Cell<bool>>,
42 #[ignore_malloc_size_of = "Rc"]
43 canceled_1: Rc<Cell<bool>>,
44 #[ignore_malloc_size_of = "Rc"]
45 canceled_2: Rc<Cell<bool>>,
46 #[ignore_malloc_size_of = "Rc"]
47 clone_for_branch_2: Rc<Cell<bool>>,
48 #[ignore_malloc_size_of = "Rc"]
49 #[allow(clippy::redundant_allocation)]
50 reason_1: Rc<Box<Heap<Value>>>,
51 #[ignore_malloc_size_of = "Rc"]
52 #[allow(clippy::redundant_allocation)]
53 reason_2: Rc<Box<Heap<Value>>>,
54 #[ignore_malloc_size_of = "Rc"]
55 cancel_promise: Rc<Promise>,
56 tee_cancel_algorithm: TeeCancelAlgorithm,
57}
58
59impl DefaultTeeUnderlyingSource {
60 #[allow(clippy::too_many_arguments)]
61 #[allow(clippy::redundant_allocation)]
62 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
63 pub(crate) fn new(
64 reader: &ReadableStreamDefaultReader,
65 stream: &ReadableStream,
66 reading: Rc<Cell<bool>>,
67 read_again: Rc<Cell<bool>>,
68 canceled_1: Rc<Cell<bool>>,
69 canceled_2: Rc<Cell<bool>>,
70 clone_for_branch_2: Rc<Cell<bool>>,
71 reason_1: Rc<Box<Heap<Value>>>,
72 reason_2: Rc<Box<Heap<Value>>>,
73 cancel_promise: Rc<Promise>,
74 tee_cancel_algorithm: TeeCancelAlgorithm,
75 can_gc: CanGc,
76 ) -> DomRoot<DefaultTeeUnderlyingSource> {
77 reflect_dom_object(
78 Box::new(DefaultTeeUnderlyingSource {
79 reflector_: Reflector::new(),
80 reader: Dom::from_ref(reader),
81 stream: Dom::from_ref(stream),
82 branch_1: MutNullableDom::new(None),
83 branch_2: MutNullableDom::new(None),
84 reading,
85 read_again,
86 canceled_1,
87 canceled_2,
88 clone_for_branch_2,
89 reason_1,
90 reason_2,
91 cancel_promise,
92 tee_cancel_algorithm,
93 }),
94 &*stream.global(),
95 can_gc,
96 )
97 }
98
99 pub(crate) fn set_branch_1(&self, stream: &ReadableStream) {
100 self.branch_1.set(Some(stream));
101 }
102
103 pub(crate) fn set_branch_2(&self, stream: &ReadableStream) {
104 self.branch_2.set(Some(stream));
105 }
106
107 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
110 pub(crate) fn pull_algorithm(&self, can_gc: CanGc) -> Rc<Promise> {
111 let cx = GlobalScope::get_cx();
112 if self.reading.get() {
114 self.read_again.set(true);
116 rooted!(in(*cx) let mut rval = UndefinedValue());
118 return Promise::new_resolved(&self.stream.global(), cx, rval.handle(), can_gc);
119 }
120
121 self.reading.set(true);
123
124 let tee_read_request = DefaultTeeReadRequest::new(
126 &self.stream,
127 &self.branch_1.get().expect("Branch 1 should be set."),
128 &self.branch_2.get().expect("Branch 2 should be set."),
129 self.reading.clone(),
130 self.read_again.clone(),
131 self.canceled_1.clone(),
132 self.canceled_2.clone(),
133 self.clone_for_branch_2.clone(),
134 self.cancel_promise.clone(),
135 self,
136 can_gc,
137 );
138
139 let read_request = ReadRequest::DefaultTee {
141 tee_read_request: Dom::from_ref(&tee_read_request),
142 };
143
144 self.reader.read(cx, &read_request, can_gc);
146
147 rooted!(in(*cx) let mut rval = UndefinedValue());
149 Promise::new_resolved(&self.stream.global(), cx, rval.handle(), can_gc)
150 }
151
152 #[allow(unsafe_code)]
157 pub(crate) fn cancel_algorithm(
158 &self,
159 cx: SafeJSContext,
160 global: &GlobalScope,
161 reason: SafeHandleValue,
162 can_gc: CanGc,
163 ) -> Option<Result<Rc<Promise>, Error>> {
164 match self.tee_cancel_algorithm {
165 TeeCancelAlgorithm::Cancel1Algorithm => {
166 self.canceled_1.set(true);
168
169 self.reason_1.set(reason.get());
171
172 if self.canceled_2.get() {
174 self.resolve_cancel_promise(cx, global, can_gc);
175 }
176 Some(Ok(self.cancel_promise.clone()))
178 },
179 TeeCancelAlgorithm::Cancel2Algorithm => {
180 self.canceled_2.set(true);
182
183 self.reason_2.set(reason.get());
185
186 if self.canceled_1.get() {
188 self.resolve_cancel_promise(cx, global, can_gc);
189 }
190 Some(Ok(self.cancel_promise.clone()))
192 },
193 }
194 }
195
196 #[allow(unsafe_code)]
197 fn resolve_cancel_promise(&self, cx: SafeJSContext, global: &GlobalScope, can_gc: CanGc) {
198 rooted_vec!(let mut reasons_values);
200 reasons_values.push(self.reason_1.get());
201 reasons_values.push(self.reason_2.get());
202
203 let reasons_values_array = HandleValueArray::from(&reasons_values);
204 rooted!(in(*cx) let reasons = unsafe { NewArrayObject(*cx, &reasons_values_array) });
205 rooted!(in(*cx) let reasons_value = ObjectValue(reasons.get()));
206
207 let cancel_result = self
209 .stream
210 .cancel(cx, global, reasons_value.handle(), can_gc);
211
212 self.cancel_promise.resolve_native(&cancel_result, can_gc);
214 }
215}