-
Notifications
You must be signed in to change notification settings - Fork 197
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
rust (question): create resource in host component and share to a guest component #1103
Comments
Would it work to add a resource topographical-map {
/// Construct a new empty map.
constructor();
/// Change this to whatever you need to populate the map.
populate-map: func(with: stuff);
// existing API...
map-width: func() -> u32;
map-height: func() -> u32;
height-at-location: func(x: u32, y: u32) -> u8;
} |
OK, thanks, so I tried that suggestion. Two things I notice:
I made the following changes (bryanburgers/advent-of-code-2024@main...day-10-wit-resource) Shared wit becomes: shared witpackage aoc2024:day10;
interface types {
resource topographical-map {
constructor(map: list<list<u8>>);
map-width: func() -> u32;
map-height: func() -> u32;
height-at-location: func(x: u32, y: u32) -> u8;
}
}
interface solver {
use types.{topographical-map};
solve-a: func(input: borrow<topographical-map>) -> u64;
solve-b: func(input: borrow<topographical-map>) -> u64;
} Solver (guest)'s wit becomes Solver (guest)'s witpackage aoc2024:day10-solver;
world solver {
export aoc2024:day10/solver;
// Newly added here?
import aoc2024:day10/types;
import aoc:base/debug;
} Parser (host)'s wit becomes Parser (host)'s witworld parser {
export aoc:base/day;
import aoc2024:day10/solver;
// Newly added here?
export aoc2024:day10/types;
} solver's lib.rs becomes: (And to me it's weird that I'm doing solver's lib.rs#[allow(warnings)]
mod bindings;
struct Component;
impl bindings::exports::aoc::base::day::Guest for Component {
fn run(input: String) -> (String, String) {
let mut map = Vec::new();
for line in input.lines() {
let row = line.bytes().map(|byte| byte - b'0').collect();
map.push(row);
}
// This is weird to me. Feels like it should be MyTopographicalMap::new(&map);
let input = bindings::aoc2024::day10::types::TopographicalMap::new(&map);
let result_a = bindings::aoc2024::day10::solver::solve_a(&input);
let result_b = bindings::aoc2024::day10::solver::solve_b(&input);
(result_a.to_string(), result_b.to_string())
}
}
struct MyTopographicalMap(Vec<Vec<u8>>);
impl bindings::exports::aoc2024::day10::types::Guest for Component {
type TopographicalMap = MyTopographicalMap;
}
impl bindings::exports::aoc2024::day10::types::GuestTopographicalMap for MyTopographicalMap {
fn new(map: Vec<Vec<u8>>) -> Self {
MyTopographicalMap(map)
}
fn map_width(&self) -> u32 {
self.0[0].len() as u32
}
fn map_height(&self) -> u32 {
self.0.len() as u32
}
fn height_at_location(&self, x: u32, y: u32) -> u8 {
self.0[y as usize][x as usize]
}
}
bindings::export!(Component with_types_in bindings); Now, all of those build fine. But the wits are interesting. wasm-tools component wit build/day10_parser.wasmpackage root:component;
world root {
import aoc2024:day10/types;
import aoc2024:day10/solver;
export aoc:base/day;
export aoc2024:day10/types;
}
package aoc2024:day10 {
interface types {
resource topographical-map {
constructor(map: list<list<u8>>);
map-width: func() -> u32;
map-height: func() -> u32;
height-at-location: func(x: u32, y: u32) -> u8;
}
}
interface solver {
use types.{topographical-map};
solve-a: func(input: borrow<topographical-map>) -> u64;
solve-b: func(input: borrow<topographical-map>) -> u64;
}
}
package aoc:base {
interface day {
run: func(input: string) -> tuple<string, string>;
}
} wasm-tools component wit build/day10_solver.wasmpackage root:component;
world root {
import aoc2024:day10/types;
export aoc2024:day10/solver;
}
package aoc2024:day10 {
interface types {
resource topographical-map {
map-width: func() -> u32;
map-height: func() -> u32;
height-at-location: func(x: u32, y: u32) -> u8;
}
}
interface solver {
use types.{topographical-map};
solve-a: func(input: borrow<topographical-map>) -> u64;
solve-b: func(input: borrow<topographical-map>) -> u64;
}
}
wasm-tools component wit build/day10.wasmpackage root:component;
world root {
import aoc2024:day10/types;
export aoc:base/day;
export aoc2024:day10/types;
}
package aoc2024:day10 {
interface types {
resource topographical-map {
constructor(map: list<list<u8>>);
map-width: func() -> u32;
map-height: func() -> u32;
height-at-location: func(x: u32, y: u32) -> u8;
}
}
}
package aoc:base {
interface day {
run: func(input: string) -> tuple<string, string>;
}
} In this last one, the composed component, it's still expecting Comparison to what my composed wits look like for previous days: wasm-tools component wit build/day09.wasmpackage root:component;
world root {
export aoc:base/day;
}
package aoc:base {
interface day {
run: func(input: string) -> tuple<string, string>;
}
} |
If I don't include
|
Oh interesting, if I have the guest implement and export the bryanburgers/advent-of-code-2024@main...day-10-wit-resource-defined-in-guest THIS WORKS! But in the larger picture, it's not exactly what I'd want: I'd still want the host to be able to define its own implementation and "information hide" everything but the interface, and the guest to just use the interface of the resource to do its work. |
OK, continuing to try things. If I make If I made a third component that just handles the map, then it works. bryanburgers/advent-of-code-2024@main...day-10-wit-resource-third-component The caveat is that the components need to be plugged in a very specific order: First
|
Short: I'm trying to take two components and compose them together. In the first component, I want to create a resource, and in the second component I want to use that resource. I can't quite figure out how to get wasm-bindgen to do what I want.
I'm using
cargo component
.Long: I'm trying to use Advent of Code to learn about components. Overall, I have a very basic world/interface that looks like this, and a runner (written in wasmtime) that takes a component and an input and outputs the two answers.
Then for every day, I create two components called "parser" and "solver", and each one has a custom wit for that particular problem. The wits I currently have for day 10 are the following, which represent parsing the input as a two-dimensional grid of values (a topological map according to the AOC story), and solving the problem with that map.
Conceptually, the parser parses the challenge input (
string
) into something close to the problem definition (list<list<u8>>
), and the solver takes the parsed input and solves it for both parts.I have been combining these with
wac plug day10_parser.wasm --plug day10_solver.wasm --out day10.wasm
. I would be willing to write a wac script if necessary.(The only reason these components are separate is because I wanted to learn more about components. It's working so far.)
What I tried to do with Day 10 and couldn't, was to use a resource.
I'm not sure exactly whether the topographical-map should be imported or exported.
This seems reasonable to me:
But when I went down this route, I couldn't find any way for the "parser" component to create a
topographical-map
from the input and then send a reference to it to the "solver" component.I know this is a very open-ended question, but I tried various things for an hour or two and didn't end up any closer to figuring out how one component could play host of a resource to another component. Is this possible?
https://github.com/bryanburgers/advent-of-code-2024
The text was updated successfully, but these errors were encountered: