Skip to content

Refactor how InitContext works with factors #3134

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

Merged
merged 2 commits into from
May 20, 2025
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
2 changes: 1 addition & 1 deletion crates/factor-key-value/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Factor for KeyValueFactor {
type AppState = AppState;
type InstanceBuilder = InstanceBuilder;

fn init<T: Send + 'static>(&mut self, mut ctx: InitContext<T, Self>) -> anyhow::Result<()> {
fn init(&mut self, ctx: &mut impl InitContext<Self>) -> anyhow::Result<()> {
ctx.link_bindings(spin_world::v1::key_value::add_to_linker)?;
ctx.link_bindings(spin_world::v2::key_value::add_to_linker)?;
ctx.link_bindings(spin_world::wasi::keyvalue::store::add_to_linker)?;
Expand Down
5 changes: 1 addition & 4 deletions crates/factor-llm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ impl Factor for LlmFactor {
type AppState = AppState;
type InstanceBuilder = InstanceState;

fn init<T: Send + 'static>(
&mut self,
mut ctx: spin_factors::InitContext<T, Self>,
) -> anyhow::Result<()> {
fn init(&mut self, ctx: &mut impl spin_factors::InitContext<Self>) -> anyhow::Result<()> {
ctx.link_bindings(spin_world::v1::llm::add_to_linker)?;
ctx.link_bindings(spin_world::v2::llm::add_to_linker)?;
Ok(())
Expand Down
7 changes: 2 additions & 5 deletions crates/factor-outbound-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,9 @@ impl Factor for OutboundHttpFactor {
type AppState = ();
type InstanceBuilder = InstanceState;

fn init<T: Send + 'static>(
&mut self,
mut ctx: spin_factors::InitContext<T, Self>,
) -> anyhow::Result<()> {
fn init(&mut self, ctx: &mut impl spin_factors::InitContext<Self>) -> anyhow::Result<()> {
ctx.link_bindings(spin_world::v1::http::add_to_linker)?;
wasi::add_to_linker::<T>(&mut ctx)?;
wasi::add_to_linker(ctx)?;
Ok(())
}

Expand Down
28 changes: 13 additions & 15 deletions crates/factor-outbound-http/src/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,24 @@ use crate::{
wasi_2023_10_18, wasi_2023_11_10, InstanceState, OutboundHttpFactor, SelfRequestOrigin,
};

pub(crate) fn add_to_linker<T: Send + 'static>(
ctx: &mut spin_factors::InitContext<T, OutboundHttpFactor>,
) -> anyhow::Result<()> {
fn type_annotate<T, F>(f: F) -> F
pub(crate) fn add_to_linker<C>(ctx: &mut C) -> anyhow::Result<()>
where
C: spin_factors::InitContext<OutboundHttpFactor>,
{
fn get_http<C>(store: &mut C::StoreData) -> WasiHttpImpl<WasiHttpImplInner<'_>>
where
F: Fn(&mut T) -> WasiHttpImpl<WasiHttpImplInner>,
C: spin_factors::InitContext<OutboundHttpFactor>,
{
f
}
let get_data_with_table = ctx.get_data_with_table_fn();
let closure = type_annotate(move |data| {
let (state, table) = get_data_with_table(data);
let (state, table) = C::get_data_with_table(store);
WasiHttpImpl(IoImpl(WasiHttpImplInner { state, table }))
});
}
let get_http = get_http::<C> as fn(&mut C::StoreData) -> WasiHttpImpl<WasiHttpImplInner<'_>>;
let linker = ctx.linker();
wasmtime_wasi_http::bindings::http::outgoing_handler::add_to_linker_get_host(linker, closure)?;
wasmtime_wasi_http::bindings::http::types::add_to_linker_get_host(linker, closure)?;
wasmtime_wasi_http::bindings::http::outgoing_handler::add_to_linker_get_host(linker, get_http)?;
wasmtime_wasi_http::bindings::http::types::add_to_linker_get_host(linker, get_http)?;

wasi_2023_10_18::add_to_linker(linker, closure)?;
wasi_2023_11_10::add_to_linker(linker, closure)?;
wasi_2023_10_18::add_to_linker(linker, get_http)?;
wasi_2023_11_10::add_to_linker(linker, get_http)?;

Ok(())
}
Expand Down
8 changes: 5 additions & 3 deletions crates/factor-outbound-http/src/wasi_2023_10_18.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ use wasi::io::streams::{InputStream, OutputStream};

use crate::wasi::WasiHttpImplInner;

pub(crate) fn add_to_linker<T, F>(linker: &mut Linker<T>, closure: F) -> Result<()>
pub(crate) fn add_to_linker<T>(
linker: &mut Linker<T>,
closure: fn(&mut T) -> WasiHttpImpl<WasiHttpImplInner<'_>>,
) -> Result<()>
where
T: Send,
F: Fn(&mut T) -> WasiHttpImpl<WasiHttpImplInner> + Send + Sync + Copy + 'static,
T: Send + 'static,
{
wasi::http::types::add_to_linker_get_host(linker, closure)?;
wasi::http::outgoing_handler::add_to_linker_get_host(linker, closure)?;
Expand Down
8 changes: 5 additions & 3 deletions crates/factor-outbound-http/src/wasi_2023_11_10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,12 @@ use wasi::io::streams::{Error as IoError, InputStream, OutputStream};

use crate::wasi::WasiHttpImplInner;

pub(crate) fn add_to_linker<T, F>(linker: &mut Linker<T>, closure: F) -> Result<()>
pub(crate) fn add_to_linker<T>(
linker: &mut Linker<T>,
closure: fn(&mut T) -> WasiHttpImpl<WasiHttpImplInner<'_>>,
) -> Result<()>
where
T: Send,
F: Fn(&mut T) -> WasiHttpImpl<WasiHttpImplInner> + Send + Sync + Copy + 'static,
T: Send + 'static,
{
wasi::http::types::add_to_linker_get_host(linker, closure)?;
wasi::http::outgoing_handler::add_to_linker_get_host(linker, closure)?;
Expand Down
5 changes: 1 addition & 4 deletions crates/factor-outbound-mqtt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ impl Factor for OutboundMqttFactor {
type AppState = ();
type InstanceBuilder = InstanceState;

fn init<T: Send + 'static>(
&mut self,
mut ctx: spin_factors::InitContext<T, Self>,
) -> anyhow::Result<()> {
fn init(&mut self, ctx: &mut impl spin_factors::InitContext<Self>) -> anyhow::Result<()> {
ctx.link_bindings(spin_world::v2::mqtt::add_to_linker)?;
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion crates/factor-outbound-mysql/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl<C: Send + Sync + Client + 'static> Factor for OutboundMysqlFactor<C> {
type AppState = ();
type InstanceBuilder = InstanceState<C>;

fn init<T: Send + 'static>(&mut self, mut ctx: InitContext<T, Self>) -> anyhow::Result<()> {
fn init(&mut self, ctx: &mut impl InitContext<Self>) -> anyhow::Result<()> {
ctx.link_bindings(v1::add_to_linker)?;
ctx.link_bindings(v2::add_to_linker)?;
Ok(())
Expand Down
5 changes: 1 addition & 4 deletions crates/factor-outbound-pg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ impl<C: Send + Sync + Client + 'static> Factor for OutboundPgFactor<C> {
type AppState = ();
type InstanceBuilder = InstanceState<C>;

fn init<T: Send + 'static>(
&mut self,
mut ctx: spin_factors::InitContext<T, Self>,
) -> anyhow::Result<()> {
fn init(&mut self, ctx: &mut impl spin_factors::InitContext<Self>) -> anyhow::Result<()> {
ctx.link_bindings(spin_world::v1::postgres::add_to_linker)?;
ctx.link_bindings(spin_world::v2::postgres::add_to_linker)?;
ctx.link_bindings(spin_world::spin::postgres::postgres::add_to_linker)?;
Expand Down
5 changes: 1 addition & 4 deletions crates/factor-outbound-redis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ impl Factor for OutboundRedisFactor {
type AppState = ();
type InstanceBuilder = InstanceState;

fn init<T: Send + 'static>(
&mut self,
mut ctx: spin_factors::InitContext<T, Self>,
) -> anyhow::Result<()> {
fn init(&mut self, ctx: &mut impl spin_factors::InitContext<Self>) -> anyhow::Result<()> {
ctx.link_bindings(spin_world::v1::redis::add_to_linker)?;
ctx.link_bindings(spin_world::v2::redis::add_to_linker)?;
Ok(())
Expand Down
5 changes: 1 addition & 4 deletions crates/factor-sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,7 @@ impl Factor for SqliteFactor {
type AppState = AppState;
type InstanceBuilder = InstanceState;

fn init<T: Send + 'static>(
&mut self,
mut ctx: spin_factors::InitContext<T, Self>,
) -> anyhow::Result<()> {
fn init(&mut self, ctx: &mut impl spin_factors::InitContext<Self>) -> anyhow::Result<()> {
ctx.link_bindings(v1::add_to_linker)?;
ctx.link_bindings(v2::add_to_linker)?;
ctx.link_bindings(v3::add_to_linker)?;
Expand Down
2 changes: 1 addition & 1 deletion crates/factor-variables/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl Factor for VariablesFactor {
type AppState = AppState;
type InstanceBuilder = InstanceState;

fn init<T: Send + 'static>(&mut self, mut ctx: InitContext<T, Self>) -> anyhow::Result<()> {
fn init(&mut self, ctx: &mut impl InitContext<Self>) -> anyhow::Result<()> {
ctx.link_bindings(spin_world::v1::config::add_to_linker)?;
ctx.link_bindings(spin_world::v2::variables::add_to_linker)?;
ctx.link_bindings(spin_world::wasi::config::store::add_to_linker)?;
Expand Down
142 changes: 85 additions & 57 deletions crates/factor-wasi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,70 +44,98 @@ impl WasiFactor {
}
}

/// Helper trait to extend `InitContext` with some more `link_*_bindings`
/// methods related to `wasmtime-wasi` and `wasmtime-wasi-io`-specific
/// signatures.
#[allow(clippy::type_complexity, reason = "sorry, blame alex")]
trait InitContextExt: InitContext<WasiFactor> {
fn get_io(data: &mut Self::StoreData) -> IoImpl<WasiImplInner<'_>> {
let (state, table) = Self::get_data_with_table(data);
IoImpl(WasiImplInner {
ctx: &mut state.ctx,
table,
})
}

fn link_io_bindings(
&mut self,
add_to_linker: fn(
&mut wasmtime::component::Linker<Self::StoreData>,
fn(&mut Self::StoreData) -> IoImpl<WasiImplInner<'_>>,
) -> anyhow::Result<()>,
) -> anyhow::Result<()> {
add_to_linker(self.linker(), Self::get_io)
}

fn get_wasi(data: &mut Self::StoreData) -> WasiImpl<WasiImplInner<'_>> {
WasiImpl(Self::get_io(data))
}

fn link_wasi_bindings(
&mut self,
add_to_linker: fn(
&mut wasmtime::component::Linker<Self::StoreData>,
fn(&mut Self::StoreData) -> WasiImpl<WasiImplInner<'_>>,
) -> anyhow::Result<()>,
) -> anyhow::Result<()> {
add_to_linker(self.linker(), Self::get_wasi)
}

fn link_wasi_default_bindings<O>(
&mut self,
add_to_linker: fn(
&mut wasmtime::component::Linker<Self::StoreData>,
&O,
fn(&mut Self::StoreData) -> WasiImpl<WasiImplInner<'_>>,
) -> anyhow::Result<()>,
) -> anyhow::Result<()>
where
O: Default,
{
add_to_linker(self.linker(), &O::default(), Self::get_wasi)
}
}

impl<T> InitContextExt for T where T: InitContext<WasiFactor> {}

impl Factor for WasiFactor {
type RuntimeConfig = ();
type AppState = ();
type InstanceBuilder = InstanceBuilder;

fn init<T: Send + 'static>(&mut self, mut ctx: InitContext<T, Self>) -> anyhow::Result<()> {
fn type_annotate_wasi<T, F>(f: F) -> F
where
F: Fn(&mut T) -> WasiImpl<WasiImplInner>,
{
f
}
fn type_annotate_io<T, F>(f: F) -> F
where
F: Fn(&mut T) -> IoImpl<WasiImplInner>,
{
f
}
let get_data_with_table = ctx.get_data_with_table_fn();
let io_closure = type_annotate_io(move |data| {
let (state, table) = get_data_with_table(data);
IoImpl(WasiImplInner {
ctx: &mut state.ctx,
table,
})
});
let wasi_closure = type_annotate_wasi(move |data| WasiImpl(io_closure(data)));
let linker = ctx.linker();
fn init(&mut self, ctx: &mut impl InitContext<Self>) -> anyhow::Result<()> {
use wasmtime_wasi::bindings;
bindings::clocks::wall_clock::add_to_linker_get_host(linker, wasi_closure)?;
bindings::clocks::monotonic_clock::add_to_linker_get_host(linker, wasi_closure)?;
bindings::filesystem::types::add_to_linker_get_host(linker, wasi_closure)?;
bindings::filesystem::preopens::add_to_linker_get_host(linker, wasi_closure)?;
bindings::io::error::add_to_linker_get_host(linker, io_closure)?;
bindings::io::poll::add_to_linker_get_host(linker, io_closure)?;
bindings::io::streams::add_to_linker_get_host(linker, io_closure)?;
bindings::random::random::add_to_linker_get_host(linker, wasi_closure)?;
bindings::random::insecure::add_to_linker_get_host(linker, wasi_closure)?;
bindings::random::insecure_seed::add_to_linker_get_host(linker, wasi_closure)?;
bindings::cli::exit::add_to_linker_get_host(linker, &Default::default(), wasi_closure)?;
bindings::cli::environment::add_to_linker_get_host(linker, wasi_closure)?;
bindings::cli::stdin::add_to_linker_get_host(linker, wasi_closure)?;
bindings::cli::stdout::add_to_linker_get_host(linker, wasi_closure)?;
bindings::cli::stderr::add_to_linker_get_host(linker, wasi_closure)?;
bindings::cli::terminal_input::add_to_linker_get_host(linker, wasi_closure)?;
bindings::cli::terminal_output::add_to_linker_get_host(linker, wasi_closure)?;
bindings::cli::terminal_stdin::add_to_linker_get_host(linker, wasi_closure)?;
bindings::cli::terminal_stdout::add_to_linker_get_host(linker, wasi_closure)?;
bindings::cli::terminal_stderr::add_to_linker_get_host(linker, wasi_closure)?;
bindings::sockets::tcp::add_to_linker_get_host(linker, wasi_closure)?;
bindings::sockets::tcp_create_socket::add_to_linker_get_host(linker, wasi_closure)?;
bindings::sockets::udp::add_to_linker_get_host(linker, wasi_closure)?;
bindings::sockets::udp_create_socket::add_to_linker_get_host(linker, wasi_closure)?;
bindings::sockets::instance_network::add_to_linker_get_host(linker, wasi_closure)?;
bindings::sockets::network::add_to_linker_get_host(
linker,
&Default::default(),
wasi_closure,
)?;
bindings::sockets::ip_name_lookup::add_to_linker_get_host(linker, wasi_closure)?;

wasi_2023_10_18::add_to_linker(linker, wasi_closure)?;
wasi_2023_11_10::add_to_linker(linker, wasi_closure)?;

ctx.link_wasi_bindings(bindings::clocks::wall_clock::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::clocks::monotonic_clock::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::filesystem::types::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::filesystem::preopens::add_to_linker_get_host)?;
ctx.link_io_bindings(bindings::io::error::add_to_linker_get_host)?;
ctx.link_io_bindings(bindings::io::poll::add_to_linker_get_host)?;
ctx.link_io_bindings(bindings::io::streams::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::random::random::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::random::insecure::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::random::insecure_seed::add_to_linker_get_host)?;
ctx.link_wasi_default_bindings(bindings::cli::exit::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::cli::environment::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::cli::stdin::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::cli::stdout::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::cli::stderr::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::cli::terminal_input::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::cli::terminal_output::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::cli::terminal_stdin::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::cli::terminal_stdout::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::cli::terminal_stderr::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::sockets::tcp::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::sockets::tcp_create_socket::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::sockets::udp::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::sockets::udp_create_socket::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::sockets::instance_network::add_to_linker_get_host)?;
ctx.link_wasi_default_bindings(bindings::sockets::network::add_to_linker_get_host)?;
ctx.link_wasi_bindings(bindings::sockets::ip_name_lookup::add_to_linker_get_host)?;

ctx.link_wasi_bindings(wasi_2023_10_18::add_to_linker)?;
ctx.link_wasi_bindings(wasi_2023_11_10::add_to_linker)?;
Ok(())
}

Expand Down
8 changes: 5 additions & 3 deletions crates/factor-wasi/src/wasi_2023_10_18.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,12 @@ use wasi::sockets::udp::Datagram;

use crate::WasiImplInner;

pub fn add_to_linker<T, F>(linker: &mut Linker<T>, closure: F) -> Result<()>
pub fn add_to_linker<T>(
linker: &mut Linker<T>,
closure: fn(&mut T) -> WasiImpl<WasiImplInner<'_>>,
) -> Result<()>
where
T: Send,
F: Fn(&mut T) -> WasiImpl<WasiImplInner> + Send + Sync + Copy + 'static,
T: Send + 'static,
{
wasi::clocks::monotonic_clock::add_to_linker_get_host(linker, closure)?;
wasi::clocks::wall_clock::add_to_linker_get_host(linker, closure)?;
Expand Down
8 changes: 5 additions & 3 deletions crates/factor-wasi/src/wasi_2023_11_10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,12 @@ use wasi::sockets::udp::{

use crate::WasiImplInner;

pub fn add_to_linker<T, F>(linker: &mut Linker<T>, closure: F) -> Result<()>
pub fn add_to_linker<T>(
linker: &mut Linker<T>,
closure: fn(&mut T) -> WasiImpl<WasiImplInner<'_>>,
) -> Result<()>
where
T: Send,
F: Fn(&mut T) -> WasiImpl<WasiImplInner> + Send + Sync + Copy + 'static,
T: Send + 'static,
{
wasi::clocks::monotonic_clock::add_to_linker_get_host(linker, closure)?;
wasi::clocks::wall_clock::add_to_linker_get_host(linker, closure)?;
Expand Down
27 changes: 19 additions & 8 deletions crates/factors-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,27 @@ fn expand_factors(input: &DeriveInput) -> syn::Result<TokenStream> {
}

#(
#Factor::init::<T>(
#[allow(non_camel_case_types)]
struct #factor_names;

impl #factors_path::FactorField for #factor_names {
type State = #state_name;
type Factor = #factor_types;

fn get(state: &mut #state_name) -> (
&mut #factors_path::FactorInstanceState<#factor_types>,
&mut #wasmtime::component::ResourceTable,
) {
(&mut state.#factor_names, &mut state.__table)
}
}

#Factor::init(
&mut self.#factor_names,
#factors_path::InitContext::<T, #factor_types>::new(
&mut #factors_path::FactorInitContext::<'_, T, #factor_names> {
linker,
|data| &mut data.as_instance_state().#factor_names,
|data| {
let state = data.as_instance_state();
(&mut state.#factor_names, &mut state.__table)
},
)
_marker: std::marker::PhantomData,
},
).map_err(#Error::factor_init_error::<#factor_types>)?;
)*
Ok(())
Expand Down
Loading
Loading