Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c57710a
fix(bindgen): stream drop logic
vados-cosmonic Mar 26, 2026
a643070
test(jco): add test for sync closed stream
vados-cosmonic Mar 26, 2026
27f2247
test(jco): ensure that last read is undefined
vados-cosmonic Mar 26, 2026
559da7f
test(jco): add test for host->host, host->guest closed streams
vados-cosmonic Mar 26, 2026
8adaa4b
test(jco): add short reads test
vados-cosmonic Mar 26, 2026
45adfd6
test(jco): add inter-task comms test
vados-cosmonic Mar 26, 2026
437ca78
refactor(bindgen): late handling of string encoding
vados-cosmonic Mar 26, 2026
fcce13a
test(jco): add read resource stream test
vados-cosmonic Mar 26, 2026
7af65c3
test(jco): add component for stream-rx tests
vados-cosmonic Mar 27, 2026
943cd0b
feat(bindgen): implement Instruction::StreamLower
vados-cosmonic Mar 28, 2026
4a45db7
test(jco): add test for stream lower impl
vados-cosmonic Mar 28, 2026
1ea3db5
feat(bindgen): host side stream writes from any async iterator
vados-cosmonic Mar 29, 2026
a7d0d53
test(jco): finish test for sync stream passthrough
vados-cosmonic Mar 29, 2026
b759a2b
fix(bindgen): check for host data in host-controlled streams
vados-cosmonic Mar 29, 2026
6e75ff2
fix(bindgen): done check during read
vados-cosmonic Mar 29, 2026
fde9311
test(jco): update tests with async itereator adoption
vados-cosmonic Mar 30, 2026
c3abb11
chore(bindgen): clippy
vados-cosmonic Mar 30, 2026
3879e9d
chore(jco): lint
vados-cosmonic Mar 30, 2026
d2d2b9a
test(jco): fix stream test
vados-cosmonic Mar 30, 2026
62c3154
feat(bindgen): add explicit checks for lowered numeric primitives
vados-cosmonic Mar 30, 2026
a19e281
test(jco): update stream lift tests
vados-cosmonic Mar 30, 2026
76b461a
fix(bindgen): fix Instruction::StreamLift in async contexts
vados-cosmonic Mar 30, 2026
a4b9e98
test(jco): async passthrough stream lower test
vados-cosmonic Mar 30, 2026
fbe2b96
refactor(bindgen): rework lowering code
vados-cosmonic Mar 30, 2026
057b24a
test(jco): implement tests for stream lower values
vados-cosmonic Mar 30, 2026
7beab04
fix(bindgen): host-side write post-read event clearing
vados-cosmonic Mar 31, 2026
893727f
test(jco): add more lower tests
vados-cosmonic Mar 31, 2026
45a1af7
fix(bindgen): missing ctx in memory usage
vados-cosmonic Mar 31, 2026
2db5f9d
fix(bindgen): async string flat lowering missing realloc
vados-cosmonic Mar 31, 2026
161b20f
test(jco): fix & re-enable tests for primitives and string
vados-cosmonic Mar 31, 2026
2dfb417
fix(bindgen): async stream record lowering impl
vados-cosmonic Mar 31, 2026
4636867
test(jco): add async record lower test
vados-cosmonic Mar 31, 2026
c6f02a4
fix(bindgen): fill in missing lower impls
vados-cosmonic Mar 31, 2026
e882983
test(jco): add async stream lower variant test
vados-cosmonic Mar 31, 2026
02d77d6
fix(bindgen): utf16 decode logic
vados-cosmonic Mar 31, 2026
57cb0b1
fix(bindgen): revert utf16 encoding changes
vados-cosmonic Mar 31, 2026
c59060b
test(jco): adapt closed stream test to async iterator semantics
vados-cosmonic Mar 31, 2026
b5be1db
chore(bindgen): fmt
vados-cosmonic Mar 31, 2026
c68cd8f
test(jco): move readable stream creating helper, fix test
vados-cosmonic Mar 31, 2026
0ff4016
chore(jco): lint
vados-cosmonic Mar 31, 2026
27e36ad
fix(bindgen): async stream option & result lowering
vados-cosmonic Apr 1, 2026
bb11855
test(jco): add async stream lower variant test
vados-cosmonic Apr 1, 2026
ca6c9c3
fix(bindgen): option, result, flag lowers
vados-cosmonic Apr 1, 2026
be91d32
fix(bindgen): async stream list lower impl
vados-cosmonic Apr 1, 2026
bdcda00
test(jco): add more stream lower tests
vados-cosmonic Apr 1, 2026
791b296
refactor(bindgen): use older iteration pattern for node 18/20
vados-cosmonic Apr 1, 2026
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
11 changes: 5 additions & 6 deletions crates/js-component-bindgen/src/esm_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,9 +396,6 @@ impl EsmBindgen {
maybe_quote_member(specifier)
);
for (external_name, local_name) in bound_external_names {
// For imports that are functions, ensure that they are noted as host provided
uwriteln!(output, "{local_name}._isHostProvided = true;");

uwriteln!(
output,
r#"
Expand All @@ -409,6 +406,9 @@ impl EsmBindgen {
}}
"#,
);

// For imports that are functions, ensure that they are noted as host provided
uwriteln!(output, "{local_name}._isHostProvided = true;");
}
} else if let Some(idl_binding) = idl_binding {
uwrite!(
Expand Down Expand Up @@ -480,9 +480,6 @@ impl EsmBindgen {

// Process all external host-provided imports
for (member_name, local_name) in generated_member_names {
// For imports that are functions, ensure that they are noted as host provided
uwriteln!(output, "{local_name}._isHostProvided = true;");

// Ensure that the imports we destructured were defined
// (if they were not, the user is likely missing an import @ instantiation time)
uwriteln!(
Expand All @@ -495,6 +492,8 @@ impl EsmBindgen {
}}
"#,
);
// For imports that are functions, ensure that they are noted as host provided
uwriteln!(output, "{local_name}._isHostProvided = true;");
}
}
}
Expand Down
435 changes: 311 additions & 124 deletions crates/js-component-bindgen/src/function_bindgen.rs

Large diffs are not rendered by default.

51 changes: 48 additions & 3 deletions crates/js-component-bindgen/src/intrinsics/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ impl ComponentIntrinsic {
let waitable_class = Intrinsic::Waitable(WaitableIntrinsic::WaitableClass).name();
let get_or_create_async_state_fn = Self::GetOrCreateAsyncState.name();
let promise_with_resolvers_fn = Intrinsic::PromiseWithResolversPonyfill.name();
let stream_readable_end_class =
Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamReadableEndClass).name();

output.push_str(&format!(
r#"
Expand Down Expand Up @@ -466,9 +468,48 @@ impl ComponentIntrinsic {
return new {waitable_class}({{ target: args?.target, }});
}}

createReadableStreamEnd(args) {{
{debug_log_fn}('[{component_async_state_class}#createStreamEnd()] args', args);
const {{ tableIdx, elemMeta, hostInjectFn }} = args;

const {{ table: localStreamTable, componentIdx }} = {global_stream_table_map}[tableIdx];
if (!localStreamTable) {{
throw new Error(`missing global stream table lookup for table [${{tableIdx}}] while creating stream`);
}}
if (componentIdx !== this.#componentIdx) {{
throw new Error('component idx mismatch while creating stream');
}}

const waitable = this.createWaitable();
const streamEnd = new {stream_readable_end_class}({{
tableIdx,
elemMeta,
hostInjectFn,
pendingBufferMeta: {{}},
target: `stream read end (lowered, @init)`,
waitable,
}});

streamEnd.setWaitableIdx(this.handles.insert(streamEnd));
streamEnd.setHandle(localStreamTable.insert(streamEnd));
if (streamEnd.streamTableIdx() !== tableIdx) {{
throw new Error("unexpectedly mismatched stream table");
}}
const streamEndWaitableIdx = streamEnd.waitableIdx();
const streamEndHandle = streamEnd.handle();
waitable.setTarget(`waitable for stream read end (lowered, waitable [${{streamEndWaitableIdx}}])`);
streamEnd.setTarget(`stream read end (lowered, waitable [${{streamEndWaitableIdx}}])`);

return {{
waitableIdx: streamEndWaitableIdx,
handle: streamEndHandle,
streamEnd,
}};
}}

createStream(args) {{
{debug_log_fn}('[{component_async_state_class}#createStream()] args', args);
const {{ tableIdx, elemMeta }} = args;
const {{ tableIdx, elemMeta, hostInjectFn }} = args;
if (tableIdx === undefined) {{ throw new Error("missing table idx while adding stream"); }}
if (elemMeta === undefined) {{ throw new Error("missing element metadata while adding stream"); }}

Expand All @@ -485,10 +526,10 @@ impl ComponentIntrinsic {

const stream = new {internal_stream_class}({{
tableIdx,
componentIdx: this.#componentIdx,
elemMeta,
readWaitable,
writeWaitable,
hostInjectFn,
}});
stream.setGlobalStreamMapRep({global_stream_map}.insert(stream));

Expand All @@ -513,17 +554,21 @@ impl ComponentIntrinsic {
readEnd.setTarget(`stream read end (waitable [${{readEndWaitableIdx}}])`);

return {{
writeEnd,
writeEndWaitableIdx,
writeEndHandle,
readEndWaitableIdx,
readEndHandle,
readEnd,
}};
}}

getStreamEnd(args) {{
{debug_log_fn}('[{component_async_state_class}#getStreamEnd()] args', args);
const {{ tableIdx, streamEndHandle, streamEndWaitableIdx }} = args;
if (tableIdx === undefined) {{ throw new Error('missing table idx while getting stream end'); }}
if (tableIdx === undefined) {{
throw new Error('missing table idx while getting stream end');
}}

const {{ table, componentIdx }} = {global_stream_table_map}[tableIdx];
const cstate = {get_or_create_async_state_fn}(componentIdx);
Expand Down
64 changes: 64 additions & 0 deletions crates/js-component-bindgen/src/intrinsics/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ pub enum ConversionIntrinsic {
ToUint8,

ToResultString,

/// Function that requires validity of various numeric primitive types (or throws a `TypeError`)
RequireValidNumericPrimitive,

/// Function that checks validity of various numeric primitive types
IsValidNumericPrimitive,
}

impl ConversionIntrinsic {
Expand Down Expand Up @@ -61,6 +67,8 @@ impl ConversionIntrinsic {
"toUint64",
"toUint64",
"toUint8",
Self::RequireValidNumericPrimitive.name(),
Self::IsValidNumericPrimitive.name(),
]
}

Expand All @@ -82,6 +90,8 @@ impl ConversionIntrinsic {
Self::I64ToF64 => "i64ToF64",
Self::F32ToI32 => "f32ToI32",
Self::F64ToI64 => "f64ToI64",
Self::RequireValidNumericPrimitive => "_requireValidNumericPrimitive",
Self::IsValidNumericPrimitive => "_isValidNumericPrimitive",
}
}

Expand Down Expand Up @@ -199,6 +209,60 @@ impl ConversionIntrinsic {
");
}

Self::RequireValidNumericPrimitive => {
let name = self.name();
let is_valid_numeric_primitive_fn = Self::IsValidNumericPrimitive.name();

output.push_str(&format!(r#"
function {name}(ty, v) {{
if (v === undefined || v === null || !{is_valid_numeric_primitive_fn}(ty, v)) {{
throw new TypeError(`invalid ${{ty}} value [${{v}}]`);
}}
return true;
}}
"#))
}

Self::IsValidNumericPrimitive => {
let name = self.name();
output.push_str(&format!(r#"
function {name}(ty, v) {{
if (v === undefined || v === null) {{ return false; }}
switch (ty) {{
case 'bool':
return v === 0 || v === 1;
break;
case 'u8':
return v >= 0 && v <= 255;
break;
case 's8':
return v >= -128 && v <= 127;
break;
case 'u16':
return v >= 0 && v <= 65535;
break;
case 's16':
return v >= -32768 && v <= 32767;
case 'u32':
return v >= 0 && v <= 4_294_967_295;
case 's32':
return v >= -2_147_483_648 && v <= 2_147_483_647;
case 'u64':
return typeof v === 'bigint' && v >= 0 && v <= 18_446_744_073_709_551_615n;
case 's64':
return typeof v === 'bigint' && v >= -9223372036854775808n && v <= 9223372036854775807n;
break;
case 'f32':
case 'f64': return typeof v === 'number';
default:
return false;
}}
return true;
}}
"#
));
}

}
}
}
Loading
Loading