use wasm_encoder::{FunctionSection, TypeSection, ValType};
use super::super::types::TypeRegistry;
use super::super::wasip2_imports::{Wasip2ImportRegistry, Wasip2ImportSlot};
use super::{
TcpCloseIndices, TcpConnectIndices, TcpPingIndices, TcpReadLineIndices, TcpSendIndices,
TcpWriteLineIndices,
};
pub(in crate::codegen::wasm_gc) struct TcpHelpers {
pub connect: Option<TcpConnectIndices>,
pub format_id: Option<(u32, u32)>,
pub parse_id: Option<(u32, u32)>,
pub write_line: Option<TcpWriteLineIndices>,
pub read_line: Option<TcpReadLineIndices>,
pub close: Option<TcpCloseIndices>,
pub send: Option<TcpSendIndices>,
pub ping: Option<TcpPingIndices>,
}
pub(in crate::codegen::wasm_gc) fn allocate(
registry: &TypeRegistry,
wasip2_imports: &Wasip2ImportRegistry,
types: &mut TypeSection,
next_type_idx: &mut u32,
next_builtin_fn_idx: &mut u32,
) -> TcpHelpers {
let connect = allocate_connect(
registry,
wasip2_imports,
types,
next_type_idx,
next_builtin_fn_idx,
);
let format_id = allocate_format_id(
registry,
&connect,
types,
next_type_idx,
next_builtin_fn_idx,
);
let parse_id = allocate_parse_id(registry, types, next_type_idx, next_builtin_fn_idx);
let write_line = allocate_write_line(
registry,
wasip2_imports,
parse_id,
types,
next_type_idx,
next_builtin_fn_idx,
);
let read_line = allocate_read_line(
registry,
wasip2_imports,
parse_id,
types,
next_type_idx,
next_builtin_fn_idx,
);
let close = allocate_close(
registry,
wasip2_imports,
parse_id,
types,
next_type_idx,
next_builtin_fn_idx,
);
let send = allocate_send(
registry,
wasip2_imports,
types,
next_type_idx,
next_builtin_fn_idx,
);
let ping = allocate_ping(
registry,
wasip2_imports,
types,
next_type_idx,
next_builtin_fn_idx,
);
TcpHelpers {
connect,
format_id,
parse_id,
write_line,
read_line,
close,
send,
ping,
}
}
pub(in crate::codegen::wasm_gc) fn register_funcs(
funcs: &mut FunctionSection,
helpers: &TcpHelpers,
) {
if let Some(t) = &helpers.connect {
funcs.function(t.fn_type);
}
if let Some((ty, _)) = helpers.format_id {
funcs.function(ty);
}
if let Some((ty, _)) = helpers.parse_id {
funcs.function(ty);
}
if let Some(t) = &helpers.write_line {
funcs.function(t.fn_type);
}
if let Some(t) = &helpers.read_line {
funcs.function(t.fn_type);
}
if let Some(t) = &helpers.close {
funcs.function(t.fn_type);
}
if let Some(t) = &helpers.send {
funcs.function(t.fn_type);
}
if let Some(t) = &helpers.ping {
funcs.function(t.fn_type);
}
}
fn allocate_connect(
registry: &TypeRegistry,
wasip2_imports: &Wasip2ImportRegistry,
types: &mut TypeSection,
next_type_idx: &mut u32,
next_builtin_fn_idx: &mut u32,
) -> Option<TcpConnectIndices> {
let string_idx = registry.string_array_type_idx?;
let result_idx = registry.result_type_idx("Result<Tcp.Connection,String>")?;
let stub_seg = registry.string_literal_segment(b"tcp: connect not yet implemented")?;
let dns_seg = registry.string_literal_segment(b"tcp: dns resolve failed")?;
let no_addr_seg = registry.string_literal_segment(b"tcp: dns no addresses")?;
let sock_err_seg = registry.string_literal_segment(b"tcp: socket create failed")?;
let conn_err_seg = registry.string_literal_segment(b"tcp: connect failed")?;
let port_err_seg = registry.string_literal_segment(b"tcp: port out of range")?;
let limit_err_seg =
registry.string_literal_segment(b"tcp: connection limit reached (256 max)")?;
let gates: &[Wasip2ImportSlot] = &[
Wasip2ImportSlot::SocketsInstanceNetworkInstanceNetwork,
Wasip2ImportSlot::SocketsIpNameLookupResolveAddresses,
Wasip2ImportSlot::SocketsIpNameLookupResourceDropResolveAddressStream,
Wasip2ImportSlot::SocketsIpNameLookupResolveAddressStreamSubscribe,
Wasip2ImportSlot::IoPollPoll,
Wasip2ImportSlot::IoPollResourceDropPollable,
Wasip2ImportSlot::SocketsIpNameLookupResolveNextAddress,
Wasip2ImportSlot::SocketsTcpCreateSocketCreateTcpSocket,
Wasip2ImportSlot::SocketsTcpStartConnect,
Wasip2ImportSlot::SocketsTcpSubscribe,
Wasip2ImportSlot::SocketsTcpFinishConnect,
Wasip2ImportSlot::SocketsTcpResourceDropTcpSocket,
];
for slot in gates {
wasip2_imports.lookup_wasm_fn_idx(*slot)?;
}
let r_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(result_idx),
});
let s_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(string_idx),
});
types.ty().function([s_ref, ValType::I64], [r_ref]);
let fn_type = *next_type_idx;
*next_type_idx += 1;
let fn_idx = *next_builtin_fn_idx;
*next_builtin_fn_idx += 1;
Some(TcpConnectIndices {
fn_type,
fn_idx,
string_type_idx: string_idx,
stub_err_segment_idx: stub_seg,
stub_err_len: b"tcp: connect not yet implemented".len() as u32,
dns_err_segment_idx: dns_seg,
dns_err_len: b"tcp: dns resolve failed".len() as u32,
no_addr_segment_idx: no_addr_seg,
no_addr_len: b"tcp: dns no addresses".len() as u32,
sock_err_segment_idx: sock_err_seg,
sock_err_len: b"tcp: socket create failed".len() as u32,
conn_err_segment_idx: conn_err_seg,
conn_err_len: b"tcp: connect failed".len() as u32,
port_err_segment_idx: port_err_seg,
port_err_len: b"tcp: port out of range".len() as u32,
limit_err_segment_idx: limit_err_seg,
limit_err_len: b"tcp: connection limit reached (256 max)".len() as u32,
})
}
fn allocate_format_id(
registry: &TypeRegistry,
connect: &Option<TcpConnectIndices>,
types: &mut TypeSection,
next_type_idx: &mut u32,
next_builtin_fn_idx: &mut u32,
) -> Option<(u32, u32)> {
connect.as_ref()?;
let s_idx = registry
.string_array_type_idx
.expect("tcp_format_id allocation gated on tcp_connect which requires the string slot");
let s_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(s_idx),
});
types.ty().function([ValType::I32], [s_ref]);
let ty = *next_type_idx;
*next_type_idx += 1;
let fn_idx = *next_builtin_fn_idx;
*next_builtin_fn_idx += 1;
Some((ty, fn_idx))
}
fn allocate_parse_id(
registry: &TypeRegistry,
types: &mut TypeSection,
next_type_idx: &mut u32,
next_builtin_fn_idx: &mut u32,
) -> Option<(u32, u32)> {
registry.tcp_slot_type_idx?;
let s_idx = registry.string_array_type_idx?;
let s_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(s_idx),
});
types.ty().function([s_ref], [ValType::I32]);
let ty = *next_type_idx;
*next_type_idx += 1;
let fn_idx = *next_builtin_fn_idx;
*next_builtin_fn_idx += 1;
Some((ty, fn_idx))
}
fn allocate_write_line(
registry: &TypeRegistry,
wasip2_imports: &Wasip2ImportRegistry,
parse_id: Option<(u32, u32)>,
types: &mut TypeSection,
next_type_idx: &mut u32,
next_builtin_fn_idx: &mut u32,
) -> Option<TcpWriteLineIndices> {
let string_idx = registry.string_array_type_idx?;
let rec_idx = registry.record_type_idx("Tcp.Connection")?;
let slot_idx = registry.tcp_slot_type_idx?;
let pool_idx = registry.tcp_pool_type_idx?;
let result_idx = registry.result_type_idx("Result<Unit,String>")?;
let write_err_seg = registry.string_literal_segment(b"tcp: write failed")?;
let unknown_seg = registry.string_literal_segment(b"tcp: unknown connection")?;
wasip2_imports.lookup_wasm_fn_idx(Wasip2ImportSlot::OutputStreamBlockingWriteAndFlush)?;
parse_id?;
let conn_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(rec_idx),
});
let s_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(string_idx),
});
let res_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(result_idx),
});
types.ty().function([conn_ref, s_ref], [res_ref]);
let ty = *next_type_idx;
*next_type_idx += 1;
let fn_idx = *next_builtin_fn_idx;
*next_builtin_fn_idx += 1;
Some(TcpWriteLineIndices {
fn_type: ty,
fn_idx,
string_type_idx: string_idx,
tcp_connection_type_idx: rec_idx,
tcp_slot_type_idx: slot_idx,
tcp_pool_type_idx: pool_idx,
write_err_segment_idx: write_err_seg,
write_err_len: b"tcp: write failed".len() as u32,
unknown_segment_idx: unknown_seg,
unknown_len: b"tcp: unknown connection".len() as u32,
})
}
fn allocate_read_line(
registry: &TypeRegistry,
wasip2_imports: &Wasip2ImportRegistry,
parse_id: Option<(u32, u32)>,
types: &mut TypeSection,
next_type_idx: &mut u32,
next_builtin_fn_idx: &mut u32,
) -> Option<TcpReadLineIndices> {
let string_idx = registry.string_array_type_idx?;
let rec_idx = registry.record_type_idx("Tcp.Connection")?;
let slot_idx = registry.tcp_slot_type_idx?;
let pool_idx = registry.tcp_pool_type_idx?;
let result_idx = registry.result_type_idx("Result<String,String>")?;
let eof_seg = registry.string_literal_segment(b"tcp: eof")?;
let unknown_seg = registry.string_literal_segment(b"tcp: unknown connection")?;
wasip2_imports.lookup_wasm_fn_idx(Wasip2ImportSlot::InputStreamBlockingRead)?;
parse_id?;
let conn_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(rec_idx),
});
let res_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(result_idx),
});
types.ty().function([conn_ref], [res_ref]);
let ty = *next_type_idx;
*next_type_idx += 1;
let fn_idx = *next_builtin_fn_idx;
*next_builtin_fn_idx += 1;
Some(TcpReadLineIndices {
fn_type: ty,
fn_idx,
string_type_idx: string_idx,
result_type_idx: result_idx,
tcp_connection_type_idx: rec_idx,
tcp_slot_type_idx: slot_idx,
tcp_pool_type_idx: pool_idx,
eof_segment_idx: eof_seg,
eof_len: b"tcp: eof".len() as u32,
unknown_segment_idx: unknown_seg,
unknown_len: b"tcp: unknown connection".len() as u32,
})
}
fn allocate_close(
registry: &TypeRegistry,
wasip2_imports: &Wasip2ImportRegistry,
parse_id: Option<(u32, u32)>,
types: &mut TypeSection,
next_type_idx: &mut u32,
next_builtin_fn_idx: &mut u32,
) -> Option<TcpCloseIndices> {
let rec_idx = registry.record_type_idx("Tcp.Connection")?;
let slot_idx = registry.tcp_slot_type_idx?;
let pool_idx = registry.tcp_pool_type_idx?;
let result_idx = registry.result_type_idx("Result<Unit,String>")?;
let string_idx = registry.string_array_type_idx?;
let unknown_seg = registry.string_literal_segment(b"tcp: unknown connection")?;
wasip2_imports.lookup_wasm_fn_idx(Wasip2ImportSlot::SocketsTcpShutdown)?;
wasip2_imports.lookup_wasm_fn_idx(Wasip2ImportSlot::IoStreamsResourceDropInputStream)?;
wasip2_imports.lookup_wasm_fn_idx(Wasip2ImportSlot::IoStreamsResourceDropOutputStream)?;
wasip2_imports.lookup_wasm_fn_idx(Wasip2ImportSlot::SocketsTcpResourceDropTcpSocket)?;
parse_id?;
let conn_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(rec_idx),
});
let res_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(result_idx),
});
types.ty().function([conn_ref], [res_ref]);
let ty = *next_type_idx;
*next_type_idx += 1;
let fn_idx = *next_builtin_fn_idx;
*next_builtin_fn_idx += 1;
Some(TcpCloseIndices {
fn_type: ty,
fn_idx,
tcp_connection_type_idx: rec_idx,
tcp_slot_type_idx: slot_idx,
tcp_pool_type_idx: pool_idx,
string_type_idx: string_idx,
unknown_segment_idx: unknown_seg,
unknown_len: b"tcp: unknown connection".len() as u32,
})
}
fn allocate_send(
registry: &TypeRegistry,
wasip2_imports: &Wasip2ImportRegistry,
types: &mut TypeSection,
next_type_idx: &mut u32,
next_builtin_fn_idx: &mut u32,
) -> Option<TcpSendIndices> {
let string_idx = registry.string_array_type_idx?;
let res_string_idx = registry.result_type_idx("Result<String,String>")?;
let dns_err_seg = registry.string_literal_segment(b"tcp: dns resolve failed")?;
let no_addr_seg = registry.string_literal_segment(b"tcp: dns no addresses")?;
let sock_err_seg = registry.string_literal_segment(b"tcp: socket create failed")?;
let conn_err_seg = registry.string_literal_segment(b"tcp: connect failed")?;
let port_err_seg = registry.string_literal_segment(b"tcp: port out of range")?;
let write_err_seg = registry.string_literal_segment(b"tcp: write failed")?;
let stream_err_seg = registry.string_literal_segment(b"tcp: stream error")?;
let size_err_seg = registry.string_literal_segment(b"tcp: response exceeds 10 MiB limit")?;
let gates: &[Wasip2ImportSlot] = &[
Wasip2ImportSlot::SocketsInstanceNetworkInstanceNetwork,
Wasip2ImportSlot::SocketsIpNameLookupResolveAddresses,
Wasip2ImportSlot::SocketsIpNameLookupResourceDropResolveAddressStream,
Wasip2ImportSlot::SocketsIpNameLookupResolveAddressStreamSubscribe,
Wasip2ImportSlot::IoPollPoll,
Wasip2ImportSlot::IoPollResourceDropPollable,
Wasip2ImportSlot::SocketsIpNameLookupResolveNextAddress,
Wasip2ImportSlot::SocketsTcpCreateSocketCreateTcpSocket,
Wasip2ImportSlot::SocketsTcpStartConnect,
Wasip2ImportSlot::SocketsTcpSubscribe,
Wasip2ImportSlot::SocketsTcpFinishConnect,
Wasip2ImportSlot::SocketsTcpResourceDropTcpSocket,
Wasip2ImportSlot::SocketsTcpShutdown,
Wasip2ImportSlot::OutputStreamBlockingWriteAndFlush,
Wasip2ImportSlot::InputStreamBlockingRead,
Wasip2ImportSlot::IoStreamsResourceDropInputStream,
Wasip2ImportSlot::IoStreamsResourceDropOutputStream,
];
for slot in gates {
wasip2_imports.lookup_wasm_fn_idx(*slot)?;
}
let s_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(string_idx),
});
let res_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(res_string_idx),
});
types.ty().function([s_ref, ValType::I64, s_ref], [res_ref]);
let ty = *next_type_idx;
*next_type_idx += 1;
let fn_idx = *next_builtin_fn_idx;
*next_builtin_fn_idx += 1;
Some(TcpSendIndices {
fn_type: ty,
fn_idx,
string_type_idx: string_idx,
result_string_string_type_idx: res_string_idx,
dns_err_segment_idx: dns_err_seg,
dns_err_len: b"tcp: dns resolve failed".len() as u32,
no_addr_segment_idx: no_addr_seg,
no_addr_len: b"tcp: dns no addresses".len() as u32,
sock_err_segment_idx: sock_err_seg,
sock_err_len: b"tcp: socket create failed".len() as u32,
conn_err_segment_idx: conn_err_seg,
conn_err_len: b"tcp: connect failed".len() as u32,
port_err_segment_idx: port_err_seg,
port_err_len: b"tcp: port out of range".len() as u32,
write_err_segment_idx: write_err_seg,
write_err_len: b"tcp: write failed".len() as u32,
stream_err_segment_idx: stream_err_seg,
stream_err_len: b"tcp: stream error".len() as u32,
size_err_segment_idx: size_err_seg,
size_err_len: b"tcp: response exceeds 10 MiB limit".len() as u32,
})
}
fn allocate_ping(
registry: &TypeRegistry,
wasip2_imports: &Wasip2ImportRegistry,
types: &mut TypeSection,
next_type_idx: &mut u32,
next_builtin_fn_idx: &mut u32,
) -> Option<TcpPingIndices> {
let string_idx = registry.string_array_type_idx?;
let res_unit_idx = registry.result_type_idx("Result<Unit,String>")?;
let dns_err_seg = registry.string_literal_segment(b"tcp: dns resolve failed")?;
let no_addr_seg = registry.string_literal_segment(b"tcp: dns no addresses")?;
let sock_err_seg = registry.string_literal_segment(b"tcp: socket create failed")?;
let conn_err_seg = registry.string_literal_segment(b"tcp: connect failed")?;
let port_err_seg = registry.string_literal_segment(b"tcp: port out of range")?;
let gates: &[Wasip2ImportSlot] = &[
Wasip2ImportSlot::SocketsInstanceNetworkInstanceNetwork,
Wasip2ImportSlot::SocketsIpNameLookupResolveAddresses,
Wasip2ImportSlot::SocketsIpNameLookupResourceDropResolveAddressStream,
Wasip2ImportSlot::SocketsIpNameLookupResolveAddressStreamSubscribe,
Wasip2ImportSlot::IoPollPoll,
Wasip2ImportSlot::IoPollResourceDropPollable,
Wasip2ImportSlot::SocketsIpNameLookupResolveNextAddress,
Wasip2ImportSlot::SocketsTcpCreateSocketCreateTcpSocket,
Wasip2ImportSlot::SocketsTcpStartConnect,
Wasip2ImportSlot::SocketsTcpSubscribe,
Wasip2ImportSlot::SocketsTcpFinishConnect,
Wasip2ImportSlot::SocketsTcpResourceDropTcpSocket,
Wasip2ImportSlot::IoStreamsResourceDropInputStream,
Wasip2ImportSlot::IoStreamsResourceDropOutputStream,
];
for slot in gates {
wasip2_imports.lookup_wasm_fn_idx(*slot)?;
}
let s_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(string_idx),
});
let res_ref = ValType::Ref(wasm_encoder::RefType {
nullable: true,
heap_type: wasm_encoder::HeapType::Concrete(res_unit_idx),
});
types.ty().function([s_ref, ValType::I64], [res_ref]);
let ty = *next_type_idx;
*next_type_idx += 1;
let fn_idx = *next_builtin_fn_idx;
*next_builtin_fn_idx += 1;
Some(TcpPingIndices {
fn_type: ty,
fn_idx,
string_type_idx: string_idx,
dns_err_segment_idx: dns_err_seg,
dns_err_len: b"tcp: dns resolve failed".len() as u32,
no_addr_segment_idx: no_addr_seg,
no_addr_len: b"tcp: dns no addresses".len() as u32,
sock_err_segment_idx: sock_err_seg,
sock_err_len: b"tcp: socket create failed".len() as u32,
conn_err_segment_idx: conn_err_seg,
conn_err_len: b"tcp: connect failed".len() as u32,
port_err_segment_idx: port_err_seg,
port_err_len: b"tcp: port out of range".len() as u32,
})
}