Skip to content

Commit 05a0a12

Browse files
committed
WIP
1 parent e8068f4 commit 05a0a12

File tree

8 files changed

+150
-12
lines changed

8 files changed

+150
-12
lines changed

dom/src/main/scala/org/scalajs/dom/ReadableStream.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package org.scalajs.dom
22

33
import scala.scalajs.js
4+
import scala.scalajs.js.annotation.JSGlobal
45

56
/** defined at [[https://streams.spec.whatwg.org/#readable-stream ¶2.1. Readable Streams]] of whatwg Streams spec.
67
*
78
* @tparam T
89
* Type of the Chunks returned by the Stream. Can't make it coveriant, due to T
910
*/
1011
@js.native
11-
trait ReadableStream[+T] extends js.Object {
12+
@JSGlobal
13+
class ReadableStream[+T](
14+
underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]],
15+
queuingStrategy: js.UndefOr[ReadableStreamQueuingStrategy[T]] = js.undefined
16+
) extends js.Object {
1217

1318
/** The locked getter returns whether or not the readable stream is locked to a reader.
1419
*

dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.scalajs.dom
22

33
import scala.scalajs.js
4-
import scala.scalajs.js.annotation._
54

65
/** [[https://streams.spec.whatwg.org/#rs-controller-class ¶3.3 Class ReadableStreamController]] of whatwg spec
76
*
@@ -14,8 +13,7 @@ import scala.scalajs.js.annotation._
1413
* Type of the Chunks to be enqueued to the Stream
1514
*/
1615
@js.native
17-
@JSGlobal
18-
class ReadableStreamController[-T](stream: ReadableStream[T] = null) extends js.Object {
16+
trait ReadableStreamController[-T] extends js.Object {
1917

2018
/** The desiredSize getter returns the desired size to fill the controlled stream’s internal queue. It can be
2119
* negative, if the queue is over-full. An underlying source should use this information to determine when and how to
@@ -39,7 +37,7 @@ class ReadableStreamController[-T](stream: ReadableStream[T] = null) extends js.
3937
* @return
4038
* seems like its an undefOr[Int] of the size
4139
*/
42-
def enqueue(chunk: Chunk[T]): js.UndefOr[Int] = js.native
40+
def enqueue(chunk: T): js.UndefOr[Int] = js.native
4341

4442
/** The error method will error the readable stream, making all future interactions with it fail with the given error
4543
* e.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.scalajs.dom
2+
3+
import scala.scalajs.js
4+
5+
/** See [[https://streams.spec.whatwg.org/#qs-api ¶7.1. The queuing strategy API]]
6+
*
7+
* @tparam T
8+
* Type of the Chunks returned by the Stream
9+
*/
10+
trait ReadableStreamQueuingStrategy[T] extends js.Object {
11+
12+
/** A non-negative number indicating the high water mark of the stream using this queuing strategy. */
13+
var highWaterMark: Double
14+
15+
/** (non-byte streams only)
16+
*
17+
* The result is used to determine backpressure, manifesting via the appropriate desiredSize property. For readable
18+
* streams, it also governs when the underlying source's [[ReadableStreamUnderlyingSource.pull]] method is called.
19+
*
20+
* A function that computes and returns the finite non-negative size of the given chunk value.
21+
*/
22+
var size: js.Function1[Chunk[T], Unit]
23+
}

dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,8 @@ class ReadableStreamReader[+T](stream: ReadableStream[T]) extends js.Object {
3030
*
3131
* If the reader is active, the cancel method behaves the same as that for the associated stream. When done, it
3232
* automatically releases the lock.
33-
*
34-
* //todo determine type of reason
3533
*/
36-
// not actually sure what the return type is here
37-
def cancel(reason: Any): js.Promise[Any] = js.native
34+
def cancel[U](reason: js.UndefOr[U]): js.Promise[U] = js.native
3835

3936
/** See [[https://streams.spec.whatwg.org/#reader-read 3.4.4.3. read()]] of whatwg Stream spec.
4037
*
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.scalajs.dom
2+
3+
import scala.scalajs.js
4+
5+
/** [[https://streams.spec.whatwg.org/#enumdef-readablestreamtype ReadableStreamType enum]] */
6+
@js.native
7+
sealed trait ReadableStreamType extends js.Any
8+
9+
object ReadableStreamType {
10+
val bytes: ReadableStreamType = "bytes".asInstanceOf[ReadableStreamType]
11+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.scalajs.dom
2+
3+
import scala.scalajs.js
4+
import scala.scalajs.js.|
5+
6+
/** See [[https://streams.spec.whatwg.org/#underlying-source-api ¶4.2.3. The underlying source API]] of whatwg streams
7+
* spec.
8+
*
9+
* @tparam T
10+
* Type of the Chunks returned by the Stream
11+
*/
12+
trait ReadableStreamUnderlyingSource[T] extends js.Object {
13+
14+
/** A function that is called immediately during creation of the ReadableStream.
15+
*
16+
* If this setup process is asynchronous, it can return a promise to signal success or failure; a rejected promise
17+
* will error the stream. Any thrown exceptions will be re-thrown by the [[ReadableStream]] constructor.
18+
*/
19+
var start: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] = js.undefined
20+
21+
/** A function that is called whenever the stream’s internal queue of chunks becomes not full, i.e. whenever the
22+
* queue’s desired size becomes positive. Generally, it will be called repeatedly until the queue reaches its high
23+
* water mark (i.e. until the desired size becomes non-positive).
24+
*
25+
* This function will not be called until [[start]] successfully completes. Additionally, it will only be called
26+
* repeatedly if it enqueues at least one chunk or fulfills a BYOB request; a no-op [[pull]] implementation will not
27+
* be continually called.
28+
*
29+
* If the function returns a promise, then it will not be called again until that promise fulfills. (If the promise
30+
* rejects, the stream will become errored.) This is mainly used in the case of pull sources, where the promise
31+
* returned represents the process of acquiring a new chunk. Throwing an exception is treated the same as returning a
32+
* rejected promise.
33+
*/
34+
var pull: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] = js.undefined
35+
36+
/** A function that is called whenever the consumer cancels the stream, via [[ReadableStream.cancel]] or
37+
* [[ReadableStreamReader.cancel]]. It takes as its argument the same value as was passed to those methods by the
38+
* consumer.
39+
*
40+
* If the shutdown process is asynchronous, it can return a promise to signal success or failure; the result will be
41+
* communicated via the return value of the [[cancel]] method that was called. Additionally, a rejected promise will
42+
* error the stream, instead of letting it close. Throwing an exception is treated the same as returning a rejected
43+
* promise.
44+
*/
45+
var cancel: js.UndefOr[js.Function1[js.Any, Unit | js.Promise[Unit]]] = js.undefined
46+
47+
/** Can be set to "bytes" to signal that the constructed [[ReadableStream]] is a readable byte stream.
48+
*
49+
* Setting any value other than "bytes" or undefined will cause the ReadableStream() constructor to throw an
50+
* exception.
51+
*/
52+
var `type`: js.UndefOr[ReadableStreamType] = js.undefined
53+
54+
/** (byte streams only)
55+
*
56+
* Can be set to a positive integer to cause the implementation to automatically allocate buffers for the underlying
57+
* source code to write into.
58+
*/
59+
var autoAllocateChunkSize: js.UndefOr[Double] = js.undefined
60+
}

dom/src/main/scala/org/scalajs/dom/package.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package org.scalajs
22

33
import scala.scalajs.js
44
import scala.scalajs.js.annotation._
5-
import scala.scalajs.js.typedarray.{ArrayBuffer, ArrayBufferView}
5+
import scala.scalajs.js.typedarray.{ArrayBuffer, ArrayBufferView, Uint8Array}
66
import scala.scalajs.js.|
77

88
package object dom {
@@ -32,7 +32,7 @@ package object dom {
3232

3333
/** defined at [[https://fetch.spec.whatwg.org/#body-mixin ¶6.2 Body mixin]] in whatwg Fetch spec */
3434
type BodyInit =
35-
Blob | BufferSource | FormData | String // todo: add URLSearchParams
35+
Blob | BufferSource | FormData | String | ReadableStream[Uint8Array] // todo: add URLSearchParams
3636

3737
/** WebIDL sequence<T> is js.Array[T] | JSIterable[T]. However @mseddon knows at least Blink's IDL compiler treats
3838
* these as simply js.Array[T] for now. We keep this type as a reminder to check in more detail

tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
package org.scalajs.dom.tests.shared
22

3-
import org.scalajs.dom.tests.shared.AsyncTesting._
3+
import org.junit.Assert.assertEquals
44
import org.junit.Test
5+
import org.scalajs.dom.tests.shared.AsyncTesting._
6+
7+
import scala.concurrent.Future
8+
import scala.scalajs.js
9+
import scala.scalajs.js.Thenable.Implicits._
10+
import scala.scalajs.js.|
511

612
trait SharedTests {
713

@@ -36,4 +42,42 @@ trait SharedTests {
3642

3743
@Test final def WindowIdbTest(): AsyncResult =
3844
IdbTest(window.indexedDB)
45+
46+
@Test
47+
final def ReadableStreamTest: AsyncResult = async {
48+
case class Tuna(color: String)
49+
50+
val expectedTunas = Seq(
51+
Tuna("blue"),
52+
Tuna("red")
53+
)
54+
55+
val stream = new ReadableStream[Tuna](
56+
new ReadableStreamUnderlyingSource[Tuna] {
57+
start = { controller: ReadableStreamController[Tuna] =>
58+
controller.enqueue(Tuna("blue"))
59+
controller.enqueue(Tuna("red"))
60+
controller.close()
61+
}.asInstanceOf[js.UndefOr[js.Function1[ReadableStreamController[Tuna], Unit | js.Promise[Unit]]]]
62+
}
63+
)
64+
65+
val reader = stream.getReader()
66+
67+
def read(tunas: Seq[Tuna]): Future[Seq[Tuna]] = {
68+
reader
69+
.read()
70+
.flatMap { chunk =>
71+
if (chunk.done) {
72+
Future.successful(tunas)
73+
} else {
74+
read(tunas :+ chunk.value)
75+
}
76+
}
77+
}
78+
read(Seq.empty)
79+
.map { receivedTunas =>
80+
assertEquals(receivedTunas, expectedTunas)
81+
}
82+
}
3983
}

0 commit comments

Comments
 (0)