Skip to content

Commit

Permalink
Support extract definitions from wasm
Browse files Browse the repository at this point in the history
  • Loading branch information
oovm committed May 16, 2024
1 parent c44a336 commit 3c7a69d
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 56 deletions.
2 changes: 2 additions & 0 deletions projects/valkyrie-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ license = "MPL-2.0"
[dependencies]
nyar-wasm = "0.0.6"
anyhow = "1.0.83"
wit-component = "0.207.0"
wit-parser = "0.207.0"
tracing = "0.1.40"
convert_case = "0.6.0"


[dev-dependencies]

[build-dependencies]
1 change: 1 addition & 0 deletions projects/valkyrie-ffi/src/extractor/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

31 changes: 24 additions & 7 deletions projects/valkyrie-ffi/src/imports/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::helpers::{FunctionContext, TypeContext, WriteDefine, WriteReference};
use convert_case::{Case, Casing};
use std::{fmt::Write, io::Write as _, path::Path};
use wit_parser::{Function, FunctionKind, Handle, Interface, Package, Resolve, Results, Type, TypeDef, TypeDefKind, TypeId};
use wit_parser::{
decoding::DecodedWasm, Function, FunctionKind, Handle, Interface, Package, Resolve, Results, Type, TypeDef, TypeDefKind,
TypeId,
};

mod visit_types;

Expand All @@ -10,11 +13,26 @@ pub struct ValkyrieFFI {
}

impl ValkyrieFFI {
pub fn new<P: AsRef<Path>>(directory: P) -> anyhow::Result<Self> {
pub fn new_deps<P: AsRef<Path>>(directory: P) -> anyhow::Result<Self> {
let mut resolved = Resolve::new();
resolved.push_dir(directory.as_ref())?;
Ok(Self { cache: resolved })
}
pub fn new_wasm(binary: &[u8]) -> anyhow::Result<Self> {
let wasm = wit_component::decode(binary)?;
println!("decoding");
match wasm {
DecodedWasm::WitPackage(resolved, id) => {
println!("package: {:?}", id);
Ok(Self { cache: resolved })
}
DecodedWasm::Component(resolved, id) => {
println!("world: {:?}", id);
Ok(Self { cache: resolved })
}
}
}

pub fn generate<P: AsRef<Path>>(&self, output: P) -> std::io::Result<()> {
let output = output.as_ref();
if !output.is_dir() {
Expand Down Expand Up @@ -58,11 +76,10 @@ impl ValkyrieFFI {
for (name, item) in interface.types.iter() {
match self.cache.types.get(*item) {
Some(s) => {
if let Err(e) = s.kind.write_define(
file,
TypeContext { ffi: &self, interface, namespace: &namespace, wasi_name: "", def: &s },
) {
tracing::error!("error exporting type: {:?}", e)
let ctx = TypeContext { ffi: &self, interface, namespace: &namespace, wasi_name: "", def: &s };
match s.kind.write_define(file, ctx) {
Ok(..) => {}
Err(e) => tracing::error!("error exporting type: {:?}", e),
}
}
None => tracing::error!("type not found: {:?}", name),
Expand Down
1 change: 1 addition & 0 deletions projects/valkyrie-ffi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod exports;
mod extractor;
mod helpers;
mod imports;

Expand Down
16 changes: 16 additions & 0 deletions projects/valkyrie-ffi/tests/homestar/host.vk
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace homestar.host;

class Time {
seconds: u64,
milliseconds: u32,
nanoseconds: u32,
}

⍝? Get current time in sub-seconds.
#import("homestar:host/helpers", "get-current-time")
micro get_current_time() -> Time {}

⍝? Basic `print` helper.
#import("homestar:host/helpers", "print")
micro print(msg: Utf8Text) -> () {}

10 changes: 9 additions & 1 deletion projects/valkyrie-ffi/tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ fn ready() {
#[test]
fn load_all() {
let here = Path::new(env!("CARGO_MANIFEST_DIR"));
let resolved = ValkyrieFFI::new(here.join("tests/wasi-cloud-core/wit")).unwrap();
let resolved = ValkyrieFFI::new_deps(here.join("tests/wasi-cloud-core/wit")).unwrap();
let here = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests");
resolved.generate(here).unwrap();
}

#[test]
fn load_wasm() {
let here = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests");
let file = std::fs::read(here.join("host.wasm")).unwrap();
let resolved = ValkyrieFFI::new_wasm(&file).unwrap();
resolved.generate(here).unwrap();
}
48 changes: 25 additions & 23 deletions projects/valkyrie-ffi/tests/wasi/blobstore.vk
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ class ObjectMetadata {
⍝? identifier for an object that includes its container name
class ObjectId {
container: utf8,
`object`: utf8,
object: utf8,
}

⍝? A data is the data stored in a data blob. The value can be of any type
⍝? that can be represented in a byte array. It provides a way to write the value
⍝? to the output-stream defined in the `wasi-io` interface.
Expand All @@ -48,7 +49,8 @@ resource class OutgoingValue {
new_outgoing_value() -> OutgoingValue { }

#import("wasi:blobstore/types", "[method]outgoing-value.outgoing-value-write-body")
outgoing_value_write_body(self) -> Result< OutputStream, () > { }
outgoing_value_write_body(self) -> Result<OutputStream, ()> { }

}
⍝? A incoming-value is a wrapper around a value. It provides a way to read the value
⍝? from the input-stream defined in the `wasi-io` interface.
Expand All @@ -62,17 +64,17 @@ resource class OutgoingValue {
#import("wasi:blobstore/types", "incoming-value")
resource class IncomingValue {
#import("wasi:blobstore/types", "[method]incoming-value.incoming-value-consume-sync")
incoming_value_consume_sync(self) -> Result< Array< u8 >, utf8 > { }
incoming_value_consume_sync(self) -> Result<Array<u8>, utf8> { }

#import("wasi:blobstore/types", "[method]incoming-value.incoming-value-consume-async")
incoming_value_consume_async(self) -> Result< InputStream, utf8 > { }
incoming_value_consume_async(self) -> Result<InputStream, utf8> { }

#import("wasi:blobstore/types", "[method]incoming-value.size")
size(self) -> u64 { }

}
alias typus IncomingValueAsyncBody = InputStream;
alias typus IncomingValueSyncBody = Array< u8 >;
alias typus IncomingValueSyncBody = Array<u8>;
alias typus InputStream = InputStream;
alias typus OutputStream = OutputStream;
alias typus ContainerMetadata = ContainerMetadata;
Expand All @@ -86,47 +88,47 @@ alias typus OutgoingValue = OutgoingValue;
resource class Container {
⍝? returns container name
#import("wasi:blobstore/container", "[method]container.name")
name(self) -> Result< utf8, utf8 > { }
name(self) -> Result<utf8, utf8> { }

⍝? returns container metadata
#import("wasi:blobstore/container", "[method]container.info")
info(self) -> Result< ContainerMetadata, utf8 > { }
info(self) -> Result<ContainerMetadata, utf8> { }

⍝? retrieves an object or portion of an object, as a resource.
⍝? Start and end offsets are inclusive.
⍝? Once a data-blob resource has been created, the underlying bytes are held by the blobstore service for the lifetime
⍝? of the data-blob resource, even if the object they came from is later deleted.
#import("wasi:blobstore/container", "[method]container.get-data")
get_data(self, name: utf8, start: u64, end: u64) -> Result< IncomingValue, utf8 > { }
get_data(self, name: utf8, start: u64, end: u64) -> Result<IncomingValue, utf8> { }

⍝? creates or replaces an object with the data blob.
#import("wasi:blobstore/container", "[method]container.write-data")
write_data(self, name: utf8, data: &OutgoingValue) -> Result< (), utf8 > { }
write_data(self, name: utf8, data: &OutgoingValue) -> Result<(), utf8> { }

⍝? returns list of objects in the container. Order is undefined.
#import("wasi:blobstore/container", "[method]container.list-objects")
list_objects(self) -> Result< StreamObjectNames, utf8 > { }
list_objects(self) -> Result<StreamObjectNames, utf8> { }

⍝? deletes object.
⍝? does not return error if object did not exist.
#import("wasi:blobstore/container", "[method]container.delete-object")
delete_object(self, name: utf8) -> Result< (), utf8 > { }
delete_object(self, name: utf8) -> Result<(), utf8> { }

⍝? deletes multiple objects in the container
#import("wasi:blobstore/container", "[method]container.delete-objects")
delete_objects(self, names: Array< utf8 >) -> Result< (), utf8 > { }
delete_objects(self, names: Array<utf8>) -> Result<(), utf8> { }

⍝? returns true if the object exists in this container
#import("wasi:blobstore/container", "[method]container.has-object")
has_object(self, name: utf8) -> Result< bool, utf8 > { }
has_object(self, name: utf8) -> Result<bool, utf8> { }

⍝? returns metadata for the object
#import("wasi:blobstore/container", "[method]container.object-info")
object_info(self, name: utf8) -> Result< ObjectMetadata, utf8 > { }
object_info(self, name: utf8) -> Result<ObjectMetadata, utf8> { }

⍝? removes all objects within the container, leaving the container empty.
#import("wasi:blobstore/container", "[method]container.clear")
clear(self) -> Result< (), utf8 > { }
clear(self) -> Result<(), utf8> { }

}
⍝? this defines the `stream-object-names` resource which is a representation of stream<object-name>
Expand All @@ -136,13 +138,13 @@ resource class StreamObjectNames {
⍝?
⍝? This function returns the list of objects read, and a boolean indicating if the end of the stream was reached.
#import("wasi:blobstore/container", "[method]stream-object-names.read-stream-object-names")
read_stream_object_names(self, len: u64) -> Result< (Array< utf8 >, bool), utf8 > { }
read_stream_object_names(self, len: u64) -> Result<(Array<utf8>, bool), utf8> { }

⍝? skip the next number of objects in the stream
⍝?
⍝? This function returns the number of objects skipped, and a boolean indicating if the end of the stream was reached.
#import("wasi:blobstore/container", "[method]stream-object-names.skip-stream-object-names")
skip_stream_object_names(self, num: u64) -> Result< (u64, bool), utf8 > { }
skip_stream_object_names(self, num: u64) -> Result<(u64, bool), utf8> { }

}
alias typus Container = Container;
Expand All @@ -151,29 +153,29 @@ alias typus ContainerName = utf8;
alias typus ObjectId = ObjectId;
⍝? creates a new empty container
#import("wasi:blobstore/blobstore", "create-container")
micro create_container(name: utf8) -> Result< Container, utf8 > { }
micro create_container(name: utf8) -> Result<Container, utf8> { }

⍝? retrieves a container by name
#import("wasi:blobstore/blobstore", "get-container")
micro get_container(name: utf8) -> Result< Container, utf8 > { }
micro get_container(name: utf8) -> Result<Container, utf8> { }

⍝? deletes a container and all objects within it
#import("wasi:blobstore/blobstore", "delete-container")
micro delete_container(name: utf8) -> Result< (), utf8 > { }
micro delete_container(name: utf8) -> Result<(), utf8> { }

⍝? returns true if the container exists
#import("wasi:blobstore/blobstore", "container-exists")
micro container_exists(name: utf8) -> Result< bool, utf8 > { }
micro container_exists(name: utf8) -> Result<bool, utf8> { }

⍝? copies (duplicates) an object, to the same or a different container.
⍝? returns an error if the target container does not exist.
⍝? overwrites destination object if it already existed.
#import("wasi:blobstore/blobstore", "copy-object")
micro copy_object(src: ObjectId, dest: ObjectId) -> Result< (), utf8 > { }
micro copy_object(src: ObjectId, dest: ObjectId) -> Result<(), utf8> { }

⍝? moves or renames an object, to the same or a different container
⍝? returns an error if the destination container does not exist.
⍝? overwrites destination object if it already existed.
#import("wasi:blobstore/blobstore", "move-object")
micro move_object(src: ObjectId, dest: ObjectId) -> Result< (), utf8 > { }
micro move_object(src: ObjectId, dest: ObjectId) -> Result<(), utf8> { }

18 changes: 18 additions & 0 deletions projects/valkyrie-ffi/tests/wasi/logging.vk
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
enumerate Level {
#export("trace")
Trace,
#export("debug")
Debug,
#export("info")
Info,
#export("warn")
Warn,
#export("error")
Error,
#export("critical")
Critical,
}

#import("wasi:logging/logging", "log")
micro log(level: Level, context: utf8, message: utf8) -> () { }

25 changes: 0 additions & 25 deletions projects/valkyrie-wit/index.wit

This file was deleted.

0 comments on commit 3c7a69d

Please sign in to comment.