Skip to content

Commit 819837a

Browse files
fix(bindgen): flat stream lift for nested streams
1 parent 7c2c787 commit 819837a

3 files changed

Lines changed: 88 additions & 31 deletions

File tree

crates/js-component-bindgen/src/intrinsics/lift.rs

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,43 +1017,65 @@ impl LiftIntrinsic {
10171017
Intrinsic::AsyncStream(AsyncStreamIntrinsic::ExternalStreamClass).name();
10181018
let lift_flat_stream_fn = self.name();
10191019
let global_stream_table_map = AsyncStreamIntrinsic::GlobalStreamTableMap.name();
1020+
let lift_u32 = Self::LiftFlatU32.name();
10201021

10211022
output.push_str(&format!(r#"
1022-
function {lift_flat_stream_fn}(streamTableIdx, ctx) {{
1023-
{debug_log_fn}('[{lift_flat_stream_fn}()] args', {{ streamTableIdx, ctx }});
1024-
const {{ memory, useDirectParams, params }} = ctx;
1023+
function {lift_flat_stream_fn}(meta) {{
1024+
const {{
1025+
streamTableIdx,
1026+
componentIdx,
1027+
isBorrowedType,
1028+
isNoneType,
1029+
isNumericTypeJs,
1030+
}} = meta;
1031+
1032+
return function {lift_flat_stream_fn}Inner(ctx) {{
1033+
{debug_log_fn}('[{lift_flat_stream_fn}()] args', {{ ctx }});
1034+
1035+
const streamMeta = {global_stream_table_map}[streamTableIdx];
1036+
if (streamMeta.componentIdx !== componentIdx) {{
1037+
throw new Error('unexpectedly mismatched component idx');
1038+
}}
1039+
const {{ table }} = streamMeta;
1040+
if (componentIdx === undefined || !table) {{
1041+
throw new Error(`invalid global stream table state for table [${{tableIdx}}]`);
1042+
}}
10251043
1026-
const {{ table, componentIdx }} = {global_stream_table_map}[streamTableIdx];
1027-
if (componentIdx === undefined || !table) {{
1028-
throw new Error(`invalid global stream table state for table [${{tableIdx}}]`);
1029-
}}
1044+
let streamEndWaitableIdx;
1045+
if (ctx.useDirectParams) {{
1046+
streamEndWaitableIdx = ctx.params[0];
1047+
ctx.params = ctx.params.slice(1);
1048+
}} else {{
1049+
const [waitableIdx, newCtx] = {lift_u32}(ctx);
1050+
ctx = newCtx;
1051+
streamEndWaitableIdx = waitableIdx;
1052+
}}
10301053
1031-
const cstate = {get_or_create_async_state_fn}(componentIdx);
1032-
if (!cstate) {{ throw new Error(`missing async state for component [${{componentIdx}}]`); }}
1054+
if (!streamEndWaitableIdx) {{ throw new Error('missing stream idx'); }}
10331055
1034-
const streamEndWaitableIdx = params[0];
1035-
if (!streamEndWaitableIdx) {{ throw new Error('missing stream idx'); }}
1056+
const cstate = {get_or_create_async_state_fn}(componentIdx);
1057+
if (!cstate) {{ throw new Error(`missing async state for component [${{componentIdx}}]`); }}
10361058
1037-
const streamEnd = cstate.getStreamEnd({{ tableIdx: streamTableIdx, streamEndWaitableIdx }});
1038-
if (!streamEnd) {{
1039-
throw new Error(`missing stream end [${{streamEndWaitableIdx}}] (table [${{streamTableIdx}}]) in component [${{componentIdx}}] during lift`);
1040-
}}
1059+
const streamEnd = cstate.getStreamEnd({{ tableIdx: streamTableIdx, streamEndWaitableIdx }});
1060+
if (!streamEnd) {{
1061+
throw new Error(`missing stream end [${{streamEndWaitableIdx}}] (table [${{streamTableIdx}}]) in component [${{componentIdx}}] during lift`);
1062+
}}
10411063
1042-
// TODO: check for borrowed type
1043-
// TODO: check for readable only
1044-
// TODO: confirm shared type matches tyep for lift
1045-
// TODO: check for IDLE state
1046-
1047-
const stream = new {external_stream_class}({{
1048-
globalRep: streamEnd.globalStreamMapRep(),
1049-
isReadable: streamEnd.isReadable(),
1050-
isWritable: streamEnd.isWritable(),
1051-
writeFn: (v) => {{ return streamEnd.write(v); }},
1052-
readFn: () => {{ return streamEnd.read(); }},
1053-
dropFn: () => {{ return streamEnd.drop(); }},
1054-
}});
1055-
1056-
return [ stream, ctx ];
1064+
if (ctx.isBorrowed) {{ throw new Error('cannot lift flat stream of borrowed type'); }}
1065+
if (streamEnd.isWritable()) {{ throw new Error('only readable streams can be lifted'); }}
1066+
if (!streamEnd.isIdle()) {{ throw new Error('streams must be in idle state'); }}
1067+
1068+
const stream = new {external_stream_class}({{
1069+
globalRep: streamEnd.globalStreamMapRep(),
1070+
isReadable: streamEnd.isReadable(),
1071+
isWritable: streamEnd.isWritable(),
1072+
writeFn: (v) => {{ return streamEnd.write(v); }},
1073+
readFn: () => {{ return streamEnd.read(); }},
1074+
dropFn: () => {{ return streamEnd.drop(); }},
1075+
}});
1076+
1077+
return [ stream, ctx ];
1078+
}}
10571079
}}
10581080
"#));
10591081
}

crates/js-component-bindgen/src/intrinsics/p3/async_stream.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,7 @@ impl AsyncStreamIntrinsic {
10061006
isDone() {{ return this.getCopyState() === {stream_end_class}.CopyState.DONE; }}
10071007
isCompleted() {{ return this.getCopyState() === {stream_end_class}.CopyState.COMPLETED; }}
10081008
isDropped() {{ return this.getCopyState() === {stream_end_class}.CopyState.DROPPED; }}
1009+
isIdle() {{ return this.getCopyState() === {stream_end_class}.CopyState.IDLE; }}
10091010
10101011
{action_impl}
10111012
{inner_rw_impl}

crates/js-component-bindgen/src/transpile_bindgen.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4897,7 +4897,41 @@ pub fn gen_flat_lift_fn_js_expr(
48974897
intrinsic_mgr.add_intrinsic(Intrinsic::Lift(LiftIntrinsic::LiftFlatStream));
48984898
let table_idx = ty_idx.as_u32();
48994899
let f = Intrinsic::Lift(LiftIntrinsic::LiftFlatStream).name();
4900-
format!("{f}.bind(null, {table_idx})")
4900+
let table_ty = &component_types[*ty_idx];
4901+
let component_idx = table_ty.instance.as_u32();
4902+
let stream_ty_idx = table_ty.ty;
4903+
let stream_ty = &component_types[stream_ty_idx];
4904+
let payload = stream_ty.payload;
4905+
let (is_borrowed, is_none_type_js, is_numeric_type_js) = match payload {
4906+
None => (false, true, false),
4907+
Some(t) => (
4908+
matches!(t, InterfaceType::Borrow(_)),
4909+
false,
4910+
matches!(
4911+
ty,
4912+
InterfaceType::U8
4913+
| InterfaceType::U16
4914+
| InterfaceType::U32
4915+
| InterfaceType::U64
4916+
| InterfaceType::S8
4917+
| InterfaceType::S16
4918+
| InterfaceType::S32
4919+
| InterfaceType::S64
4920+
| InterfaceType::Float32
4921+
| InterfaceType::Float64
4922+
),
4923+
),
4924+
};
4925+
4926+
format!(
4927+
r#"{f}({{
4928+
streamTableIdx: {table_idx},
4929+
componentIdx: {component_idx},
4930+
isBorrowedType: {is_borrowed},
4931+
isNoneType: {is_none_type_js},
4932+
isNumericTypeJs: {is_numeric_type_js},
4933+
}})"#
4934+
)
49014935
}
49024936

49034937
InterfaceType::ErrorContext(ty_idx) => {

0 commit comments

Comments
 (0)