Skip to content
Open
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
385 changes: 184 additions & 201 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.141"
thiserror = "2.0.12"
tokio = { version = "1.46.1", features = ["full"] }
wasmtime = "34.0.2"
wasmtime-wasi = "34.0.2"
wasmtime = "35.0.0"
wasmtime-wasi = "35.0.0"
8 changes: 2 additions & 6 deletions src/core/app.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::string::String;

use crux_core::{Command, macros::effect};

use crate::core::capabilities::{
Expand Down Expand Up @@ -57,10 +55,8 @@ impl crux_core::App for App {
Event::Update(request) => call_update(request.data).then_send(Event::GotUpdate),
Event::Resolve(request) => call_resolve(request).then_send(Event::GotResolve),
Event::View(_) => call_view().then_send(Event::GotView),
Event::GotSchema(SchemaResponse(result)) => {
render::render(result.map(String::into_bytes))
}
Event::GotUpdate(UpdateResponse(result))
Event::GotSchema(SchemaResponse(result))
| Event::GotUpdate(UpdateResponse(result))
| Event::GotResolve(ResolveResponse(result))
| Event::GotView(ViewResponse(result)) => render::render(result),
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/capabilities/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::Result;

pub struct SchemaRequest;

pub struct SchemaResponse(pub Result<String>);
pub struct SchemaResponse(pub Result<Vec<u8>>);

impl Operation for SchemaRequest {
type Output = SchemaResponse;
Expand Down
12 changes: 9 additions & 3 deletions src/event_loop.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::string::String;

use tokio::sync::mpsc::Sender;

use crate::{
Expand Down Expand Up @@ -35,14 +37,18 @@ impl Core {
fn process_effect(&self, effect: Effect, tx: &Sender<Result<Vec<u8>>>) {
let effects = match effect {
Effect::Schema(mut request) => {
let result = self.host.schema().map_err(Error::Other);
let result = self
.host
.schema()
.map(String::into_bytes)
.map_err(Error::Other);
self.core
.resolve(&mut request, SchemaResponse(result))
.expect("should resolve")
}
Effect::Update(request) => {
let (request, mut handler) = request.split();
let result = self.host.update(request.data).map_err(Error::Other);
let result = self.host.update(&request.data).map_err(Error::Other);
self.core
.resolve(&mut handler, UpdateResponse(result))
.expect("should resolve")
Expand All @@ -51,7 +57,7 @@ impl Core {
let (request, mut handler) = request.split();
let result = self
.host
.resolve(request.effect_id, request.data)
.resolve(request.effect_id, &request.data)
.map_err(Error::Other);
self.core
.resolve(&mut handler, ResolveResponse(result))
Expand Down
133 changes: 52 additions & 81 deletions src/shell/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ use std::{
use anyhow::{Result, anyhow, bail};
use wasmtime::{
Engine, Store,
component::{Component, Linker, ResourceTable, TypedFunc},
component::{Component, Linker, ResourceAny, ResourceTable, bindgen},
};

use self::exports::crux::shared_lib::core::Guest;
use wasmtime_wasi::p2::{IoView, WasiCtx, WasiCtxBuilder, WasiView, add_to_linker_sync};

bindgen!();

pub struct ComponentRunStates {
pub wasi_ctx: WasiCtx,
pub resource_table: ResourceTable,
Expand All @@ -28,16 +32,11 @@ impl WasiView for ComponentRunStates {
}
}

type Bytes = Vec<u8>;

#[derive(Default)]
#[allow(clippy::type_complexity)]
pub struct Host {
store: Arc<Mutex<Option<Store<ComponentRunStates>>>>,
schema: Option<TypedFunc<(), (String,)>>,
update: Option<TypedFunc<(Bytes,), (Result<Bytes, String>,)>>,
resolve: Option<TypedFunc<(u32, Bytes), (Result<Bytes, String>,)>>,
view: Option<TypedFunc<(), (Result<Bytes, String>,)>>,
shared: Option<Shared>,
resource: Option<ResourceAny>,
}

impl Host {
Expand All @@ -55,98 +54,70 @@ impl Host {

let file = PathBuf::from(env::var("CRUX_COMPONENT")?);
let component = Component::from_file(&engine, file)?;
let instance = linker.instantiate(&mut store, &component)?;

if let Some(func) = instance.get_func(&mut store, "schema") {
self.schema = Some(func.typed::<(), (String,)>(&store)?);
} else {
bail!("schema function not found");
}

if let Some(func) = instance.get_func(&mut store, "update") {
self.update = Some(func.typed::<(Bytes,), (Result<Bytes, String>,)>(&store)?);
} else {
bail!("update function not found");
}

if let Some(func) = instance.get_func(&mut store, "resolve") {
self.resolve = Some(func.typed::<(u32, Bytes), (Result<Bytes, String>,)>(&store)?);
} else {
bail!("resolve function not found");
}

if let Some(func) = instance.get_func(&mut store, "view") {
self.view = Some(func.typed::<(), (Result<Bytes, String>,)>(&store)?);
} else {
bail!("view function not found");
}

// Use the generated bindings to instantiate the component
let shared = Shared::instantiate(&mut store, &component, &linker)?;

// Create a new instance of the exported resource
let resource = shared
.crux_shared_lib_core()
.instance()
.call_constructor(&mut store)?;

self.shared = Some(shared);
self.resource = Some(resource);
self.store = Arc::new(Mutex::new(Some(store)));

Ok(())
}

pub fn schema(&self) -> Result<String> {
let Some(schema) = self.schema else {
bail!("no schema function");
fn with_guest<T, F>(&self, f: F) -> Result<T>
where
F: FnOnce(&Guest, &mut Store<ComponentRunStates>, ResourceAny) -> Result<T>,
{
let Some(shared) = &self.shared else {
bail!("component not loaded");
};

let mut store = self.store.lock().expect("failed to lock store");
let Some(mut store) = store.as_mut() else {
bail!("no store");
};

let (data,) = schema.call(&mut store, ())?;
schema.post_return(&mut store)?;

Ok(data)
}

pub fn update(&self, data: Vec<u8>) -> Result<Vec<u8>> {
let Some(update) = self.update else {
bail!("no update function");
let Some(resource) = &self.resource else {
bail!("no instance created");
};

let mut store = self.store.lock().expect("failed to lock store");
let Some(mut store) = store.as_mut() else {
let Some(store) = store.as_mut() else {
bail!("no store");
};

let (data,) = update.call(&mut store, (data,))?;
update.post_return(&mut store)?;

data.map_err(|e| anyhow!("bridge error: {e}"))
f(shared.crux_shared_lib_core(), store, *resource)
}

pub fn resolve(&self, effect_id: u32, data: Vec<u8>) -> Result<Vec<u8>> {
let Some(resolve) = self.resolve else {
bail!("no update function");
};

let mut store = self.store.lock().expect("failed to lock store");
let Some(mut store) = store.as_mut() else {
bail!("no store");
};
pub fn schema(&self) -> Result<String> {
self.with_guest(|guest, store, resource| guest.instance().call_schema(store, resource))
}

let (data,) = resolve.call(&mut store, (effect_id, data))?;
resolve.post_return(&mut store)?;
pub fn update(&self, data: &[u8]) -> Result<Vec<u8>> {
self.with_guest(|guest, store, resource| {
guest
.instance()
.call_update(store, resource, data)?
.map_err(|e| anyhow!("bridge error: {e}"))
})
}

data.map_err(|e| anyhow!("bridge error: {e}"))
pub fn resolve(&self, effect_id: u32, data: &[u8]) -> Result<Vec<u8>> {
self.with_guest(|guest, store, resource| {
guest
.instance()
.call_resolve(store, resource, effect_id, data)?
.map_err(|e| anyhow!("bridge error: {e}"))
})
}

pub fn view(&self) -> Result<Vec<u8>> {
let Some(view) = &self.view else {
bail!("no view function");
};

let mut store = self.store.lock().expect("failed to lock store");
let Some(mut store) = store.as_mut() else {
bail!("no store");
};

let (data,) = view.call(&mut store, ())?;
view.post_return(&mut store)?;

data.map_err(|e| anyhow!("bridge error: {e}"))
self.with_guest(|guest, store, resource| {
guest
.instance()
.call_view(store, resource)?
.map_err(|e| anyhow!("bridge error: {e}"))
})
}
}
11 changes: 11 additions & 0 deletions wit/core.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package crux:shared-lib;

interface core {
resource instance {
constructor();
update: func(data: list<u8>) -> result<list<u8>, string>;
resolve: func(effect-id: u32, data: list<u8>) -> result<list<u8>, string>;
view: func() -> result<list<u8>, string>;
schema: func() -> string;
}
}
5 changes: 5 additions & 0 deletions wit/world.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package crux:shared-lib;

world shared {
export core;
}
Loading