Skip to main content

ferrijs_std/stream_web/readable/
controller.rs

1use rquickjs::{
2    class::{OwnedBorrowMut, Trace},
3    Ctx, IntoJs, JsLifetime, Promise, Result, Value,
4};
5
6use crate::stream_web::readable::{
7    byte_controller::{ReadableByteStreamControllerClass, ReadableByteStreamControllerOwned},
8    default_controller::{
9        ReadableStreamDefaultControllerClass, ReadableStreamDefaultControllerOwned,
10    },
11    default_reader::ReadableStreamReadRequest,
12    objects::{ReadableStreamDefaultReaderObjects, ReadableStreamObjects},
13    reader::ReadableStreamReader,
14};
15
16pub(crate) trait ReadableStreamController<'js>: Sized {
17    type Class: Clone + Trace<'js>;
18
19    fn with_controller<C, O>(
20        self,
21        ctx: C,
22        default: impl FnOnce(
23            C,
24            ReadableStreamDefaultControllerOwned<'js>,
25        ) -> Result<(O, ReadableStreamDefaultControllerOwned<'js>)>,
26        byte: impl FnOnce(
27            C,
28            ReadableByteStreamControllerOwned<'js>,
29        ) -> Result<(O, ReadableByteStreamControllerOwned<'js>)>,
30    ) -> Result<(O, Self)>;
31
32    fn into_inner(self) -> Self::Class;
33    fn from_class(class: Self::Class) -> Self;
34
35    fn into_erased(self) -> ReadableStreamControllerOwned<'js>;
36    fn try_from_erased(erased: ReadableStreamControllerOwned<'js>) -> Option<Self>;
37
38    fn pull_steps(
39        ctx: &Ctx<'js>,
40        objects: ReadableStreamDefaultReaderObjects<'js, Self>,
41        read_request: impl ReadableStreamReadRequest<'js> + 'js,
42    ) -> Result<ReadableStreamDefaultReaderObjects<'js, Self>>;
43
44    fn cancel_steps<R: ReadableStreamReader<'js>>(
45        ctx: &Ctx<'js>,
46        objects: ReadableStreamObjects<'js, Self, R>,
47        reason: Value<'js>,
48    ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, Self, R>)>;
49
50    fn release_steps(&mut self);
51}
52
53#[derive(JsLifetime, Trace, Clone)]
54pub enum ReadableStreamControllerClass<'js> {
55    ReadableStreamDefaultController(ReadableStreamDefaultControllerClass<'js>),
56    ReadableStreamByteController(ReadableByteStreamControllerClass<'js>),
57    Uninitialised, // Only for use when initialising a Stream - should never be present later on
58}
59
60impl<'js> IntoJs<'js> for ReadableStreamControllerClass<'js> {
61    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {
62        match self {
63            Self::ReadableStreamDefaultController(c) => c.into_js(ctx),
64            Self::ReadableStreamByteController(c) => c.into_js(ctx),
65            Self::Uninitialised => {
66                panic!("Tried to convert an uninitialised controller class to JS")
67            },
68        }
69    }
70}
71
72pub(crate) enum ReadableStreamControllerOwned<'js> {
73    ReadableStreamDefaultController(ReadableStreamDefaultControllerOwned<'js>),
74    ReadableStreamByteController(ReadableByteStreamControllerOwned<'js>),
75}
76
77impl<'js> ReadableStreamController<'js> for ReadableStreamControllerOwned<'js> {
78    type Class = ReadableStreamControllerClass<'js>;
79
80    fn with_controller<C, O>(
81        self,
82        ctx: C,
83        default: impl FnOnce(
84            C,
85            ReadableStreamDefaultControllerOwned<'js>,
86        ) -> Result<(O, ReadableStreamDefaultControllerOwned<'js>)>,
87        byob: impl FnOnce(
88            C,
89            ReadableByteStreamControllerOwned<'js>,
90        ) -> Result<(O, ReadableByteStreamControllerOwned<'js>)>,
91    ) -> Result<(O, Self)> {
92        match self {
93            ReadableStreamControllerOwned::ReadableStreamDefaultController(r) => {
94                let (ctx, r) = default(ctx, r)?;
95                Ok((ctx, Self::ReadableStreamDefaultController(r)))
96            },
97            ReadableStreamControllerOwned::ReadableStreamByteController(r) => {
98                let (ctx, r) = byob(ctx, r)?;
99                Ok((ctx, Self::ReadableStreamByteController(r)))
100            },
101        }
102    }
103
104    fn into_inner(self) -> Self::Class {
105        match self {
106            ReadableStreamControllerOwned::ReadableStreamDefaultController(c) => {
107                ReadableStreamControllerClass::ReadableStreamDefaultController(c.into_inner())
108            },
109            ReadableStreamControllerOwned::ReadableStreamByteController(c) => {
110                ReadableStreamControllerClass::ReadableStreamByteController(c.into_inner())
111            },
112        }
113    }
114
115    fn from_class(class: Self::Class) -> Self {
116        match class {
117            ReadableStreamControllerClass::ReadableStreamDefaultController(class) => {
118                ReadableStreamControllerOwned::ReadableStreamDefaultController(
119                    OwnedBorrowMut::from_class(class),
120                )
121            },
122            ReadableStreamControllerClass::ReadableStreamByteController(class) => {
123                ReadableStreamControllerOwned::ReadableStreamByteController(
124                    OwnedBorrowMut::from_class(class),
125                )
126            },
127            ReadableStreamControllerClass::Uninitialised => {
128                panic!("Tried to borrow an uninitialised controller class")
129            },
130        }
131    }
132
133    fn into_erased(self) -> ReadableStreamControllerOwned<'js> {
134        self
135    }
136
137    fn try_from_erased(erased: ReadableStreamControllerOwned<'js>) -> Option<Self> {
138        Some(erased)
139    }
140
141    fn pull_steps(
142        ctx: &Ctx<'js>,
143        objects: ReadableStreamDefaultReaderObjects<'js, Self>,
144        read_request: impl ReadableStreamReadRequest<'js> + 'js,
145    ) -> Result<ReadableStreamDefaultReaderObjects<'js, Self>> {
146        objects
147            .with_controller(
148                read_request,
149                |read_request, objects| {
150                    ReadableStreamDefaultControllerOwned::<'js>::pull_steps(
151                        ctx,
152                        objects,
153                        read_request,
154                    )
155                    .map(|objects| ((), objects))
156                },
157                |read_request, objects| {
158                    ReadableByteStreamControllerOwned::<'js>::pull_steps(ctx, objects, read_request)
159                        .map(|objects| ((), objects))
160                },
161            )
162            .map(|((), objects)| objects)
163    }
164
165    fn cancel_steps<R: ReadableStreamReader<'js>>(
166        ctx: &Ctx<'js>,
167        objects: ReadableStreamObjects<'js, Self, R>,
168        reason: Value<'js>,
169    ) -> Result<(Promise<'js>, ReadableStreamObjects<'js, Self, R>)> {
170        objects.with_controller(
171            reason,
172            |reason, objects| {
173                ReadableStreamDefaultControllerOwned::<'js>::cancel_steps(ctx, objects, reason)
174            },
175            |reason, objects| {
176                ReadableByteStreamControllerOwned::<'js>::cancel_steps(ctx, objects, reason)
177            },
178        )
179    }
180
181    fn release_steps(&mut self) {
182        match self {
183            ReadableStreamControllerOwned::ReadableStreamDefaultController(c) => c.release_steps(),
184            ReadableStreamControllerOwned::ReadableStreamByteController(c) => c.release_steps(),
185        }
186    }
187}
188
189impl<'js> From<ReadableStreamDefaultControllerOwned<'js>> for ReadableStreamControllerOwned<'js> {
190    fn from(value: ReadableStreamDefaultControllerOwned<'js>) -> Self {
191        Self::ReadableStreamDefaultController(value)
192    }
193}
194
195impl<'js> From<ReadableByteStreamControllerOwned<'js>> for ReadableStreamControllerOwned<'js> {
196    fn from(value: ReadableByteStreamControllerOwned<'js>) -> Self {
197        Self::ReadableStreamByteController(value)
198    }
199}