Skip to content

Commit fdb5bd2

Browse files
authored
WASM improvements (#30)
* Don't take self in close functions. It's a pain when Drop is used. * Fix some WASM stuff. * Some WASM improvements. * WIP * Some fixes to the read_buf API * Oops advance_mut * Remove some less useful changes. * Not needed either. * Clippy
1 parent 463dd22 commit fdb5bd2

File tree

11 files changed

+286
-148
lines changed

11 files changed

+286
-148
lines changed

web-transport-wasm/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ authors = ["Luke Curley"]
55
repository = "https://github.com/kixelated/web-transport-rs"
66
license = "MIT"
77

8-
version = "0.1.1"
8+
version = "0.2.0"
99
edition = "2021"
1010

1111
keywords = ["quic", "http3", "webtransport"]
@@ -16,6 +16,8 @@ wasm-bindgen = "0.2"
1616
wasm-bindgen-futures = "0.4"
1717
js-sys = "0.3.69"
1818
bytes = "1"
19+
thiserror = "1"
20+
url = "2"
1921

2022
[dependencies.web-sys]
2123
version = "0.3.69"
@@ -24,11 +26,13 @@ features = [
2426
"ReadableStreamDefaultReader",
2527
"ReadableStreamReadResult",
2628
"WebTransport",
29+
"WebTransportOptions",
2730
"WebTransportBidirectionalStream",
2831
"WebTransportCloseInfo",
2932
"WebTransportSendStream",
3033
"WebTransportReceiveStream",
3134
"WebTransportDatagramDuplexStream",
35+
"WebTransportCongestionControl",
3236
"WritableStream",
3337
"WritableStreamDefaultWriter",
3438
]

web-transport-wasm/rust-toolchain.toml

Lines changed: 0 additions & 2 deletions
This file was deleted.

web-transport-wasm/src/error.rs

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,61 @@
1-
use std::{error, fmt};
1+
use wasm_bindgen::prelude::*;
22

3-
use wasm_bindgen::JsValue;
3+
#[derive(Clone, Debug, thiserror::Error)]
4+
#[error("web error: {0:?}")]
5+
pub struct WebError(js_sys::Error);
46

5-
#[derive(Debug)]
6-
pub struct WebError {
7-
value: JsValue,
7+
impl From<js_sys::Error> for WebError {
8+
fn from(e: js_sys::Error) -> Self {
9+
Self(e)
10+
}
811
}
912

10-
impl From<JsValue> for WebError {
11-
fn from(value: JsValue) -> Self {
12-
Self { value }
13+
impl From<wasm_bindgen::JsValue> for WebError {
14+
fn from(e: wasm_bindgen::JsValue) -> Self {
15+
Self(e.into())
1316
}
1417
}
1518

16-
impl error::Error for WebError {}
19+
pub trait WebErrorExt<T> {
20+
fn throw(self) -> Result<T, WebError>;
21+
}
1722

18-
impl fmt::Display for WebError {
19-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20-
// Print out the JsValue as a string
21-
match self.value.as_string() {
22-
Some(s) => write!(f, "{}", s),
23-
None => write!(f, "{:?}", self.value),
24-
}
23+
impl<T, E: Into<WebError>> WebErrorExt<T> for Result<T, E> {
24+
fn throw(self) -> Result<T, WebError> {
25+
self.map_err(Into::into)
2526
}
2627
}
2728

28-
impl From<&str> for WebError {
29-
fn from(value: &str) -> Self {
30-
Self {
31-
value: value.into(),
32-
}
29+
#[derive(Clone, Debug, thiserror::Error)]
30+
#[error("read error: {0:?}")]
31+
pub struct ReadError(#[from] WebError);
32+
33+
#[derive(Clone, Debug, thiserror::Error)]
34+
#[error("write error: {0:?}")]
35+
pub struct WriteError(#[from] WebError);
36+
37+
#[derive(Clone, Debug, thiserror::Error)]
38+
pub enum SessionError {
39+
// TODO distinguish between different kinds of errors
40+
#[error("read error: {0}")]
41+
Read(#[from] ReadError),
42+
43+
#[error("write error: {0}")]
44+
Write(#[from] WriteError),
45+
46+
#[error("web error: {0}")]
47+
Web(#[from] WebError),
48+
}
49+
50+
pub(crate) trait PromiseExt {
51+
fn ignore(self);
52+
}
53+
54+
impl PromiseExt for js_sys::Promise {
55+
// Ignore the result of the promise by using an empty catch.
56+
fn ignore(self) {
57+
let closure = Closure::wrap(Box::new(|_: JsValue| {}) as Box<dyn FnMut(JsValue)>);
58+
let _ = self.catch(&closure);
59+
closure.forget();
3360
}
3461
}

web-transport-wasm/src/reader.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,45 @@
11
use js_sys::Reflect;
2-
use wasm_bindgen::{JsCast, JsValue};
2+
use wasm_bindgen::prelude::*;
33
use wasm_bindgen_futures::JsFuture;
44
use web_sys::{ReadableStream, ReadableStreamDefaultReader, ReadableStreamReadResult};
55

6-
use crate::WebError;
6+
use crate::{PromiseExt, ReadError, WebErrorExt};
77

88
// Wrapper around ReadableStream
99
pub struct Reader {
1010
inner: ReadableStreamDefaultReader,
1111
}
1212

1313
impl Reader {
14-
pub fn new(stream: &ReadableStream) -> Result<Self, WebError> {
14+
pub fn new(stream: &ReadableStream) -> Result<Self, ReadError> {
1515
let inner = stream.get_reader().unchecked_into();
1616
Ok(Self { inner })
1717
}
1818

19-
pub async fn read<T: JsCast>(&mut self) -> Result<Option<T>, WebError> {
20-
let result: ReadableStreamReadResult = JsFuture::from(self.inner.read()).await?.into();
19+
pub async fn read<T: JsCast>(&mut self) -> Result<Option<T>, ReadError> {
20+
let result: ReadableStreamReadResult =
21+
JsFuture::from(self.inner.read()).await.throw()?.into();
2122

22-
if Reflect::get(&result, &"done".into())?.is_truthy() {
23+
if Reflect::get(&result, &"done".into()).throw()?.is_truthy() {
2324
return Ok(None);
2425
}
2526

26-
let res = Reflect::get(&result, &"value".into())?.dyn_into()?;
27+
let res = Reflect::get(&result, &"value".into())
28+
.throw()?
29+
.unchecked_into();
30+
2731
Ok(Some(res))
2832
}
2933

30-
pub fn close(self, reason: &str) {
34+
pub fn close(&mut self, reason: &str) {
3135
let str = JsValue::from_str(reason);
32-
let _ = self.inner.cancel_with_reason(&str); // ignore the promise
36+
self.inner.cancel_with_reason(&str).ignore();
3337
}
3438
}
3539

3640
impl Drop for Reader {
3741
fn drop(&mut self) {
38-
let _ = self.inner.cancel(); // ignore the promise
42+
self.inner.cancel().ignore();
3943
self.inner.release_lock();
4044
}
4145
}

web-transport-wasm/src/recv.rs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,15 @@ use bytes::{BufMut, Bytes, BytesMut};
44
use js_sys::Uint8Array;
55
use web_sys::WebTransportReceiveStream;
66

7-
use crate::{Reader, WebError};
7+
use crate::{ReadError, Reader};
88

99
pub struct RecvStream {
1010
reader: Reader,
1111
buffer: BytesMut,
1212
}
1313

1414
impl RecvStream {
15-
pub fn new(stream: WebTransportReceiveStream) -> Result<Self, WebError> {
16-
if stream.locked() {
17-
return Err("locked".into());
18-
}
19-
15+
pub(super) fn new(stream: WebTransportReceiveStream) -> Result<Self, ReadError> {
2016
let reader = Reader::new(&stream)?;
2117

2218
Ok(Self {
@@ -25,25 +21,30 @@ impl RecvStream {
2521
})
2622
}
2723

28-
pub async fn read(&mut self, buf: &mut [u8]) -> Result<Option<usize>, WebError> {
29-
Ok(self.read_chunk(buf.len()).await?.map(|chunk| {
30-
let size = chunk.len();
31-
buf[..size].copy_from_slice(&chunk);
32-
size
33-
}))
24+
pub async fn read(&mut self, buf: &mut [u8]) -> Result<Option<usize>, ReadError> {
25+
let chunk = match self.read_chunk(buf.len()).await? {
26+
Some(chunk) => chunk,
27+
None => return Ok(None),
28+
};
29+
30+
let size = chunk.len();
31+
buf[..size].copy_from_slice(&chunk);
32+
Ok(Some(size))
3433
}
3534

36-
pub async fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Result<bool, WebError> {
37-
Ok(match self.read_chunk(buf.remaining_mut()).await? {
38-
Some(chunk) => {
39-
buf.put(chunk);
40-
true
41-
}
42-
None => false,
43-
})
35+
pub async fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Result<Option<usize>, ReadError> {
36+
let chunk = match self.read_chunk(buf.remaining_mut()).await? {
37+
Some(chunk) => chunk,
38+
None => return Ok(None),
39+
};
40+
41+
let size = chunk.len();
42+
buf.put(chunk);
43+
44+
Ok(Some(size))
4445
}
4546

46-
pub async fn read_chunk(&mut self, max: usize) -> Result<Option<Bytes>, WebError> {
47+
pub async fn read_chunk(&mut self, max: usize) -> Result<Option<Bytes>, ReadError> {
4748
if !self.buffer.is_empty() {
4849
let size = cmp::min(max, self.buffer.len());
4950
let data = self.buffer.split_to(size).freeze();
@@ -64,7 +65,7 @@ impl RecvStream {
6465
Ok(Some(data))
6566
}
6667

67-
pub fn stop(self, reason: &str) {
68+
pub fn stop(&mut self, reason: &str) {
6869
self.reader.close(reason);
6970
}
7071
}

web-transport-wasm/src/send.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,36 @@ use bytes::{Buf, Bytes};
22
use js_sys::{Reflect, Uint8Array};
33
use web_sys::WebTransportSendStream;
44

5-
use crate::{WebError, Writer};
5+
use crate::{WriteError, Writer};
66

77
pub struct SendStream {
88
stream: WebTransportSendStream,
99
writer: Writer,
1010
}
1111

1212
impl SendStream {
13-
pub fn new(stream: WebTransportSendStream) -> Result<Self, WebError> {
13+
pub(super) fn new(stream: WebTransportSendStream) -> Result<Self, WriteError> {
1414
let writer = Writer::new(&stream)?;
1515
Ok(Self { stream, writer })
1616
}
1717

18-
pub async fn write(&mut self, buf: &[u8]) -> Result<usize, WebError> {
18+
pub async fn write(&mut self, buf: &[u8]) -> Result<usize, WriteError> {
1919
self.writer.write(&Uint8Array::from(buf)).await?;
2020
Ok(buf.len())
2121
}
2222

23-
pub async fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Result<usize, WebError> {
24-
let chunk = buf.chunk();
25-
self.writer.write(&Uint8Array::from(chunk)).await?;
26-
Ok(chunk.len())
23+
pub async fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Result<usize, WriteError> {
24+
let size = self.write(buf.chunk()).await?;
25+
buf.advance(size);
26+
27+
Ok(size)
2728
}
2829

29-
pub async fn write_chunk(&mut self, buf: Bytes) -> Result<(), WebError> {
30+
pub async fn write_chunk(&mut self, buf: Bytes) -> Result<(), WriteError> {
3031
self.write(&buf).await.map(|_| ())
3132
}
3233

33-
pub fn reset(self, reason: &str) {
34+
pub fn reset(&mut self, reason: &str) {
3435
self.writer.close(reason);
3536
}
3637

0 commit comments

Comments
 (0)