Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented UnderlyingSource and added a trivial ReadableStream constructor #254

Merged
merged 6 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions crates/jstz_api/src/idl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,20 @@ impl ArrayBufferLike for JsBufferSource {
}
}
}

// https://webidl.spec.whatwg.org/#idl-types

pub type Any = JsValue;
pub type Bytes = i8;
pub type Octet = u8;
pub type Short = i16;
pub type UnsignedShort = u16;
pub type Long = i32;
pub type UnsignedLong = u32;
pub type LongLong = i64;
pub type UnsignedLongLong = u64;
pub type UnrestrictedFloat = f32;
pub type UnrestrictedDouble = f64;

pub type PositiveInteger = UnsignedLongLong;
pub type Number = f64;
2 changes: 2 additions & 0 deletions crates/jstz_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub mod idl;
pub mod js_log;
mod kv;
pub mod random;
pub mod stream;
pub mod todo;
pub mod url;
pub mod urlpattern;

Expand Down
14 changes: 14 additions & 0 deletions crates/jstz_api/src/stream/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use boa_engine::Context;

use self::readable::ReadableStreamApi;

pub mod readable;
mod tmp;

pub struct StreamApi;

impl jstz_core::Api for StreamApi {
fn init(self, context: &mut Context<'_>) {
ReadableStreamApi.init(context);
}
}
61 changes: 61 additions & 0 deletions crates/jstz_api/src/stream/readable/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use boa_engine::{value::TryFromJs, Context, JsArgs, JsResult};
use boa_gc::{custom_trace, Finalize, Trace};
use jstz_core::native::{
register_global_class, ClassBuilder, JsNativeObject, NativeClass,
};

use crate::stream::readable::underlying_source::UnderlyingSource;

pub mod underlying_source;

pub struct ReadableStream {
// TODO
}

impl Finalize for ReadableStream {
fn finalize(&self) {
todo!()
}
}

unsafe impl Trace for ReadableStream {
custom_trace!(this, {
let _ = this;
todo!()
});
}

pub struct ReadableStreamClass;

impl NativeClass for ReadableStreamClass {
type Instance = ReadableStream;

const NAME: &'static str = "ReadableStream";

fn constructor(
_this: &JsNativeObject<Self::Instance>,
args: &[boa_engine::JsValue],
context: &mut Context<'_>,
) -> JsResult<Self::Instance> {
let underlying_source =
Option::<UnderlyingSource>::try_from_js(args.get_or_undefined(0), context)?;
let _ = underlying_source;
todo!()
}

fn init(class: &mut ClassBuilder<'_, '_>) -> JsResult<()> {
// TODO
let _ = class;
Ok(())
}
}

pub struct ReadableStreamApi;

impl jstz_core::Api for ReadableStreamApi {
fn init(self, context: &mut Context<'_>) {
register_global_class::<ReadableStreamClass>(context)
.expect("The `ReadableStream` class shouldn't exist yet")
// TODO
}
}
389 changes: 389 additions & 0 deletions crates/jstz_api/src/stream/readable/underlying_source.rs

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions crates/jstz_api/src/stream/tmp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! Temporary definitions to allow compiling before defining all types

use boa_engine::{
js_string, property::PropertyKey, Context, JsObject, JsResult, JsValue,
};

use crate::todo::Todo;

pub type ReadableStreamDefaultController = Todo;
pub type ReadableByteStreamController = Todo;

// TODO check that this function works as intended in all cases,
// and move it either to a new derive macro for TryFromJs, or to JsObject
pub fn get_jsobject_property(
obj: &JsObject,
name: &str,
context: &mut Context<'_>,
) -> JsResult<JsValue> {
let key = PropertyKey::from(js_string!(name));
let has_prop = obj.has_property(key.clone(), context)?;
if has_prop {
obj.get(key, context)
} else {
Ok(JsValue::Undefined)
}
}
40 changes: 40 additions & 0 deletions crates/jstz_api/src/todo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use boa_engine::value::TryFromJs;
use boa_gc::{custom_trace, Finalize, Trace};
use jstz_core::value::IntoJs;

/// A placeholder for types that have yet to be defined
#[derive(Debug)]
pub enum Todo {
Todo,
}

impl Finalize for Todo {
fn finalize(&self) {
todo!()
}
}

#[allow(unused_variables)]
unsafe impl Trace for Todo {
custom_trace!(this, todo!());
}

#[allow(unused_variables)]
impl IntoJs for Todo {
fn into_js(
self,
context: &mut boa_engine::prelude::Context<'_>,
) -> boa_engine::prelude::JsValue {
todo!()
}
}

#[allow(unused_variables)]
impl TryFromJs for Todo {
fn try_from_js(
value: &boa_engine::prelude::JsValue,
context: &mut boa_engine::prelude::Context<'_>,
) -> boa_engine::prelude::JsResult<Self> {
todo!()
}
}
5 changes: 3 additions & 2 deletions crates/jstz_cli/src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::js_logger::PrettyLogger;
use anyhow::Result;
use boa_engine::{js_string, JsResult, JsValue, Source};
use jstz_api::{
encoding::EncodingApi, http::HttpApi, js_log::set_js_logger, url::UrlApi,
urlpattern::UrlPatternApi, ConsoleApi, KvApi,
encoding::EncodingApi, http::HttpApi, js_log::set_js_logger, stream::StreamApi,
url::UrlApi, urlpattern::UrlPatternApi, ConsoleApi, KvApi,
};
use jstz_core::host::HostRuntime;
use jstz_core::{
Expand Down Expand Up @@ -72,6 +72,7 @@ pub fn exec(self_address: Option<String>, cfg: &Config) -> Result<()> {
rt.context(),
);
realm_clone.register_api(EncodingApi, rt.context());
realm_clone.register_api(StreamApi, rt.context());
realm_clone.register_api(UrlApi, rt.context());
realm_clone.register_api(UrlPatternApi, rt.context());
realm_clone.register_api(HttpApi, rt.context());
Expand Down
123 changes: 123 additions & 0 deletions crates/jstz_core/src/js_fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use std::{marker::PhantomData, ops::Deref};

use boa_engine::{
object::builtins::JsFunction, value::TryFromJs, Context, JsResult, JsValue,
};
use boa_gc::{custom_trace, Finalize, Trace};

use crate::value::IntoJs;

pub trait IntoJsArgs {
type Target: AsRef<[JsValue]>;
fn into_js_args(self, context: &mut Context<'_>) -> Self::Target;
}

impl IntoJsArgs for () {
type Target = [JsValue; 0];
fn into_js_args(self, _context: &mut Context<'_>) -> Self::Target {
[]
}
}

impl<T0: IntoJs> IntoJsArgs for (T0,) {
type Target = [JsValue; 1];
fn into_js_args(self, context: &mut Context<'_>) -> Self::Target {
[self.0.into_js(context)]
}
}

impl<T0: IntoJs, T1: IntoJs> IntoJsArgs for (T0, T1) {
type Target = [JsValue; 2];
fn into_js_args(self, context: &mut Context<'_>) -> Self::Target {
[self.0.into_js(context), self.1.into_js(context)]
}
}

impl<T0: IntoJs, T1: IntoJs, T2: IntoJs> IntoJsArgs for (T0, T1, T2) {
type Target = [JsValue; 3];
fn into_js_args(self, context: &mut Context<'_>) -> Self::Target {
[
self.0.into_js(context),
self.1.into_js(context),
self.2.into_js(context),
]
}
}

/// A `JsFn<T, I, O>` is a `JsFunction` tagged with some Rust types used to handle the `TryFromJs` and `IntoJs` conversions automatically:
/// - `T` is the type of the `this` parameter;
/// - `N` is the arity;
/// - `I` is a tuple `(I1, ..., IN)` that contains the types of the parameters;
/// - `O` is the type of the output.
#[derive(Debug)]
pub struct JsFn<T: IntoJs, I: IntoJsArgs, O: TryFromJs> {
function: JsFunction,
_this_type: PhantomData<T>,
_inputs_type: PhantomData<I>,
_output_type: PhantomData<O>,
}

impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> Finalize for JsFn<T, I, O> {}

unsafe impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> Trace for JsFn<T, I, O> {
custom_trace!(this, {
mark(&this.function);
});
}

impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> Deref for JsFn<T, I, O> {
type Target = JsFunction;

fn deref(&self) -> &Self::Target {
&self.function
}
}

impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> From<JsFn<T, I, O>> for JsFunction {
fn from(value: JsFn<T, I, O>) -> Self {
value.function
}
}

impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> From<JsFunction> for JsFn<T, I, O> {
fn from(value: JsFunction) -> Self {
JsFn {
function: value,
_this_type: PhantomData,
_inputs_type: PhantomData,
_output_type: PhantomData,
}
}
}

impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> From<JsFn<T, I, O>> for JsValue {
fn from(value: JsFn<T, I, O>) -> Self {
value.function.into()
}
}

// impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> TryFrom<JsValue> for JsFn<T, I, O>
// This is implementable, but the right way to implement it would be to lift the implementation of `TryFromJs` for `JsFunction` (that does not use the context) to an implementation of `TryFrom<JsFunction>` in boa
// (If it is eventually implemented, then the implementation of TryFromJs below should use it)

impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> IntoJs for JsFn<T, I, O> {
fn into_js(self, _context: &mut Context<'_>) -> JsValue {
self.function.into()
}
}

impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> TryFromJs for JsFn<T, I, O> {
fn try_from_js(value: &JsValue, context: &mut Context<'_>) -> JsResult<Self> {
JsFunction::try_from_js(value, context).map(JsFn::from)
}
}

impl<T: IntoJs, I: IntoJsArgs, O: TryFromJs> JsFn<T, I, O> {
pub fn call(&self, this: T, inputs: I, context: &mut Context<'_>) -> JsResult<O> {
let js_this = this.into_js(context);
let js_args = inputs.into_js_args(context);
self.deref()
.call(&js_this, js_args.as_ref(), context)
.and_then(|output| O::try_from_js(&output, context))
}
}
1 change: 1 addition & 0 deletions crates/jstz_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub use error::{Error, Result};
pub mod future;
pub mod host;
pub mod iterators;
pub mod js_fn;
pub mod kv;
pub mod native;
pub mod realm;
Expand Down
2 changes: 1 addition & 1 deletion crates/jstz_core/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub use boa_engine::{object::NativeObject, NativeFunction};
use crate::value::IntoJs;

/// This struct permits Rust types to be passed around as JavaScript objects.
#[derive(Trace, Finalize)]
#[derive(Trace, Finalize, Debug)]
pub struct JsNativeObject<T: NativeObject> {
inner: JsValue,
_phantom: PhantomData<T>,
Expand Down
1 change: 1 addition & 0 deletions crates/jstz_core/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub trait IntoJs {
fn into_js(self, context: &mut Context<'_>) -> JsValue;
}

#[macro_export]
macro_rules! impl_into_js_from_into {
($($T: ty), *) => {
$(
Expand Down
Loading