-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Let's take a WritableStream
for example.
If it was a trait, could just implement it for a JsValue
, like so: impl WritableStream for JsValue { ... }
(with some codegen of course).
Then, if needed, we could very elegantly extend WritableStream
with WebTransportSendStream
with an explicit trait WebTransportSendStream: WritableStream { ... }
- and also implement the WebTransportSendStream
for JsValue
.
With the given WebIDL:
WebIDL
[Exposed=*, Transferable]
interface WritableStream {
constructor(optional object underlyingSink, optional QueuingStrategy strategy = {});
readonly attribute boolean locked;
Promise<undefined> abort(optional any reason);
Promise<undefined> close();
WritableStreamDefaultWriter getWriter();
};
[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportSendStream : WritableStream {
attribute WebTransportSendGroup? sendGroup;
attribute long long sendOrder;
Promise<WebTransportSendStreamStats> getStats();
WebTransportWriter getWriter();
};
The traits would look somewhat like this:
Traits
trait WritableStream: Sized + JsAny {
fn new() -> Self;
fn new_with_underlying_sink(underlying_sink: &impl JsObject) -> Self;
// ...
fn locked(&self) -> bool;
fn abort(&self) -> Promise<()>;
fn abort_with_reason(&self, reason: &impl JsAny) -> Promise<()>;
fn close(&self) -> Promise<()>;
fn get_writer(&self) -> Result<impl WritableStreamDefaultWriter>;
}
trait WebTransportSendStream: WritableStream + JsAny {
fn send_group(&self) -> Option<impl WebTransportSendGroup>;
fn set_send_group(&self, value: &impl WebTransportSendGroup) -> Option<impl WebTransportSendGroup>;
fn unset_send_group(&self);
fn send_order(&self) -> i64;
fn set_send_order(&self, value: i64);
fn unset_send_order(&self);
fn get_stats(&self) -> Promise<impl WebTransportSendStreamStats>;
fn get_writer(&self) -> Result<impl WebTransportWriter>;
}
and impls like this:
Impls
impl WritableStream for JsValue {
fn new() -> Self {
__shim_WritableStream_new()
}
fn new_with_underlying_sink(underlying_sink: &impl JsObject) -> Self {
__shim_WritableStream_new_with_underlying_sink(underlying_sink)
}
// ... and so on.
}
impl WebTransportSendStream for JsValue {
fn send_group(&self) -> Option<impl WebTransportSendGroup> {
__shim_WebTransportSendStream_send_group()
}
// ... and so on.
}
A couple things to note:
-
the idea of having a:JsAny
type, that would work somewhat like adyn std::any::Any
and enable typechecking of the underlying type of anyJsValue
let random_value: JsValue = ...; let stream: impl WebTransportSendStream = JsAny::as_unchecked<dyn WebTransportSendStream>(random_value); // might also have an `instanceof` and/or custom guard variants.
UPD: no! actually, what we just need is this:
trait JsAny { fn as_js_value(self: Self) -> JsValue }
;JsValue
already has all the impls, so this effectively allows us to castimpl WebTransportSendStream
toJsValue
and from there to anything:let random_value: JsValue = ...; // Works cause of impl WebTransportSendStream for JsValue. let stream: impl WebTransportSendStream = random_value; // Works cause WebTransportSendStream: WritableStream. let stream: impl WritableStream = stream; // Doesn't work, as this type of generalization is not necessarily ture: not every `impl WritableStream` is a `impl WebTransportSendStream` let stream: impl WebTransportSendStream = stream; // This works though. let stream: impl WebTransportSendStream = JsAny::as_js_value(stream);
This might look scary - but you would just always use generics or trait object if an issue is encountered here.
Also, we should consider having something like this:
JsValue<dyn WebTransportSendStream>
- theJsValue
is already effectively a pointer to a value, but this way it can also carry on the information about the associated API.Then we'd implement the traits for
impl WebTransportSendStream for JsValue<dyn WebTransportSendStream> { ... }
to provide the type restrictions... -
the shims being standalone functions instead of being implementation details of a given type.
Originally posted by @MOZGIII in #3933 (comment)