From 493d97d73f3998f962700348fab16185b1796fa0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 26 Mar 2020 09:10:30 -0700 Subject: [PATCH 1/4] Shuffle around the wiggle crates This commit reorganizes the wiggle crates slightly by performing the following transforms: * The `crates/wiggle` crate, previously named `wiggle`, was moved to `crates/wiggle/crates/macro` and is renamed to `wiggle-macro`. * The `crates/wiggle/crates/runtime` crate, previously named `wiggle-runtime`, was moved to `crates/wiggle` and is renamed to `wiggle`. * The new `wiggle` crate depends on `wiggle-macro` and reexports the macro. The goal here is that consumers only deal with the `wiggle` crate itself. No more crates depend on `wiggle-runtime` and all dependencies are entirely on just the `wiggle` crate. --- Cargo.lock | 17 +- crates/wasi-common/Cargo.toml | 5 +- crates/wasi-common/src/path.rs | 2 +- .../src/snapshots/wasi_snapshot_preview1.rs | 2 +- crates/wasi-common/src/wasi.rs | 12 +- crates/wasi-common/wig/src/wasi.rs | 4 +- crates/wasi/Cargo.toml | 2 +- crates/wiggle/Cargo.toml | 20 +- crates/wiggle/crates/generate/Cargo.toml | 1 - crates/wiggle/crates/generate/src/funcs.rs | 18 +- crates/wiggle/crates/generate/src/lib.rs | 4 +- crates/wiggle/crates/generate/src/names.rs | 6 +- .../wiggle/crates/generate/src/types/enum.rs | 22 +- .../wiggle/crates/generate/src/types/flags.rs | 20 +- .../crates/generate/src/types/handle.rs | 10 +- .../wiggle/crates/generate/src/types/int.rs | 18 +- .../wiggle/crates/generate/src/types/mod.rs | 6 +- .../crates/generate/src/types/struct.rs | 20 +- .../wiggle/crates/generate/src/types/union.rs | 14 +- .../crates/{runtime => macro}/Cargo.toml | 19 +- .../wiggle/crates/{runtime => macro}/LICENSE | 0 crates/wiggle/crates/macro/src/lib.rs | 98 +++ crates/wiggle/crates/runtime/src/lib.rs | 579 --------------- crates/wiggle/crates/test/Cargo.toml | 2 +- crates/wiggle/crates/test/src/lib.rs | 6 +- .../wiggle/{crates/runtime => }/src/borrow.rs | 0 .../wiggle/{crates/runtime => }/src/error.rs | 0 .../{crates/runtime => }/src/guest_type.rs | 0 crates/wiggle/src/lib.rs | 671 +++++++++++++++--- .../wiggle/{crates/runtime => }/src/region.rs | 0 crates/wiggle/tests/arrays.rs | 2 +- crates/wiggle/tests/atoms.rs | 2 +- crates/wiggle/tests/flags.rs | 2 +- crates/wiggle/tests/handles.rs | 2 +- crates/wiggle/tests/ints.rs | 2 +- crates/wiggle/tests/pointers.rs | 2 +- crates/wiggle/tests/strings.rs | 2 +- crates/wiggle/tests/structs.rs | 2 +- crates/wiggle/tests/union.rs | 2 +- crates/wiggle/tests/wasi.rs | 2 +- scripts/test-all.sh | 1 - 41 files changed, 800 insertions(+), 799 deletions(-) rename crates/wiggle/crates/{runtime => macro}/Cargo.toml (60%) rename crates/wiggle/crates/{runtime => macro}/LICENSE (100%) create mode 100644 crates/wiggle/crates/macro/src/lib.rs delete mode 100644 crates/wiggle/crates/runtime/src/lib.rs rename crates/wiggle/{crates/runtime => }/src/borrow.rs (100%) rename crates/wiggle/{crates/runtime => }/src/error.rs (100%) rename crates/wiggle/{crates/runtime => }/src/guest_type.rs (100%) rename crates/wiggle/{crates/runtime => }/src/region.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e8b7813187f1..fabef9936052 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2243,7 +2243,6 @@ dependencies = [ "thiserror", "wig", "wiggle", - "wiggle-runtime", "winapi", "winx", "yanix", @@ -2517,7 +2516,7 @@ dependencies = [ "wasmtime", "wasmtime-runtime", "wig", - "wiggle-runtime", + "wiggle", ] [[package]] @@ -2571,9 +2570,8 @@ name = "wiggle" version = "0.13.0" dependencies = [ "proptest", - "syn", - "wiggle-generate", - "wiggle-runtime", + "thiserror", + "wiggle-macro", "wiggle-test", "witx", ] @@ -2587,15 +2585,16 @@ dependencies = [ "proc-macro2", "quote", "syn", - "wiggle-runtime", "witx", ] [[package]] -name = "wiggle-runtime" +name = "wiggle-macro" version = "0.13.0" dependencies = [ - "thiserror", + "syn", + "wiggle", + "wiggle-generate", "witx", ] @@ -2604,7 +2603,7 @@ name = "wiggle-test" version = "0.13.0" dependencies = [ "proptest", - "wiggle-runtime", + "wiggle", ] [[package]] diff --git a/crates/wasi-common/Cargo.toml b/crates/wasi-common/Cargo.toml index e24745adfb1d..704c92109aaa 100644 --- a/crates/wasi-common/Cargo.toml +++ b/crates/wasi-common/Cargo.toml @@ -21,8 +21,7 @@ filetime = "0.2.7" lazy_static = "1.4.0" num = { version = "0.2.0", default-features = false } wig = { path = "wig", version = "0.13.0" } -wiggle = { path = "../wiggle", default-features = false } -wiggle-runtime = { path = "../wiggle/crates/runtime" } +wiggle = { path = "../wiggle", default-features = false, version = "0.13.0" } [target.'cfg(unix)'.dependencies] yanix = { path = "yanix", version = "0.13.0" } @@ -38,4 +37,4 @@ maintenance = { status = "actively-developed" } [features] # Need to make the wiggle_metadata feature available to consumers of this # crate if they want the snapshots to have metadata available. -wiggle_metadata = ["wiggle/wiggle_metadata", "wiggle-runtime/wiggle_metadata"] +wiggle_metadata = ["wiggle/wiggle_metadata"] diff --git a/crates/wasi-common/src/path.rs b/crates/wasi-common/src/path.rs index 27a23ba1d954..80f80f9c2ff6 100644 --- a/crates/wasi-common/src/path.rs +++ b/crates/wasi-common/src/path.rs @@ -4,7 +4,7 @@ use crate::wasi::{types, Errno, Result}; use crate::{entry::Descriptor, entry::Entry}; use std::path::{Component, Path}; use std::str; -use wiggle_runtime::{GuestBorrows, GuestPtr}; +use wiggle::{GuestBorrows, GuestPtr}; pub(crate) use sys::path::*; diff --git a/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs b/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs index b19638bc3688..7038bea6e748 100644 --- a/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs +++ b/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs @@ -9,7 +9,7 @@ use std::cell::Ref; use std::convert::TryInto; use std::fs::File; use std::io::{self, Read, Seek, SeekFrom, Write}; -use wiggle_runtime::{GuestBorrows, GuestPtr}; +use wiggle::{GuestBorrows, GuestPtr}; impl<'a> WasiSnapshotPreview1 for WasiCtx { fn args_get<'b>( diff --git a/crates/wasi-common/src/wasi.rs b/crates/wasi-common/src/wasi.rs index 41b555589854..879388189d9d 100644 --- a/crates/wasi-common/src/wasi.rs +++ b/crates/wasi-common/src/wasi.rs @@ -11,23 +11,23 @@ wiggle::from_witx!({ pub use types::Errno; pub type Result = std::result::Result; -impl<'a> wiggle_runtime::GuestErrorType<'a> for Errno { +impl<'a> wiggle::GuestErrorType<'a> for Errno { type Context = WasiCtx; fn success() -> Self { Self::Success } - fn from_error(e: wiggle_runtime::GuestError, _ctx: &Self::Context) -> Self { + fn from_error(e: wiggle::GuestError, _ctx: &Self::Context) -> Self { eprintln!("Guest error: {:?}", e); // TODO proper error mapping Self::Inval } } -impl From for Errno { - fn from(err: wiggle_runtime::GuestError) -> Self { - use wiggle_runtime::GuestError::*; +impl From for Errno { + fn from(err: wiggle::GuestError) -> Self { + use wiggle::GuestError::*; match err { InvalidFlagValue { .. } => Self::Inval, InvalidEnumValue { .. } => Self::Inval, @@ -83,7 +83,7 @@ pub(crate) trait AsBytes { impl AsBytes for types::Dirent { fn as_bytes(&self) -> Result> { use std::convert::TryInto; - use wiggle_runtime::GuestType; + use wiggle::GuestType; assert_eq!( Self::guest_size(), diff --git a/crates/wasi-common/wig/src/wasi.rs b/crates/wasi-common/wig/src/wasi.rs index 001bb708fb76..48ee4ec14a93 100644 --- a/crates/wasi-common/wig/src/wasi.rs +++ b/crates/wasi-common/wig/src/wasi.rs @@ -464,7 +464,7 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream { quote! { /// Lightweight `wasmtime::Memory` wrapper so that we can - /// implement `wiggle_runtime::GuestMemory` trait on it which is + /// implement `wiggle::GuestMemory` trait on it which is /// now required to interface with `wasi-common`. struct WasiMemory(wasmtime::Memory); @@ -474,7 +474,7 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream { } } - unsafe impl wiggle_runtime::GuestMemory for WasiMemory { + unsafe impl wiggle::GuestMemory for WasiMemory { fn base(&self) -> (*mut u8, u32) { (self.0.data_ptr(), self.0.data_size() as _) } diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml index 4f2b919631d2..28846fa51922 100644 --- a/crates/wasi/Cargo.toml +++ b/crates/wasi/Cargo.toml @@ -18,7 +18,7 @@ wasi-common = { path = "../wasi-common", version = "0.13.0" } wasmtime = { path = "../api", version = "0.13.0", default-features = false } wasmtime-runtime = { path = "../runtime", version = "0.13.0" } wig = { path = "../wasi-common/wig", version = "0.13.0" } -wiggle-runtime = { path = "../wiggle/crates/runtime", version = "0.13.0" } +wiggle = { path = "../wiggle", version = "0.13.0" } [badges] maintenance = { status = "actively-developed" } diff --git a/crates/wiggle/Cargo.toml b/crates/wiggle/Cargo.toml index b9ad2234fbcc..4ef105d952c4 100644 --- a/crates/wiggle/Cargo.toml +++ b/crates/wiggle/Cargo.toml @@ -2,23 +2,21 @@ name = "wiggle" version = "0.13.0" authors = ["Pat Hickey ", "Jakub Konka ", "Alex Crichton "] -license = "Apache-2.0 WITH LLVM-exception" edition = "2018" -description = "Wiggle code generator" +license = "Apache-2.0 WITH LLVM-exception" +description = "Runtime components of wiggle code generator" categories = ["wasm"] keywords = ["webassembly", "wasm"] repository = "https://github.com/bytecodealliance/wasmtime" -readme = "README.md" include = ["src/**/*", "LICENSE"] -[lib] -proc-macro = true - [dependencies] -wiggle-generate = { path = "crates/generate", version = "0.13.0" } -wiggle-runtime = { path = "crates/runtime", version = "0.13.0" } -witx = { path = "../wasi-common/wig/WASI/tools/witx", version = "0.8.4" } -syn = { version = "1.0", features = ["full"] } +thiserror = "1" +witx = { path = "../wasi-common/wig/WASI/tools/witx", version = "0.8.4", optional = true } +wiggle-macro = { path = "crates/macro", version = "0.13.0" } + +[badges] +maintenance = { status = "actively-developed" } [dev-dependencies] wiggle-test = { path = "crates/test", version = "0.13.0" } @@ -31,7 +29,7 @@ proptest = "0.9" # by the `wiggle_metadata` feature flag. We use this feature flag so that # users of wiggle are not forced to take a direct dependency on the `witx` # crate unless they want it. -wiggle_metadata = ["wiggle-runtime/wiggle_metadata"] +wiggle_metadata = ['witx', "wiggle-macro/wiggle_metadata"] # In order to test that the contents of this metadata module meet # expectations, we must have this feature enabled for the crate by default. default = ["wiggle_metadata"] diff --git a/crates/wiggle/crates/generate/Cargo.toml b/crates/wiggle/crates/generate/Cargo.toml index 6b4f27b9535b..98b5415b61d5 100644 --- a/crates/wiggle/crates/generate/Cargo.toml +++ b/crates/wiggle/crates/generate/Cargo.toml @@ -14,7 +14,6 @@ include = ["src/**/*", "LICENSE"] [lib] [dependencies] -wiggle-runtime = { path = "../runtime", version = "0.13.0" } witx = { version = "0.8.4", path = "../../../wasi-common/wig/WASI/tools/witx" } quote = "1.0" proc-macro2 = "1.0" diff --git a/crates/wiggle/crates/generate/src/funcs.rs b/crates/wiggle/crates/generate/src/funcs.rs index 2c82ba79e8ef..de163f6e3d72 100644 --- a/crates/wiggle/crates/generate/src/funcs.rs +++ b/crates/wiggle/crates/generate/src/funcs.rs @@ -19,7 +19,7 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { }); let abi_args = quote!( - ctx: &#ctx_type, memory: &dyn wiggle_runtime::GuestMemory, + ctx: &#ctx_type, memory: &dyn wiggle::GuestMemory, #(#params),* ); let abi_ret = if let Some(ret) = &coretype.ret { @@ -51,8 +51,8 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { }; let err_typename = names.type_ref(&tref, anon_lifetime()); quote! { - let e = wiggle_runtime::GuestError::InFunc { funcname: #funcname, location: #location, err: Box::new(e.into()) }; - let err: #err_typename = wiggle_runtime::GuestErrorType::from_error(e, ctx); + let e = wiggle::GuestError::InFunc { funcname: #funcname, location: #location, err: Box::new(e.into()) }; + let err: #err_typename = wiggle::GuestErrorType::from_error(e, ctx); return #abi_ret::from(err); } } else { @@ -100,7 +100,7 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { let success = if let Some(ref err_type) = err_type { let err_typename = names.type_ref(&err_type, anon_lifetime()); quote! { - let success:#err_typename = wiggle_runtime::GuestErrorType::success(); + let success:#err_typename = wiggle::GuestErrorType::success(); #abi_ret::from(success) } } else { @@ -147,7 +147,7 @@ fn marshal_arg( let arg_name = names.func_ptr_binding(¶m.name); let name = names.func_param(¶m.name); quote! { - let #name = match wiggle_runtime::GuestPtr::<#pointee_type>::new(memory, #arg_name as u32).read() { + let #name = match wiggle::GuestPtr::<#pointee_type>::new(memory, #arg_name as u32).read() { Ok(r) => r, Err(e) => { #error_handling @@ -193,7 +193,7 @@ fn marshal_arg( let len_name = names.func_len_binding(¶m.name); let name = names.func_param(¶m.name); quote! { - let #name = wiggle_runtime::GuestPtr::<#lifetime, str>::new(memory, (#ptr_name as u32, #len_name as u32)); + let #name = wiggle::GuestPtr::<#lifetime, str>::new(memory, (#ptr_name as u32, #len_name as u32)); } } }, @@ -201,7 +201,7 @@ fn marshal_arg( let pointee_type = names.type_ref(pointee, anon_lifetime()); let name = names.func_param(¶m.name); quote! { - let #name = wiggle_runtime::GuestPtr::<#pointee_type>::new(memory, #name as u32); + let #name = wiggle::GuestPtr::<#pointee_type>::new(memory, #name as u32); } } witx::Type::Struct(_) => read_conversion, @@ -211,7 +211,7 @@ fn marshal_arg( let len_name = names.func_len_binding(¶m.name); let name = names.func_param(¶m.name); quote! { - let #name = wiggle_runtime::GuestPtr::<[#pointee_type]>::new(memory, (#ptr_name as u32, #len_name as u32)); + let #name = wiggle::GuestPtr::<[#pointee_type]>::new(memory, (#ptr_name as u32, #len_name as u32)); } } witx::Type::Union(_u) => read_conversion, @@ -239,7 +239,7 @@ where let ptr_name = names.func_ptr_binding(&result.name); let ptr_err_handling = error_handling(&format!("{}:result_ptr_mut", result.name.as_str())); let pre = quote! { - let #ptr_name = wiggle_runtime::GuestPtr::<#pointee_type>::new(memory, #ptr_name as u32); + let #ptr_name = wiggle::GuestPtr::<#pointee_type>::new(memory, #ptr_name as u32); }; // trait binding returns func_param name. let val_name = names.func_param(&result.name); diff --git a/crates/wiggle/crates/generate/src/lib.rs b/crates/wiggle/crates/generate/src/lib.rs index e1e4f773df8d..f67761850a11 100644 --- a/crates/wiggle/crates/generate/src/lib.rs +++ b/crates/wiggle/crates/generate/src/lib.rs @@ -40,8 +40,8 @@ pub fn generate(doc: &witx::Document, config: &Config) -> TokenStream { quote! { pub mod metadata { pub const DOC_TEXT: &str = #doc_text; - pub fn document() -> wiggle_runtime::witx::Document { - wiggle_runtime::witx::parse(DOC_TEXT).unwrap() + pub fn document() -> wiggle::witx::Document { + wiggle::witx::parse(DOC_TEXT).unwrap() } } } diff --git a/crates/wiggle/crates/generate/src/names.rs b/crates/wiggle/crates/generate/src/names.rs index aa67364a0eda..5879f6605bdf 100644 --- a/crates/wiggle/crates/generate/src/names.rs +++ b/crates/wiggle/crates/generate/src/names.rs @@ -26,7 +26,7 @@ impl Names { } pub fn builtin_type(&self, b: BuiltinType, lifetime: TokenStream) -> TokenStream { match b { - BuiltinType::String => quote!(wiggle_runtime::GuestPtr<#lifetime, str>), + BuiltinType::String => quote!(wiggle::GuestPtr<#lifetime, str>), BuiltinType::U8 => quote!(u8), BuiltinType::U16 => quote!(u16), BuiltinType::U32 => quote!(u32), @@ -64,11 +64,11 @@ impl Names { witx::Type::Builtin(builtin) => self.builtin_type(*builtin, lifetime.clone()), witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { let pointee_type = self.type_ref(&pointee, lifetime.clone()); - quote!(wiggle_runtime::GuestPtr<#lifetime, #pointee_type>) + quote!(wiggle::GuestPtr<#lifetime, #pointee_type>) } witx::Type::Array(pointee) => { let pointee_type = self.type_ref(&pointee, lifetime.clone()); - quote!(wiggle_runtime::GuestPtr<#lifetime, [#pointee_type]>) + quote!(wiggle::GuestPtr<#lifetime, [#pointee_type]>) } _ => unimplemented!("anonymous type ref {:?}", tref), }, diff --git a/crates/wiggle/crates/generate/src/types/enum.rs b/crates/wiggle/crates/generate/src/types/enum.rs index 8aa77f868250..5dd5de168b31 100644 --- a/crates/wiggle/crates/generate/src/types/enum.rs +++ b/crates/wiggle/crates/generate/src/types/enum.rs @@ -46,18 +46,18 @@ pub(super) fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype } impl ::std::convert::TryFrom<#repr> for #ident { - type Error = wiggle_runtime::GuestError; - fn try_from(value: #repr) -> Result<#ident, wiggle_runtime::GuestError> { + type Error = wiggle::GuestError; + fn try_from(value: #repr) -> Result<#ident, wiggle::GuestError> { match value as usize { #(#tryfrom_repr_cases),*, - _ => Err(wiggle_runtime::GuestError::InvalidEnumValue(stringify!(#ident))), + _ => Err(wiggle::GuestError::InvalidEnumValue(stringify!(#ident))), } } } impl ::std::convert::TryFrom<#abi_repr> for #ident { - type Error = wiggle_runtime::GuestError; - fn try_from(value: #abi_repr) -> Result<#ident, wiggle_runtime::GuestError> { + type Error = wiggle::GuestError; + fn try_from(value: #abi_repr) -> Result<#ident, wiggle::GuestError> { #ident::try_from(value as #repr) } } @@ -76,7 +76,7 @@ pub(super) fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype } } - impl<'a> wiggle_runtime::GuestType<'a> for #ident { + impl<'a> wiggle::GuestType<'a> for #ident { fn guest_size() -> u32 { #repr::guest_size() } @@ -85,23 +85,23 @@ pub(super) fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype #repr::guest_align() } - fn read(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> { + fn read(location: &wiggle::GuestPtr<#ident>) -> Result<#ident, wiggle::GuestError> { use std::convert::TryFrom; let reprval = #repr::read(&location.cast())?; let value = #ident::try_from(reprval)?; Ok(value) } - fn write(location: &wiggle_runtime::GuestPtr<'_, #ident>, val: Self) - -> Result<(), wiggle_runtime::GuestError> + fn write(location: &wiggle::GuestPtr<'_, #ident>, val: Self) + -> Result<(), wiggle::GuestError> { #repr::write(&location.cast(), #repr::from(val)) } } - unsafe impl <'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident { + unsafe impl <'a> wiggle::GuestTypeTransparent<'a> for #ident { #[inline] - fn validate(location: *mut #ident) -> Result<(), wiggle_runtime::GuestError> { + fn validate(location: *mut #ident) -> Result<(), wiggle::GuestError> { use std::convert::TryFrom; // Validate value in memory using #ident::try_from(reprval) let reprval = unsafe { (location as *mut #repr).read() }; diff --git a/crates/wiggle/crates/generate/src/types/flags.rs b/crates/wiggle/crates/generate/src/types/flags.rs index b0ba9c86a603..084ac9e45254 100644 --- a/crates/wiggle/crates/generate/src/types/flags.rs +++ b/crates/wiggle/crates/generate/src/types/flags.rs @@ -116,10 +116,10 @@ pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDataty } impl ::std::convert::TryFrom<#repr> for #ident { - type Error = wiggle_runtime::GuestError; - fn try_from(value: #repr) -> Result { + type Error = wiggle::GuestError; + fn try_from(value: #repr) -> Result { if #repr::from(!#ident::all()) & value != 0 { - Err(wiggle_runtime::GuestError::InvalidFlagValue(stringify!(#ident))) + Err(wiggle::GuestError::InvalidFlagValue(stringify!(#ident))) } else { Ok(#ident(value)) } @@ -127,8 +127,8 @@ pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDataty } impl ::std::convert::TryFrom<#abi_repr> for #ident { - type Error = wiggle_runtime::GuestError; - fn try_from(value: #abi_repr) -> Result<#ident, wiggle_runtime::GuestError> { + type Error = wiggle::GuestError; + fn try_from(value: #abi_repr) -> Result<#ident, wiggle::GuestError> { #ident::try_from(value as #repr) } } @@ -145,7 +145,7 @@ pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDataty } } - impl<'a> wiggle_runtime::GuestType<'a> for #ident { + impl<'a> wiggle::GuestType<'a> for #ident { fn guest_size() -> u32 { #repr::guest_size() } @@ -154,21 +154,21 @@ pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDataty #repr::guest_align() } - fn read(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> { + fn read(location: &wiggle::GuestPtr<#ident>) -> Result<#ident, wiggle::GuestError> { use std::convert::TryFrom; let reprval = #repr::read(&location.cast())?; let value = #ident::try_from(reprval)?; Ok(value) } - fn write(location: &wiggle_runtime::GuestPtr<'_, #ident>, val: Self) -> Result<(), wiggle_runtime::GuestError> { + fn write(location: &wiggle::GuestPtr<'_, #ident>, val: Self) -> Result<(), wiggle::GuestError> { let val: #repr = #repr::from(val); #repr::write(&location.cast(), val) } } - unsafe impl <'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident { + unsafe impl <'a> wiggle::GuestTypeTransparent<'a> for #ident { #[inline] - fn validate(location: *mut #ident) -> Result<(), wiggle_runtime::GuestError> { + fn validate(location: *mut #ident) -> Result<(), wiggle::GuestError> { use std::convert::TryFrom; // Validate value in memory using #ident::try_from(reprval) let reprval = unsafe { (location as *mut #repr).read() }; diff --git a/crates/wiggle/crates/generate/src/types/handle.rs b/crates/wiggle/crates/generate/src/types/handle.rs index 52e0d2501c29..b42e90df1c8e 100644 --- a/crates/wiggle/crates/generate/src/types/handle.rs +++ b/crates/wiggle/crates/generate/src/types/handle.rs @@ -52,7 +52,7 @@ pub(super) fn define_handle( } } - impl<'a> wiggle_runtime::GuestType<'a> for #ident { + impl<'a> wiggle::GuestType<'a> for #ident { fn guest_size() -> u32 { #size } @@ -61,18 +61,18 @@ pub(super) fn define_handle( #align } - fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> { + fn read(location: &wiggle::GuestPtr<'a, #ident>) -> Result<#ident, wiggle::GuestError> { Ok(#ident(u32::read(&location.cast())?)) } - fn write(location: &wiggle_runtime::GuestPtr<'_, Self>, val: Self) -> Result<(), wiggle_runtime::GuestError> { + fn write(location: &wiggle::GuestPtr<'_, Self>, val: Self) -> Result<(), wiggle::GuestError> { u32::write(&location.cast(), val.0) } } - unsafe impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident { + unsafe impl<'a> wiggle::GuestTypeTransparent<'a> for #ident { #[inline] - fn validate(_location: *mut #ident) -> Result<(), wiggle_runtime::GuestError> { + fn validate(_location: *mut #ident) -> Result<(), wiggle::GuestError> { // All bit patterns accepted Ok(()) } diff --git a/crates/wiggle/crates/generate/src/types/int.rs b/crates/wiggle/crates/generate/src/types/int.rs index ee870eb6a659..78a439e49434 100644 --- a/crates/wiggle/crates/generate/src/types/int.rs +++ b/crates/wiggle/crates/generate/src/types/int.rs @@ -37,15 +37,15 @@ pub(super) fn define_int(names: &Names, name: &witx::Id, i: &witx::IntDatatype) } impl ::std::convert::TryFrom<#repr> for #ident { - type Error = wiggle_runtime::GuestError; - fn try_from(value: #repr) -> Result { + type Error = wiggle::GuestError; + fn try_from(value: #repr) -> Result { Ok(#ident(value)) } } impl ::std::convert::TryFrom<#abi_repr> for #ident { - type Error = wiggle_runtime::GuestError; - fn try_from(value: #abi_repr) -> Result<#ident, wiggle_runtime::GuestError> { + type Error = wiggle::GuestError; + fn try_from(value: #abi_repr) -> Result<#ident, wiggle::GuestError> { #ident::try_from(value as #repr) } } @@ -62,7 +62,7 @@ pub(super) fn define_int(names: &Names, name: &witx::Id, i: &witx::IntDatatype) } } - impl<'a> wiggle_runtime::GuestType<'a> for #ident { + impl<'a> wiggle::GuestType<'a> for #ident { fn guest_size() -> u32 { #repr::guest_size() } @@ -71,19 +71,19 @@ pub(super) fn define_int(names: &Names, name: &witx::Id, i: &witx::IntDatatype) #repr::guest_align() } - fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> { + fn read(location: &wiggle::GuestPtr<'a, #ident>) -> Result<#ident, wiggle::GuestError> { Ok(#ident(#repr::read(&location.cast())?)) } - fn write(location: &wiggle_runtime::GuestPtr<'_, #ident>, val: Self) -> Result<(), wiggle_runtime::GuestError> { + fn write(location: &wiggle::GuestPtr<'_, #ident>, val: Self) -> Result<(), wiggle::GuestError> { #repr::write(&location.cast(), val.0) } } - unsafe impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident { + unsafe impl<'a> wiggle::GuestTypeTransparent<'a> for #ident { #[inline] - fn validate(_location: *mut #ident) -> Result<(), wiggle_runtime::GuestError> { + fn validate(_location: *mut #ident) -> Result<(), wiggle::GuestError> { // All bit patterns accepted Ok(()) } diff --git a/crates/wiggle/crates/generate/src/types/mod.rs b/crates/wiggle/crates/generate/src/types/mod.rs index 93e7d5f89206..cba24d8197af 100644 --- a/crates/wiggle/crates/generate/src/types/mod.rs +++ b/crates/wiggle/crates/generate/src/types/mod.rs @@ -23,10 +23,10 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea witx::Type::Handle(h) => handle::define_handle(names, &namedtype.name, &h), witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b), witx::Type::Pointer(p) => { - define_witx_pointer(names, &namedtype.name, quote!(wiggle_runtime::GuestPtr), p) + define_witx_pointer(names, &namedtype.name, quote!(wiggle::GuestPtr), p) } witx::Type::ConstPointer(p) => { - define_witx_pointer(names, &namedtype.name, quote!(wiggle_runtime::GuestPtr), p) + define_witx_pointer(names, &namedtype.name, quote!(wiggle::GuestPtr), p) } witx::Type::Array(arr) => define_witx_array(names, &namedtype.name, &arr), }, @@ -68,7 +68,7 @@ fn define_witx_pointer( fn define_witx_array(names: &Names, name: &witx::Id, arr_raw: &witx::TypeRef) -> TokenStream { let ident = names.type_(name); let pointee_type = names.type_ref(arr_raw, quote!('a)); - quote!(pub type #ident<'a> = wiggle_runtime::GuestPtr<'a, [#pointee_type]>;) + quote!(pub type #ident<'a> = wiggle::GuestPtr<'a, [#pointee_type]>;) } fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream { diff --git a/crates/wiggle/crates/generate/src/types/struct.rs b/crates/wiggle/crates/generate/src/types/struct.rs index ea0a66115aaa..975233ded2e7 100644 --- a/crates/wiggle/crates/generate/src/types/struct.rs +++ b/crates/wiggle/crates/generate/src/types/struct.rs @@ -23,7 +23,7 @@ pub(super) fn define_struct( witx::Type::Builtin(builtin) => names.builtin_type(*builtin, quote!('a)), witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { let pointee_type = names.type_ref(&pointee, quote!('a)); - quote!(wiggle_runtime::GuestPtr<'a, #pointee_type>) + quote!(wiggle::GuestPtr<'a, #pointee_type>) } _ => unimplemented!("other anonymous struct members"), }, @@ -39,20 +39,20 @@ pub(super) fn define_struct( witx::TypeRef::Name(nt) => { let type_ = names.type_(&nt.name); quote! { - let #name = <#type_ as wiggle_runtime::GuestType>::read(&#location)?; + let #name = <#type_ as wiggle::GuestType>::read(&#location)?; } } witx::TypeRef::Value(ty) => match &**ty { witx::Type::Builtin(builtin) => { let type_ = names.builtin_type(*builtin, anon_lifetime()); quote! { - let #name = <#type_ as wiggle_runtime::GuestType>::read(&#location)?; + let #name = <#type_ as wiggle::GuestType>::read(&#location)?; } } witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { let pointee_type = names.type_ref(&pointee, anon_lifetime()); quote! { - let #name = as wiggle_runtime::GuestType>::read(&#location)?; + let #name = as wiggle::GuestType>::read(&#location)?; } } _ => unimplemented!("other anonymous struct members"), @@ -64,7 +64,7 @@ pub(super) fn define_struct( let name = names.struct_member(&ml.member.name); let offset = ml.offset as u32; quote! { - wiggle_runtime::GuestType::write( + wiggle::GuestType::write( &location.cast::().add(#offset)?.cast(), val.#name, )?; @@ -91,9 +91,9 @@ pub(super) fn define_struct( }); quote! { - unsafe impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident { + unsafe impl<'a> wiggle::GuestTypeTransparent<'a> for #ident { #[inline] - fn validate(location: *mut #ident) -> Result<(), wiggle_runtime::GuestError> { + fn validate(location: *mut #ident) -> Result<(), wiggle::GuestError> { #(#member_validate)* Ok(()) } @@ -109,7 +109,7 @@ pub(super) fn define_struct( #(#member_decls),* } - impl<'a> wiggle_runtime::GuestType<'a> for #ident #struct_lifetime { + impl<'a> wiggle::GuestType<'a> for #ident #struct_lifetime { fn guest_size() -> u32 { #size } @@ -118,12 +118,12 @@ pub(super) fn define_struct( #align } - fn read(location: &wiggle_runtime::GuestPtr<'a, Self>) -> Result { + fn read(location: &wiggle::GuestPtr<'a, Self>) -> Result { #(#member_reads)* Ok(#ident { #(#member_names),* }) } - fn write(location: &wiggle_runtime::GuestPtr<'_, Self>, val: Self) -> Result<(), wiggle_runtime::GuestError> { + fn write(location: &wiggle::GuestPtr<'_, Self>, val: Self) -> Result<(), wiggle::GuestError> { #(#member_writes)* Ok(()) } diff --git a/crates/wiggle/crates/generate/src/types/union.rs b/crates/wiggle/crates/generate/src/types/union.rs index c3c31d771460..c7318e8cb775 100644 --- a/crates/wiggle/crates/generate/src/types/union.rs +++ b/crates/wiggle/crates/generate/src/types/union.rs @@ -33,7 +33,7 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty quote! { #tagname::#variantname => { let variant_ptr = location.cast::().add(#contents_offset)?; - let variant_val = <#varianttype as wiggle_runtime::GuestType>::read(&variant_ptr.cast())?; + let variant_val = <#varianttype as wiggle::GuestType>::read(&variant_ptr.cast())?; Ok(#ident::#variantname(variant_val)) } } @@ -53,7 +53,7 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty #ident::#variantname(contents) => { #write_tag let variant_ptr = location.cast::().add(#contents_offset)?; - <#varianttype as wiggle_runtime::GuestType>::write(&variant_ptr.cast(), contents)?; + <#varianttype as wiggle::GuestType>::write(&variant_ptr.cast(), contents)?; } } } else { @@ -77,7 +77,7 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty #(#variants),* } - impl<'a> wiggle_runtime::GuestType<'a> for #ident #enum_lifetime { + impl<'a> wiggle::GuestType<'a> for #ident #enum_lifetime { fn guest_size() -> u32 { #size } @@ -86,8 +86,8 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty #align } - fn read(location: &wiggle_runtime::GuestPtr<'a, Self>) - -> Result + fn read(location: &wiggle::GuestPtr<'a, Self>) + -> Result { let tag = location.cast().read()?; match tag { @@ -96,8 +96,8 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty } - fn write(location: &wiggle_runtime::GuestPtr<'_, Self>, val: Self) - -> Result<(), wiggle_runtime::GuestError> + fn write(location: &wiggle::GuestPtr<'_, Self>, val: Self) + -> Result<(), wiggle::GuestError> { match val { #(#write_variant)* diff --git a/crates/wiggle/crates/runtime/Cargo.toml b/crates/wiggle/crates/macro/Cargo.toml similarity index 60% rename from crates/wiggle/crates/runtime/Cargo.toml rename to crates/wiggle/crates/macro/Cargo.toml index d03721cbd9c1..7869b2f0687c 100644 --- a/crates/wiggle/crates/runtime/Cargo.toml +++ b/crates/wiggle/crates/macro/Cargo.toml @@ -1,21 +1,26 @@ [package] -name = "wiggle-runtime" +name = "wiggle-macro" version = "0.13.0" authors = ["Pat Hickey ", "Jakub Konka ", "Alex Crichton "] edition = "2018" license = "Apache-2.0 WITH LLVM-exception" -description = "Runtime components of wiggle code generator" +description = "Wiggle code generator" categories = ["wasm"] keywords = ["webassembly", "wasm"] repository = "https://github.com/bytecodealliance/wasmtime" +readme = "README.md" include = ["src/**/*", "LICENSE"] +[lib] +proc-macro = true + [dependencies] -thiserror = "1" -witx = { path = "../../../wasi-common/wig/WASI/tools/witx", version = "0.8.4", optional = true } +wiggle-generate = { path = "../generate", version = "0.13.0" } +witx = { path = "../../../wasi-common/wig/WASI/tools/witx", version = "0.8.4" } +syn = { version = "1.0", features = ["full"] } -[badges] -maintenance = { status = "actively-developed" } +[dev-dependencies] +wiggle = { path = "../.." } [features] -wiggle_metadata = ['witx'] +wiggle_metadata = [] diff --git a/crates/wiggle/crates/runtime/LICENSE b/crates/wiggle/crates/macro/LICENSE similarity index 100% rename from crates/wiggle/crates/runtime/LICENSE rename to crates/wiggle/crates/macro/LICENSE diff --git a/crates/wiggle/crates/macro/src/lib.rs b/crates/wiggle/crates/macro/src/lib.rs new file mode 100644 index 000000000000..dd983e1b4ef3 --- /dev/null +++ b/crates/wiggle/crates/macro/src/lib.rs @@ -0,0 +1,98 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use syn::parse_macro_input; + +/// This macro expands to a set of `pub` Rust modules: +/// +/// * The `types` module contains definitions for each `typename` declared in +/// the witx document. Type names are translated to the Rust-idiomatic +/// CamelCase. +/// +/// * For each `module` defined in the witx document, a Rust module is defined +/// containing definitions for that module. Module names are teanslated to the +/// Rust-idiomatic snake\_case. +/// +/// * For each `@interface func` defined in a witx module, an abi-level +/// function is generated which takes ABI-level arguments, along with a +/// "context" struct (whose type is given by the `ctx` field in the +/// macro invocation) and a `GuestMemory` implementation. +/// +/// * A public "module trait" is defined (called the module name, in +/// SnakeCase) which has a `&self` method for each function in the +/// module. These methods takes idiomatic Rust types for each argument +/// and return `Result<($return_types),$error_type>` +/// +/// Arguments are provided using Rust struct value syntax. +/// +/// * `witx` takes a list of string literal paths. Paths are relative to the +/// CARGO_MANIFEST_DIR of the crate where the macro is invoked. +/// * `ctx` takes a type name. This type must implement all of the module +/// traits +/// +/// ## Example +/// +/// ``` +/// use wiggle::{GuestPtr, GuestErrorType}; +/// +/// /// The test witx file `arrays.witx` lives in the test directory. For a +/// /// full-fledged example with runtime tests, see `tests/arrays.rs` and +/// /// the rest of the files in that directory. +/// wiggle::from_witx!({ +/// witx: ["../../tests/arrays.witx"], +/// ctx: YourCtxType, +/// }); +/// +/// /// The `ctx` type for this wiggle invocation. +/// pub struct YourCtxType {} +/// +/// /// `arrays.witx` contains one module called `arrays`. So, we must +/// /// implement this one method trait for our ctx type: +/// impl arrays::Arrays for YourCtxType { +/// /// The arrays module has two methods, shown here. +/// /// Note that the `GuestPtr` type comes from `wiggle`, +/// /// whereas the witx-defined types like `Excuse` and `Errno` come +/// /// from the `pub mod types` emitted by the `wiggle::from_witx!` +/// /// invocation above. +/// fn reduce_excuses(&self, _a: &GuestPtr<[GuestPtr]>) +/// -> Result { +/// unimplemented!() +/// } +/// fn populate_excuses(&self, _a: &GuestPtr<[GuestPtr]>) +/// -> Result<(), types::Errno> { +/// unimplemented!() +/// } +/// } +/// +/// /// For all types used in the `Error` position of a `Result` in the module +/// /// traits, you must implement `GuestErrorType` which tells wiggle-generated +/// /// code how to determine if a method call has been successful, as well as +/// /// how to translate a wiggle runtime error into an ABI-level error. +/// impl<'a> GuestErrorType<'a> for types::Errno { +/// type Context = YourCtxType; +/// fn success() -> Self { +/// unimplemented!() +/// } +/// fn from_error(_e: wiggle::GuestError, _c: &Self::Context) -> Self { +/// unimplemented!() +/// } +/// } +/// +/// # fn main() { println!("this fools doc tests into compiling the above outside a function body") +/// # } +/// ``` +#[proc_macro] +pub fn from_witx(args: TokenStream) -> TokenStream { + let mut config = parse_macro_input!(args as wiggle_generate::Config); + config.witx.make_paths_relative_to( + std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR env var"), + ); + + #[cfg(feature = "wiggle_metadata")] + { + config.emit_metadata = true; + } + + let doc = witx::load(&config.witx.paths).expect("loading witx"); + TokenStream::from(wiggle_generate::generate(&doc, &config)) +} diff --git a/crates/wiggle/crates/runtime/src/lib.rs b/crates/wiggle/crates/runtime/src/lib.rs deleted file mode 100644 index 92a913ffdaf4..000000000000 --- a/crates/wiggle/crates/runtime/src/lib.rs +++ /dev/null @@ -1,579 +0,0 @@ -use std::cell::Cell; -use std::fmt; -use std::marker; -use std::rc::Rc; -use std::slice; -use std::str; -use std::sync::Arc; - -#[cfg(feature = "wiggle_metadata")] -pub use witx; - -mod borrow; -mod error; -mod guest_type; -mod region; - -pub use borrow::GuestBorrows; -pub use error::GuestError; -pub use guest_type::{GuestErrorType, GuestType, GuestTypeTransparent}; -pub use region::Region; - -/// A trait which abstracts how to get at the region of host memory taht -/// contains guest memory. -/// -/// All `GuestPtr` types will contain a handle to this trait, signifying where -/// the pointer is actually pointing into. This type will need to be implemented -/// for the host's memory storage object. -/// -/// # Safety -/// -/// Safety around this type is tricky, and the trait is `unsafe` since there are -/// a few contracts you need to uphold to implement this type correctly and have -/// everything else in this crate work out safely. -/// -/// The most important method of this trait is the `base` method. This returns, -/// in host memory, a pointer and a length. The pointer should point to valid -/// memory for the guest to read/write for the length contiguous bytes -/// afterwards. -/// -/// The region returned by `base` must not only be valid, however, but it must -/// be valid for "a period of time before the guest is reentered". This isn't -/// exactly well defined but the general idea is that `GuestMemory` is allowed -/// to change under our feet to accomodate instructions like `memory.grow` or -/// other guest modifications. Memory, however, cannot be changed if the guest -/// is not reentered or if no explicitly action is taken to modify the guest -/// memory. -/// -/// This provides the guarantee that host pointers based on the return value of -/// `base` have a dynamic period for which they are valid. This time duration -/// must be "somehow nonzero in length" to allow users of `GuestMemory` and -/// `GuestPtr` to safely read and write interior data. -/// -/// # Using Raw Pointers -/// -/// Methods like [`GuestMemory::base`] or [`GuestPtr::as_raw`] will return raw -/// pointers to use. Returning raw pointers is significant because it shows -/// there are hazards with using the returned pointers, and they can't blanket -/// be used in a safe fashion. It is possible to use these pointers safely, but -/// any usage needs to uphold a few guarantees. -/// -/// * Whenever a `*mut T` is accessed or modified, it must be guaranteed that -/// since the pointer was originally obtained the guest memory wasn't -/// relocated in any way. This means you can't call back into the guest, call -/// other arbitrary functions which might call into the guest, etc. The -/// problem here is that the guest could execute instructions like -/// `memory.grow` which would invalidate the raw pointer. If, however, after -/// you acquire `*mut T` you only execute your own code and it doesn't touch -/// the guest, then `*mut T` is still guaranteed to point to valid code. -/// -/// * Furthermore, Rust's aliasing rules must still be upheld. For example you -/// can't have two `&mut T` types that point to the area or overlap in any -/// way. This in particular becomes an issue when you're dealing with multiple -/// `GuestPtr` types. If you want to simultaneously work with them then you -/// need to dynamically validate that you're either working with them all in a -/// shared fashion (e.g. as if they were `&T`) or you must verify that they do -/// not overlap to work with them as `&mut T`. -/// -/// Note that safely using the raw pointers is relatively difficult. This crate -/// strives to provide utilities to safely work with guest pointers so long as -/// the previous guarantees are all upheld. If advanced operations are done with -/// guest pointers it's recommended to be extremely cautious and thoroughly -/// consider possible ramifications with respect to this API before codifying -/// implementation details. -pub unsafe trait GuestMemory { - /// Returns the base allocation of this guest memory, located in host - /// memory. - /// - /// A pointer/length pair are returned to signify where the guest memory - /// lives in the host, and how many contiguous bytes the memory is valid for - /// after the returned pointer. - /// - /// Note that there are safety guarantees about this method that - /// implementations must uphold, and for more details see the - /// [`GuestMemory`] documentation. - fn base(&self) -> (*mut u8, u32); - - /// Validates a guest-relative pointer given various attributes, and returns - /// the corresponding host pointer. - /// - /// * `offset` - this is the guest-relative pointer, an offset from the - /// base. - /// * `align` - this is the desired alignment of the guest pointer, and if - /// successful the host pointer will be guaranteed to have this alignment. - /// * `len` - this is the number of bytes, after `offset`, that the returned - /// pointer must be valid for. - /// - /// This function will guarantee that the returned pointer is in-bounds of - /// `base`, *at this time*, for `len` bytes and has alignment `align`. If - /// any guarantees are not upheld then an error will be returned. - /// - /// Note that the returned pointer is an unsafe pointer. This is not safe to - /// use in general because guest memory can be relocated. Additionally the - /// guest may be modifying/reading memory as well. Consult the - /// [`GuestMemory`] documentation for safety information about using this - /// returned pointer. - fn validate_size_align( - &self, - offset: u32, - align: usize, - len: u32, - ) -> Result<*mut u8, GuestError> { - let (base_ptr, base_len) = self.base(); - let region = Region { start: offset, len }; - - // Figure out our pointer to the start of memory - let start = match (base_ptr as usize).checked_add(offset as usize) { - Some(ptr) => ptr, - None => return Err(GuestError::PtrOverflow), - }; - // and use that to figure out the end pointer - let end = match start.checked_add(len as usize) { - Some(ptr) => ptr, - None => return Err(GuestError::PtrOverflow), - }; - // and then verify that our end doesn't reach past the end of our memory - if end > (base_ptr as usize) + (base_len as usize) { - return Err(GuestError::PtrOutOfBounds(region)); - } - // and finally verify that the alignment is correct - if start % align != 0 { - return Err(GuestError::PtrNotAligned(region, align as u32)); - } - Ok(start as *mut u8) - } - - /// Convenience method for creating a `GuestPtr` at a particular offset. - /// - /// Note that `T` can be almost any type, and typically `offset` is a `u32`. - /// The exception is slices and strings, in which case `offset` is a `(u32, - /// u32)` of `(offset, length)`. - fn ptr<'a, T>(&'a self, offset: T::Pointer) -> GuestPtr<'a, T> - where - Self: Sized, - T: ?Sized + Pointee, - { - GuestPtr::new(self, offset) - } -} - -// Forwarding trait implementations to the original type - -unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a T { - fn base(&self) -> (*mut u8, u32) { - T::base(self) - } -} - -unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a mut T { - fn base(&self) -> (*mut u8, u32) { - T::base(self) - } -} - -unsafe impl GuestMemory for Box { - fn base(&self) -> (*mut u8, u32) { - T::base(self) - } -} - -unsafe impl GuestMemory for Rc { - fn base(&self) -> (*mut u8, u32) { - T::base(self) - } -} - -unsafe impl GuestMemory for Arc { - fn base(&self) -> (*mut u8, u32) { - T::base(self) - } -} - -/// A *guest* pointer into host memory. -/// -/// This type represents a pointer from the guest that points into host memory. -/// Internally a `GuestPtr` contains a handle to its original [`GuestMemory`] as -/// well as the offset into the memory that the pointer is pointing at. -/// -/// Presence of a [`GuestPtr`] does not imply any form of validity. Pointers can -/// be out-of-bounds, misaligned, etc. It is safe to construct a `GuestPtr` with -/// any offset at any time. Consider a `GuestPtr` roughly equivalent to `*mut -/// T`, although there are a few more safety guarantees around this type. -/// -/// ## Slices and Strings -/// -/// Note that the type parameter does not need to implement the `Sized` trait, -/// so you can implement types such as this: -/// -/// * `GuestPtr<'_, str>` - a pointer to a guest string -/// * `GuestPtr<'_, [T]>` - a pointer to a guest array -/// -/// Unsized types such as this may have extra methods and won't have methods -/// like [`GuestPtr::read`] or [`GuestPtr::write`]. -/// -/// ## Type parameter and pointee -/// -/// The `T` type parameter is largely intended for more static safety in Rust as -/// well as having a better handle on what we're pointing to. A `GuestPtr`, -/// however, does not necessarily literally imply a guest pointer pointing to -/// type `T`. Instead the [`GuestType`] trait is a layer of abstraction where -/// `GuestPtr` may actually be a pointer to `U` in guest memory, but you can -/// construct a `T` from a `U`. -/// -/// For example `GuestPtr>` is a valid type, but this is actually -/// more equivalent to `GuestPtr` because guest pointers are always -/// 32-bits. That being said you can create a `GuestPtr` from a `u32`. -/// -/// Additionally `GuestPtr` will actually delegate, typically, to and -/// implementation which loads the underlying data as `GuestPtr` (or -/// similar) and then the bytes loaded are validated to fit within the -/// definition of `MyEnum` before `MyEnum` is returned. -/// -/// For more information see the [`GuestPtr::read`] and [`GuestPtr::write`] -/// methods. In general though be extremely careful about writing `unsafe` code -/// when working with a `GuestPtr` if you're not using one of the -/// already-attached helper methods. -pub struct GuestPtr<'a, T: ?Sized + Pointee> { - mem: &'a (dyn GuestMemory + 'a), - pointer: T::Pointer, - _marker: marker::PhantomData<&'a Cell>, -} - -impl<'a, T: ?Sized + Pointee> GuestPtr<'a, T> { - /// Creates a new `GuestPtr` from the given `mem` and `pointer` values. - /// - /// Note that for sized types like `u32`, `GuestPtr`, etc, the `pointer` - /// vlue is a `u32` offset into guest memory. For slices and strings, - /// `pointer` is a `(u32, u32)` offset/length pair. - pub fn new(mem: &'a (dyn GuestMemory + 'a), pointer: T::Pointer) -> GuestPtr<'_, T> { - GuestPtr { - mem, - pointer, - _marker: marker::PhantomData, - } - } - - /// Returns the offset of this pointer in guest memory. - /// - /// Note that for sized types this returns a `u32`, but for slices and - /// strings it returns a `(u32, u32)` pointer/length pair. - pub fn offset(&self) -> T::Pointer { - self.pointer - } - - /// Returns the guest memory that this pointer is coming from. - pub fn mem(&self) -> &'a (dyn GuestMemory + 'a) { - self.mem - } - - /// Casts this `GuestPtr` type to a different type. - /// - /// This is a safe method which is useful for simply reinterpreting the type - /// parameter on this `GuestPtr`. Note that this is a safe method, where - /// again there's no guarantees about alignment, validity, in-bounds-ness, - /// etc of the returned pointer. - pub fn cast(&self) -> GuestPtr<'a, U> - where - T: Pointee, - { - GuestPtr::new(self.mem, self.pointer) - } - - /// Safely read a value from this pointer. - /// - /// This is a fun method, and is one of the lynchpins of this - /// implementation. The highlight here is that this is a *safe* operation, - /// not an unsafe one like `*mut T`. This works for a few reasons: - /// - /// * The `unsafe` contract of the `GuestMemory` trait means that there's - /// always at least some backing memory for this `GuestPtr`. - /// - /// * This does not use Rust-intrinsics to read the type `T`, but rather it - /// delegates to `T`'s implementation of [`GuestType`] to actually read - /// the underlying data. This again is a safe method, so any unsafety, if - /// any, must be internally documented. - /// - /// * Eventually what typically happens it that this bottoms out in the read - /// implementations for primitives types (like `i32`) which can safely be - /// read at any time, and then it's up to the runtime to determine what to - /// do with the bytes it read in a safe manner. - /// - /// Naturally lots of things can still go wrong, such as out-of-bounds - /// checks, alignment checks, validity checks (e.g. for enums), etc. All of - /// these check failures, however, are returned as a [`GuestError`] in the - /// `Result` here, and `Ok` is only returned if all the checks passed. - pub fn read(&self) -> Result - where - T: GuestType<'a>, - { - T::read(self) - } - - /// Safely write a value to this pointer. - /// - /// This method, like [`GuestPtr::read`], is pretty crucial for the safe - /// operation of this crate. All the same reasons apply though for why this - /// method is safe, even eventually bottoming out in primitives like writing - /// an `i32` which is safe to write bit patterns into memory at any time due - /// to the guarantees of [`GuestMemory`]. - /// - /// Like `read`, `write` can fail due to any manner of pointer checks, but - /// any failure is returned as a [`GuestError`]. - pub fn write(&self, val: T) -> Result<(), GuestError> - where - T: GuestType<'a>, - { - T::write(self, val) - } - - /// Performs pointer arithmetic on this pointer, moving the pointer forward - /// `amt` slots. - /// - /// This will either return the resulting pointer or `Err` if the pointer - /// arithmetic calculation would overflow around the end of the address - /// space. - pub fn add(&self, amt: u32) -> Result, GuestError> - where - T: GuestType<'a> + Pointee, - { - let offset = amt - .checked_mul(T::guest_size()) - .and_then(|o| self.pointer.checked_add(o)); - let offset = match offset { - Some(o) => o, - None => return Err(GuestError::PtrOverflow), - }; - Ok(GuestPtr::new(self.mem, offset)) - } - - /// Returns a `GuestPtr` for an array of `T`s using this pointer as the - /// base. - pub fn as_array(&self, elems: u32) -> GuestPtr<'a, [T]> - where - T: GuestType<'a> + Pointee, - { - GuestPtr::new(self.mem, (self.pointer, elems)) - } -} - -impl<'a, T> GuestPtr<'a, [T]> { - /// For slices, specifically returns the relative pointer to the base of the - /// array. - /// - /// This is similar to `<[T]>::as_ptr()` - pub fn offset_base(&self) -> u32 { - self.pointer.0 - } - - /// For slices, returns the length of the slice, in units. - pub fn len(&self) -> u32 { - self.pointer.1 - } - - /// Returns an iterator over interior pointers. - /// - /// Each item is a `Result` indicating whether it overflowed past the end of - /// the address space or not. - pub fn iter<'b>( - &'b self, - ) -> impl ExactSizeIterator, GuestError>> + 'b - where - T: GuestType<'a>, - { - let base = self.as_ptr(); - (0..self.len()).map(move |i| base.add(i)) - } - - /// Attempts to read a raw `*mut [T]` pointer from this pointer, performing - /// bounds checks and type validation. - /// The resulting `*mut [T]` can be used as a `&mut [t]` as long as the - /// reference is dropped before any Wasm code is re-entered. - /// - /// This function will return a raw pointer into host memory if all checks - /// succeed (valid utf-8, valid pointers, etc). If any checks fail then - /// `GuestError` will be returned. - /// - /// Note that the `*mut [T]` pointer is still unsafe to use in general, but - /// there are specific situations that it is safe to use. For more - /// information about using the raw pointer, consult the [`GuestMemory`] - /// trait documentation. - /// - /// For safety against overlapping mutable borrows, the user must use the - /// same `GuestBorrows` to create all *mut str or *mut [T] that are alive - /// at the same time. - pub fn as_raw(&self, bc: &mut GuestBorrows) -> Result<*mut [T], GuestError> - where - T: GuestTypeTransparent<'a>, - { - let len = match self.pointer.1.checked_mul(T::guest_size()) { - Some(l) => l, - None => return Err(GuestError::PtrOverflow), - }; - let ptr = - self.mem - .validate_size_align(self.pointer.0, T::guest_align(), len)? as *mut T; - - bc.borrow(Region { - start: self.pointer.0, - len, - })?; - - // Validate all elements in slice. - // SAFETY: ptr has been validated by self.mem.validate_size_align - for offs in 0..self.pointer.1 { - T::validate(unsafe { ptr.add(offs as usize) })?; - } - - // SAFETY: iff there are no overlapping borrows (all uses of as_raw use this same - // GuestBorrows), its valid to construct a *mut [T] - unsafe { - let s = slice::from_raw_parts_mut(ptr, self.pointer.1 as usize); - Ok(s as *mut [T]) - } - } - - /// Copies the data pointed to by `slice` into this guest region. - /// - /// This method is a *safe* method to copy data from the host to the guest. - /// This requires that `self` and `slice` have the same length. The pointee - /// type `T` requires the [`GuestTypeTransparent`] trait which is an - /// assertion that the representation on the host and on the guest is the - /// same. - /// - /// # Errors - /// - /// Returns an error if this guest pointer is out of bounds or if the length - /// of this guest pointer is not equal to the length of the slice provided. - pub fn copy_from_slice(&self, slice: &[T]) -> Result<(), GuestError> - where - T: GuestTypeTransparent<'a> + Copy, - { - // bounds check ... - let raw = self.as_raw(&mut GuestBorrows::new())?; - unsafe { - // ... length check ... - if (*raw).len() != slice.len() { - return Err(GuestError::SliceLengthsDiffer); - } - // ... and copy! - (*raw).copy_from_slice(slice); - Ok(()) - } - } - - /// Returns a `GuestPtr` pointing to the base of the array for the interior - /// type `T`. - pub fn as_ptr(&self) -> GuestPtr<'a, T> { - GuestPtr::new(self.mem, self.offset_base()) - } -} - -impl<'a> GuestPtr<'a, str> { - /// For strings, returns the relative pointer to the base of the string - /// allocation. - pub fn offset_base(&self) -> u32 { - self.pointer.0 - } - - /// Returns the length, in bytes, of th estring. - pub fn len(&self) -> u32 { - self.pointer.1 - } - - /// Returns a raw pointer for the underlying slice of bytes that this - /// pointer points to. - pub fn as_bytes(&self) -> GuestPtr<'a, [u8]> { - GuestPtr::new(self.mem, self.pointer) - } - - /// Attempts to read a raw `*mut str` pointer from this pointer, performing - /// bounds checks and utf-8 checks. - /// The resulting `*mut str` can be used as a `&mut str` as long as the - /// reference is dropped before any Wasm code is re-entered. - /// - /// This function will return a raw pointer into host memory if all checks - /// succeed (valid utf-8, valid pointers, etc). If any checks fail then - /// `GuestError` will be returned. - /// - /// Note that the `*mut str` pointer is still unsafe to use in general, but - /// there are specific situations that it is safe to use. For more - /// information about using the raw pointer, consult the [`GuestMemory`] - /// trait documentation. - /// - /// For safety against overlapping mutable borrows, the user must use the - /// same `GuestBorrows` to create all *mut str or *mut [T] that are alive - /// at the same time. - pub fn as_raw(&self, bc: &mut GuestBorrows) -> Result<*mut str, GuestError> { - let ptr = self - .mem - .validate_size_align(self.pointer.0, 1, self.pointer.1)?; - - bc.borrow(Region { - start: self.pointer.0, - len: self.pointer.1, - })?; - - // SAFETY: iff there are no overlapping borrows (all uses of as_raw use this same - // GuestBorrows), its valid to construct a *mut str - unsafe { - let s = slice::from_raw_parts_mut(ptr, self.pointer.1 as usize); - match str::from_utf8_mut(s) { - Ok(s) => Ok(s), - Err(e) => Err(GuestError::InvalidUtf8(e)), - } - } - } -} - -impl Clone for GuestPtr<'_, T> { - fn clone(&self) -> Self { - *self - } -} - -impl Copy for GuestPtr<'_, T> {} - -impl fmt::Debug for GuestPtr<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - T::debug(self.pointer, f) - } -} - -mod private { - pub trait Sealed {} - impl Sealed for T {} - impl Sealed for [T] {} - impl Sealed for str {} -} - -/// Types that can be pointed to by `GuestPtr`. -/// -/// In essence everything can, and the only special-case is unsized types like -/// `str` and `[T]` which have special implementations. -pub trait Pointee: private::Sealed { - #[doc(hidden)] - type Pointer: Copy; - #[doc(hidden)] - fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result; -} - -impl Pointee for T { - type Pointer = u32; - fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "*guest {:#x}", pointer) - } -} - -impl Pointee for [T] { - type Pointer = (u32, u32); - fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "*guest {:#x}/{}", pointer.0, pointer.1) - } -} - -impl Pointee for str { - type Pointer = (u32, u32); - fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result { - <[u8]>::debug(pointer, f) - } -} diff --git a/crates/wiggle/crates/test/Cargo.toml b/crates/wiggle/crates/test/Cargo.toml index 3e960ed843d8..6ebe4cc6a188 100644 --- a/crates/wiggle/crates/test/Cargo.toml +++ b/crates/wiggle/crates/test/Cargo.toml @@ -11,8 +11,8 @@ repository = "https://github.com/bytecodealliance/wasmtime" include = ["src/**/*", "LICENSE"] [dependencies] -wiggle-runtime = { path = "../runtime", version = "0.13.0" } proptest = "0.9" +wiggle = { path = "../..", version = "0.13.0" } [badges] maintenance = { status = "actively-developed" } diff --git a/crates/wiggle/crates/test/src/lib.rs b/crates/wiggle/crates/test/src/lib.rs index 8ec8f916dd5c..27766dbff9d5 100644 --- a/crates/wiggle/crates/test/src/lib.rs +++ b/crates/wiggle/crates/test/src/lib.rs @@ -1,7 +1,7 @@ use proptest::prelude::*; use std::cell::UnsafeCell; use std::marker; -use wiggle_runtime::GuestMemory; +use wiggle::GuestMemory; #[derive(Debug, Clone)] pub struct MemAreas(Vec); @@ -289,7 +289,7 @@ mod test { } use std::cell::RefCell; -use wiggle_runtime::GuestError; +use wiggle::GuestError; // In lucet, our Ctx struct needs a lifetime, so we're using one // on the test as well. @@ -314,7 +314,7 @@ impl<'a> WasiCtx<'a> { #[macro_export] macro_rules! impl_errno { ( $errno:ty ) => { - impl<'a> wiggle_runtime::GuestErrorType<'a> for $errno { + impl<'a> wiggle::GuestErrorType<'a> for $errno { type Context = WasiCtx<'a>; fn success() -> $errno { <$errno>::Ok diff --git a/crates/wiggle/crates/runtime/src/borrow.rs b/crates/wiggle/src/borrow.rs similarity index 100% rename from crates/wiggle/crates/runtime/src/borrow.rs rename to crates/wiggle/src/borrow.rs diff --git a/crates/wiggle/crates/runtime/src/error.rs b/crates/wiggle/src/error.rs similarity index 100% rename from crates/wiggle/crates/runtime/src/error.rs rename to crates/wiggle/src/error.rs diff --git a/crates/wiggle/crates/runtime/src/guest_type.rs b/crates/wiggle/src/guest_type.rs similarity index 100% rename from crates/wiggle/crates/runtime/src/guest_type.rs rename to crates/wiggle/src/guest_type.rs diff --git a/crates/wiggle/src/lib.rs b/crates/wiggle/src/lib.rs index 16a149eb7df0..d91c60128cca 100644 --- a/crates/wiggle/src/lib.rs +++ b/crates/wiggle/src/lib.rs @@ -1,98 +1,581 @@ -extern crate proc_macro; - -use proc_macro::TokenStream; -use syn::parse_macro_input; - -/// This macro expands to a set of `pub` Rust modules: -/// -/// * The `types` module contains definitions for each `typename` declared in -/// the witx document. Type names are translated to the Rust-idiomatic -/// CamelCase. -/// -/// * For each `module` defined in the witx document, a Rust module is defined -/// containing definitions for that module. Module names are teanslated to the -/// Rust-idiomatic snake\_case. -/// -/// * For each `@interface func` defined in a witx module, an abi-level -/// function is generated which takes ABI-level arguments, along with a -/// "context" struct (whose type is given by the `ctx` field in the -/// macro invocation) and a `GuestMemory` implementation. -/// -/// * A public "module trait" is defined (called the module name, in -/// SnakeCase) which has a `&self` method for each function in the -/// module. These methods takes idiomatic Rust types for each argument -/// and return `Result<($return_types),$error_type>` -/// -/// Arguments are provided using Rust struct value syntax. -/// -/// * `witx` takes a list of string literal paths. Paths are relative to the -/// CARGO_MANIFEST_DIR of the crate where the macro is invoked. -/// * `ctx` takes a type name. This type must implement all of the module -/// traits -/// -/// ## Example -/// -/// ``` -/// use wiggle_runtime::{GuestPtr, GuestErrorType}; -/// -/// /// The test witx file `arrays.witx` lives in the test directory. For a -/// /// full-fledged example with runtime tests, see `tests/arrays.rs` and -/// /// the rest of the files in that directory. -/// wiggle::from_witx!({ -/// witx: ["tests/arrays.witx"], -/// ctx: YourCtxType, -/// }); -/// -/// /// The `ctx` type for this wiggle invocation. -/// pub struct YourCtxType {} -/// -/// /// `arrays.witx` contains one module called `arrays`. So, we must -/// /// implement this one method trait for our ctx type: -/// impl arrays::Arrays for YourCtxType { -/// /// The arrays module has two methods, shown here. -/// /// Note that the `GuestPtr` type comes from `wiggle_runtime`, -/// /// whereas the witx-defined types like `Excuse` and `Errno` come -/// /// from the `pub mod types` emitted by the `wiggle::from_witx!` -/// /// invocation above. -/// fn reduce_excuses(&self, _a: &GuestPtr<[GuestPtr]>) -/// -> Result { -/// unimplemented!() -/// } -/// fn populate_excuses(&self, _a: &GuestPtr<[GuestPtr]>) -/// -> Result<(), types::Errno> { -/// unimplemented!() -/// } -/// } -/// -/// /// For all types used in the `Error` position of a `Result` in the module -/// /// traits, you must implement `GuestErrorType` which tells wiggle-generated -/// /// code how to determine if a method call has been successful, as well as -/// /// how to translate a wiggle runtime error into an ABI-level error. -/// impl<'a> GuestErrorType<'a> for types::Errno { -/// type Context = YourCtxType; -/// fn success() -> Self { -/// unimplemented!() -/// } -/// fn from_error(_e: wiggle_runtime::GuestError, _c: &Self::Context) -> Self { -/// unimplemented!() -/// } -/// } -/// -/// # fn main() { println!("this fools doc tests into compiling the above outside a function body") -/// # } -/// ``` -#[proc_macro] -pub fn from_witx(args: TokenStream) -> TokenStream { - let mut config = parse_macro_input!(args as wiggle_generate::Config); - config.witx.make_paths_relative_to( - std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR env var"), - ); - - #[cfg(feature = "wiggle_metadata")] +use std::cell::Cell; +use std::fmt; +use std::marker; +use std::rc::Rc; +use std::slice; +use std::str; +use std::sync::Arc; + +pub use wiggle_macro::from_witx; + +#[cfg(feature = "wiggle_metadata")] +pub use witx; + +mod borrow; +mod error; +mod guest_type; +mod region; + +pub use borrow::GuestBorrows; +pub use error::GuestError; +pub use guest_type::{GuestErrorType, GuestType, GuestTypeTransparent}; +pub use region::Region; + +/// A trait which abstracts how to get at the region of host memory taht +/// contains guest memory. +/// +/// All `GuestPtr` types will contain a handle to this trait, signifying where +/// the pointer is actually pointing into. This type will need to be implemented +/// for the host's memory storage object. +/// +/// # Safety +/// +/// Safety around this type is tricky, and the trait is `unsafe` since there are +/// a few contracts you need to uphold to implement this type correctly and have +/// everything else in this crate work out safely. +/// +/// The most important method of this trait is the `base` method. This returns, +/// in host memory, a pointer and a length. The pointer should point to valid +/// memory for the guest to read/write for the length contiguous bytes +/// afterwards. +/// +/// The region returned by `base` must not only be valid, however, but it must +/// be valid for "a period of time before the guest is reentered". This isn't +/// exactly well defined but the general idea is that `GuestMemory` is allowed +/// to change under our feet to accomodate instructions like `memory.grow` or +/// other guest modifications. Memory, however, cannot be changed if the guest +/// is not reentered or if no explicitly action is taken to modify the guest +/// memory. +/// +/// This provides the guarantee that host pointers based on the return value of +/// `base` have a dynamic period for which they are valid. This time duration +/// must be "somehow nonzero in length" to allow users of `GuestMemory` and +/// `GuestPtr` to safely read and write interior data. +/// +/// # Using Raw Pointers +/// +/// Methods like [`GuestMemory::base`] or [`GuestPtr::as_raw`] will return raw +/// pointers to use. Returning raw pointers is significant because it shows +/// there are hazards with using the returned pointers, and they can't blanket +/// be used in a safe fashion. It is possible to use these pointers safely, but +/// any usage needs to uphold a few guarantees. +/// +/// * Whenever a `*mut T` is accessed or modified, it must be guaranteed that +/// since the pointer was originally obtained the guest memory wasn't +/// relocated in any way. This means you can't call back into the guest, call +/// other arbitrary functions which might call into the guest, etc. The +/// problem here is that the guest could execute instructions like +/// `memory.grow` which would invalidate the raw pointer. If, however, after +/// you acquire `*mut T` you only execute your own code and it doesn't touch +/// the guest, then `*mut T` is still guaranteed to point to valid code. +/// +/// * Furthermore, Rust's aliasing rules must still be upheld. For example you +/// can't have two `&mut T` types that point to the area or overlap in any +/// way. This in particular becomes an issue when you're dealing with multiple +/// `GuestPtr` types. If you want to simultaneously work with them then you +/// need to dynamically validate that you're either working with them all in a +/// shared fashion (e.g. as if they were `&T`) or you must verify that they do +/// not overlap to work with them as `&mut T`. +/// +/// Note that safely using the raw pointers is relatively difficult. This crate +/// strives to provide utilities to safely work with guest pointers so long as +/// the previous guarantees are all upheld. If advanced operations are done with +/// guest pointers it's recommended to be extremely cautious and thoroughly +/// consider possible ramifications with respect to this API before codifying +/// implementation details. +pub unsafe trait GuestMemory { + /// Returns the base allocation of this guest memory, located in host + /// memory. + /// + /// A pointer/length pair are returned to signify where the guest memory + /// lives in the host, and how many contiguous bytes the memory is valid for + /// after the returned pointer. + /// + /// Note that there are safety guarantees about this method that + /// implementations must uphold, and for more details see the + /// [`GuestMemory`] documentation. + fn base(&self) -> (*mut u8, u32); + + /// Validates a guest-relative pointer given various attributes, and returns + /// the corresponding host pointer. + /// + /// * `offset` - this is the guest-relative pointer, an offset from the + /// base. + /// * `align` - this is the desired alignment of the guest pointer, and if + /// successful the host pointer will be guaranteed to have this alignment. + /// * `len` - this is the number of bytes, after `offset`, that the returned + /// pointer must be valid for. + /// + /// This function will guarantee that the returned pointer is in-bounds of + /// `base`, *at this time*, for `len` bytes and has alignment `align`. If + /// any guarantees are not upheld then an error will be returned. + /// + /// Note that the returned pointer is an unsafe pointer. This is not safe to + /// use in general because guest memory can be relocated. Additionally the + /// guest may be modifying/reading memory as well. Consult the + /// [`GuestMemory`] documentation for safety information about using this + /// returned pointer. + fn validate_size_align( + &self, + offset: u32, + align: usize, + len: u32, + ) -> Result<*mut u8, GuestError> { + let (base_ptr, base_len) = self.base(); + let region = Region { start: offset, len }; + + // Figure out our pointer to the start of memory + let start = match (base_ptr as usize).checked_add(offset as usize) { + Some(ptr) => ptr, + None => return Err(GuestError::PtrOverflow), + }; + // and use that to figure out the end pointer + let end = match start.checked_add(len as usize) { + Some(ptr) => ptr, + None => return Err(GuestError::PtrOverflow), + }; + // and then verify that our end doesn't reach past the end of our memory + if end > (base_ptr as usize) + (base_len as usize) { + return Err(GuestError::PtrOutOfBounds(region)); + } + // and finally verify that the alignment is correct + if start % align != 0 { + return Err(GuestError::PtrNotAligned(region, align as u32)); + } + Ok(start as *mut u8) + } + + /// Convenience method for creating a `GuestPtr` at a particular offset. + /// + /// Note that `T` can be almost any type, and typically `offset` is a `u32`. + /// The exception is slices and strings, in which case `offset` is a `(u32, + /// u32)` of `(offset, length)`. + fn ptr<'a, T>(&'a self, offset: T::Pointer) -> GuestPtr<'a, T> + where + Self: Sized, + T: ?Sized + Pointee, { - config.emit_metadata = true; + GuestPtr::new(self, offset) + } +} + +// Forwarding trait implementations to the original type + +unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a T { + fn base(&self) -> (*mut u8, u32) { + T::base(self) } +} + +unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a mut T { + fn base(&self) -> (*mut u8, u32) { + T::base(self) + } +} + +unsafe impl GuestMemory for Box { + fn base(&self) -> (*mut u8, u32) { + T::base(self) + } +} - let doc = witx::load(&config.witx.paths).expect("loading witx"); - TokenStream::from(wiggle_generate::generate(&doc, &config)) +unsafe impl GuestMemory for Rc { + fn base(&self) -> (*mut u8, u32) { + T::base(self) + } +} + +unsafe impl GuestMemory for Arc { + fn base(&self) -> (*mut u8, u32) { + T::base(self) + } +} + +/// A *guest* pointer into host memory. +/// +/// This type represents a pointer from the guest that points into host memory. +/// Internally a `GuestPtr` contains a handle to its original [`GuestMemory`] as +/// well as the offset into the memory that the pointer is pointing at. +/// +/// Presence of a [`GuestPtr`] does not imply any form of validity. Pointers can +/// be out-of-bounds, misaligned, etc. It is safe to construct a `GuestPtr` with +/// any offset at any time. Consider a `GuestPtr` roughly equivalent to `*mut +/// T`, although there are a few more safety guarantees around this type. +/// +/// ## Slices and Strings +/// +/// Note that the type parameter does not need to implement the `Sized` trait, +/// so you can implement types such as this: +/// +/// * `GuestPtr<'_, str>` - a pointer to a guest string +/// * `GuestPtr<'_, [T]>` - a pointer to a guest array +/// +/// Unsized types such as this may have extra methods and won't have methods +/// like [`GuestPtr::read`] or [`GuestPtr::write`]. +/// +/// ## Type parameter and pointee +/// +/// The `T` type parameter is largely intended for more static safety in Rust as +/// well as having a better handle on what we're pointing to. A `GuestPtr`, +/// however, does not necessarily literally imply a guest pointer pointing to +/// type `T`. Instead the [`GuestType`] trait is a layer of abstraction where +/// `GuestPtr` may actually be a pointer to `U` in guest memory, but you can +/// construct a `T` from a `U`. +/// +/// For example `GuestPtr>` is a valid type, but this is actually +/// more equivalent to `GuestPtr` because guest pointers are always +/// 32-bits. That being said you can create a `GuestPtr` from a `u32`. +/// +/// Additionally `GuestPtr` will actually delegate, typically, to and +/// implementation which loads the underlying data as `GuestPtr` (or +/// similar) and then the bytes loaded are validated to fit within the +/// definition of `MyEnum` before `MyEnum` is returned. +/// +/// For more information see the [`GuestPtr::read`] and [`GuestPtr::write`] +/// methods. In general though be extremely careful about writing `unsafe` code +/// when working with a `GuestPtr` if you're not using one of the +/// already-attached helper methods. +pub struct GuestPtr<'a, T: ?Sized + Pointee> { + mem: &'a (dyn GuestMemory + 'a), + pointer: T::Pointer, + _marker: marker::PhantomData<&'a Cell>, +} + +impl<'a, T: ?Sized + Pointee> GuestPtr<'a, T> { + /// Creates a new `GuestPtr` from the given `mem` and `pointer` values. + /// + /// Note that for sized types like `u32`, `GuestPtr`, etc, the `pointer` + /// vlue is a `u32` offset into guest memory. For slices and strings, + /// `pointer` is a `(u32, u32)` offset/length pair. + pub fn new(mem: &'a (dyn GuestMemory + 'a), pointer: T::Pointer) -> GuestPtr<'_, T> { + GuestPtr { + mem, + pointer, + _marker: marker::PhantomData, + } + } + + /// Returns the offset of this pointer in guest memory. + /// + /// Note that for sized types this returns a `u32`, but for slices and + /// strings it returns a `(u32, u32)` pointer/length pair. + pub fn offset(&self) -> T::Pointer { + self.pointer + } + + /// Returns the guest memory that this pointer is coming from. + pub fn mem(&self) -> &'a (dyn GuestMemory + 'a) { + self.mem + } + + /// Casts this `GuestPtr` type to a different type. + /// + /// This is a safe method which is useful for simply reinterpreting the type + /// parameter on this `GuestPtr`. Note that this is a safe method, where + /// again there's no guarantees about alignment, validity, in-bounds-ness, + /// etc of the returned pointer. + pub fn cast(&self) -> GuestPtr<'a, U> + where + T: Pointee, + { + GuestPtr::new(self.mem, self.pointer) + } + + /// Safely read a value from this pointer. + /// + /// This is a fun method, and is one of the lynchpins of this + /// implementation. The highlight here is that this is a *safe* operation, + /// not an unsafe one like `*mut T`. This works for a few reasons: + /// + /// * The `unsafe` contract of the `GuestMemory` trait means that there's + /// always at least some backing memory for this `GuestPtr`. + /// + /// * This does not use Rust-intrinsics to read the type `T`, but rather it + /// delegates to `T`'s implementation of [`GuestType`] to actually read + /// the underlying data. This again is a safe method, so any unsafety, if + /// any, must be internally documented. + /// + /// * Eventually what typically happens it that this bottoms out in the read + /// implementations for primitives types (like `i32`) which can safely be + /// read at any time, and then it's up to the runtime to determine what to + /// do with the bytes it read in a safe manner. + /// + /// Naturally lots of things can still go wrong, such as out-of-bounds + /// checks, alignment checks, validity checks (e.g. for enums), etc. All of + /// these check failures, however, are returned as a [`GuestError`] in the + /// `Result` here, and `Ok` is only returned if all the checks passed. + pub fn read(&self) -> Result + where + T: GuestType<'a>, + { + T::read(self) + } + + /// Safely write a value to this pointer. + /// + /// This method, like [`GuestPtr::read`], is pretty crucial for the safe + /// operation of this crate. All the same reasons apply though for why this + /// method is safe, even eventually bottoming out in primitives like writing + /// an `i32` which is safe to write bit patterns into memory at any time due + /// to the guarantees of [`GuestMemory`]. + /// + /// Like `read`, `write` can fail due to any manner of pointer checks, but + /// any failure is returned as a [`GuestError`]. + pub fn write(&self, val: T) -> Result<(), GuestError> + where + T: GuestType<'a>, + { + T::write(self, val) + } + + /// Performs pointer arithmetic on this pointer, moving the pointer forward + /// `amt` slots. + /// + /// This will either return the resulting pointer or `Err` if the pointer + /// arithmetic calculation would overflow around the end of the address + /// space. + pub fn add(&self, amt: u32) -> Result, GuestError> + where + T: GuestType<'a> + Pointee, + { + let offset = amt + .checked_mul(T::guest_size()) + .and_then(|o| self.pointer.checked_add(o)); + let offset = match offset { + Some(o) => o, + None => return Err(GuestError::PtrOverflow), + }; + Ok(GuestPtr::new(self.mem, offset)) + } + + /// Returns a `GuestPtr` for an array of `T`s using this pointer as the + /// base. + pub fn as_array(&self, elems: u32) -> GuestPtr<'a, [T]> + where + T: GuestType<'a> + Pointee, + { + GuestPtr::new(self.mem, (self.pointer, elems)) + } +} + +impl<'a, T> GuestPtr<'a, [T]> { + /// For slices, specifically returns the relative pointer to the base of the + /// array. + /// + /// This is similar to `<[T]>::as_ptr()` + pub fn offset_base(&self) -> u32 { + self.pointer.0 + } + + /// For slices, returns the length of the slice, in units. + pub fn len(&self) -> u32 { + self.pointer.1 + } + + /// Returns an iterator over interior pointers. + /// + /// Each item is a `Result` indicating whether it overflowed past the end of + /// the address space or not. + pub fn iter<'b>( + &'b self, + ) -> impl ExactSizeIterator, GuestError>> + 'b + where + T: GuestType<'a>, + { + let base = self.as_ptr(); + (0..self.len()).map(move |i| base.add(i)) + } + + /// Attempts to read a raw `*mut [T]` pointer from this pointer, performing + /// bounds checks and type validation. + /// The resulting `*mut [T]` can be used as a `&mut [t]` as long as the + /// reference is dropped before any Wasm code is re-entered. + /// + /// This function will return a raw pointer into host memory if all checks + /// succeed (valid utf-8, valid pointers, etc). If any checks fail then + /// `GuestError` will be returned. + /// + /// Note that the `*mut [T]` pointer is still unsafe to use in general, but + /// there are specific situations that it is safe to use. For more + /// information about using the raw pointer, consult the [`GuestMemory`] + /// trait documentation. + /// + /// For safety against overlapping mutable borrows, the user must use the + /// same `GuestBorrows` to create all *mut str or *mut [T] that are alive + /// at the same time. + pub fn as_raw(&self, bc: &mut GuestBorrows) -> Result<*mut [T], GuestError> + where + T: GuestTypeTransparent<'a>, + { + let len = match self.pointer.1.checked_mul(T::guest_size()) { + Some(l) => l, + None => return Err(GuestError::PtrOverflow), + }; + let ptr = + self.mem + .validate_size_align(self.pointer.0, T::guest_align(), len)? as *mut T; + + bc.borrow(Region { + start: self.pointer.0, + len, + })?; + + // Validate all elements in slice. + // SAFETY: ptr has been validated by self.mem.validate_size_align + for offs in 0..self.pointer.1 { + T::validate(unsafe { ptr.add(offs as usize) })?; + } + + // SAFETY: iff there are no overlapping borrows (all uses of as_raw use this same + // GuestBorrows), its valid to construct a *mut [T] + unsafe { + let s = slice::from_raw_parts_mut(ptr, self.pointer.1 as usize); + Ok(s as *mut [T]) + } + } + + /// Copies the data pointed to by `slice` into this guest region. + /// + /// This method is a *safe* method to copy data from the host to the guest. + /// This requires that `self` and `slice` have the same length. The pointee + /// type `T` requires the [`GuestTypeTransparent`] trait which is an + /// assertion that the representation on the host and on the guest is the + /// same. + /// + /// # Errors + /// + /// Returns an error if this guest pointer is out of bounds or if the length + /// of this guest pointer is not equal to the length of the slice provided. + pub fn copy_from_slice(&self, slice: &[T]) -> Result<(), GuestError> + where + T: GuestTypeTransparent<'a> + Copy, + { + // bounds check ... + let raw = self.as_raw(&mut GuestBorrows::new())?; + unsafe { + // ... length check ... + if (*raw).len() != slice.len() { + return Err(GuestError::SliceLengthsDiffer); + } + // ... and copy! + (*raw).copy_from_slice(slice); + Ok(()) + } + } + + /// Returns a `GuestPtr` pointing to the base of the array for the interior + /// type `T`. + pub fn as_ptr(&self) -> GuestPtr<'a, T> { + GuestPtr::new(self.mem, self.offset_base()) + } +} + +impl<'a> GuestPtr<'a, str> { + /// For strings, returns the relative pointer to the base of the string + /// allocation. + pub fn offset_base(&self) -> u32 { + self.pointer.0 + } + + /// Returns the length, in bytes, of th estring. + pub fn len(&self) -> u32 { + self.pointer.1 + } + + /// Returns a raw pointer for the underlying slice of bytes that this + /// pointer points to. + pub fn as_bytes(&self) -> GuestPtr<'a, [u8]> { + GuestPtr::new(self.mem, self.pointer) + } + + /// Attempts to read a raw `*mut str` pointer from this pointer, performing + /// bounds checks and utf-8 checks. + /// The resulting `*mut str` can be used as a `&mut str` as long as the + /// reference is dropped before any Wasm code is re-entered. + /// + /// This function will return a raw pointer into host memory if all checks + /// succeed (valid utf-8, valid pointers, etc). If any checks fail then + /// `GuestError` will be returned. + /// + /// Note that the `*mut str` pointer is still unsafe to use in general, but + /// there are specific situations that it is safe to use. For more + /// information about using the raw pointer, consult the [`GuestMemory`] + /// trait documentation. + /// + /// For safety against overlapping mutable borrows, the user must use the + /// same `GuestBorrows` to create all *mut str or *mut [T] that are alive + /// at the same time. + pub fn as_raw(&self, bc: &mut GuestBorrows) -> Result<*mut str, GuestError> { + let ptr = self + .mem + .validate_size_align(self.pointer.0, 1, self.pointer.1)?; + + bc.borrow(Region { + start: self.pointer.0, + len: self.pointer.1, + })?; + + // SAFETY: iff there are no overlapping borrows (all uses of as_raw use this same + // GuestBorrows), its valid to construct a *mut str + unsafe { + let s = slice::from_raw_parts_mut(ptr, self.pointer.1 as usize); + match str::from_utf8_mut(s) { + Ok(s) => Ok(s), + Err(e) => Err(GuestError::InvalidUtf8(e)), + } + } + } +} + +impl Clone for GuestPtr<'_, T> { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for GuestPtr<'_, T> {} + +impl fmt::Debug for GuestPtr<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + T::debug(self.pointer, f) + } +} + +mod private { + pub trait Sealed {} + impl Sealed for T {} + impl Sealed for [T] {} + impl Sealed for str {} +} + +/// Types that can be pointed to by `GuestPtr`. +/// +/// In essence everything can, and the only special-case is unsized types like +/// `str` and `[T]` which have special implementations. +pub trait Pointee: private::Sealed { + #[doc(hidden)] + type Pointer: Copy; + #[doc(hidden)] + fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result; +} + +impl Pointee for T { + type Pointer = u32; + fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "*guest {:#x}", pointer) + } +} + +impl Pointee for [T] { + type Pointer = (u32, u32); + fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "*guest {:#x}/{}", pointer.0, pointer.1) + } +} + +impl Pointee for str { + type Pointer = (u32, u32); + fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result { + <[u8]>::debug(pointer, f) + } } diff --git a/crates/wiggle/crates/runtime/src/region.rs b/crates/wiggle/src/region.rs similarity index 100% rename from crates/wiggle/crates/runtime/src/region.rs rename to crates/wiggle/src/region.rs diff --git a/crates/wiggle/tests/arrays.rs b/crates/wiggle/tests/arrays.rs index b0dea82a5448..49bbc1fdb99b 100644 --- a/crates/wiggle/tests/arrays.rs +++ b/crates/wiggle/tests/arrays.rs @@ -1,5 +1,5 @@ use proptest::prelude::*; -use wiggle_runtime::{GuestError, GuestMemory, GuestPtr}; +use wiggle::{GuestError, GuestMemory, GuestPtr}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; wiggle::from_witx!({ diff --git a/crates/wiggle/tests/atoms.rs b/crates/wiggle/tests/atoms.rs index d19d19c20922..e366ef291fa8 100644 --- a/crates/wiggle/tests/atoms.rs +++ b/crates/wiggle/tests/atoms.rs @@ -1,5 +1,5 @@ use proptest::prelude::*; -use wiggle_runtime::{GuestError, GuestMemory}; +use wiggle::{GuestError, GuestMemory}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; wiggle::from_witx!({ diff --git a/crates/wiggle/tests/flags.rs b/crates/wiggle/tests/flags.rs index 4270ef50c746..dd4a6283bfe0 100644 --- a/crates/wiggle/tests/flags.rs +++ b/crates/wiggle/tests/flags.rs @@ -1,6 +1,6 @@ use proptest::prelude::*; use std::convert::TryFrom; -use wiggle_runtime::{GuestError, GuestMemory, GuestPtr}; +use wiggle::{GuestError, GuestMemory, GuestPtr}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; wiggle::from_witx!({ diff --git a/crates/wiggle/tests/handles.rs b/crates/wiggle/tests/handles.rs index c9e44122eca4..dff979fb5685 100644 --- a/crates/wiggle/tests/handles.rs +++ b/crates/wiggle/tests/handles.rs @@ -1,5 +1,5 @@ use proptest::prelude::*; -use wiggle_runtime::{GuestError, GuestMemory, GuestType}; +use wiggle::{GuestError, GuestMemory, GuestType}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; const FD_VAL: u32 = 123; diff --git a/crates/wiggle/tests/ints.rs b/crates/wiggle/tests/ints.rs index b4adeb2969fe..3a192b09a431 100644 --- a/crates/wiggle/tests/ints.rs +++ b/crates/wiggle/tests/ints.rs @@ -1,6 +1,6 @@ use proptest::prelude::*; use std::convert::TryFrom; -use wiggle_runtime::{GuestError, GuestMemory}; +use wiggle::{GuestError, GuestMemory}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; wiggle::from_witx!({ diff --git a/crates/wiggle/tests/pointers.rs b/crates/wiggle/tests/pointers.rs index cbabd7656346..2c8841c4e6ce 100644 --- a/crates/wiggle/tests/pointers.rs +++ b/crates/wiggle/tests/pointers.rs @@ -1,5 +1,5 @@ use proptest::prelude::*; -use wiggle_runtime::{GuestError, GuestMemory, GuestPtr}; +use wiggle::{GuestError, GuestMemory, GuestPtr}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; wiggle::from_witx!({ diff --git a/crates/wiggle/tests/strings.rs b/crates/wiggle/tests/strings.rs index 7fca007b4d86..c494cf63fcb4 100644 --- a/crates/wiggle/tests/strings.rs +++ b/crates/wiggle/tests/strings.rs @@ -1,5 +1,5 @@ use proptest::prelude::*; -use wiggle_runtime::{GuestBorrows, GuestError, GuestMemory, GuestPtr}; +use wiggle::{GuestBorrows, GuestError, GuestMemory, GuestPtr}; use wiggle_test::{impl_errno, HostMemory, MemArea, MemAreas, WasiCtx}; wiggle::from_witx!({ diff --git a/crates/wiggle/tests/structs.rs b/crates/wiggle/tests/structs.rs index 0be912feeb5f..7a38c00aa63b 100644 --- a/crates/wiggle/tests/structs.rs +++ b/crates/wiggle/tests/structs.rs @@ -1,5 +1,5 @@ use proptest::prelude::*; -use wiggle_runtime::{GuestError, GuestMemory, GuestPtr}; +use wiggle::{GuestError, GuestMemory, GuestPtr}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; wiggle::from_witx!({ diff --git a/crates/wiggle/tests/union.rs b/crates/wiggle/tests/union.rs index b2510e4ef9b0..d0935fd0ebb0 100644 --- a/crates/wiggle/tests/union.rs +++ b/crates/wiggle/tests/union.rs @@ -1,5 +1,5 @@ use proptest::prelude::*; -use wiggle_runtime::{GuestError, GuestMemory, GuestType}; +use wiggle::{GuestError, GuestMemory, GuestType}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; wiggle::from_witx!({ diff --git a/crates/wiggle/tests/wasi.rs b/crates/wiggle/tests/wasi.rs index 505c9d7dfff3..5e2f133782c4 100644 --- a/crates/wiggle/tests/wasi.rs +++ b/crates/wiggle/tests/wasi.rs @@ -1,4 +1,4 @@ -use wiggle_runtime::{GuestBorrows, GuestError, GuestErrorType, GuestPtr}; +use wiggle::{GuestBorrows, GuestError, GuestErrorType, GuestPtr}; use wiggle_test::WasiCtx; // This test file exists to make sure that the entire `wasi.witx` file can be diff --git a/scripts/test-all.sh b/scripts/test-all.sh index b6d38502c5d0..bcdbbce75bc6 100755 --- a/scripts/test-all.sh +++ b/scripts/test-all.sh @@ -62,7 +62,6 @@ RUST_BACKTRACE=1 cargo test \ --package wasmtime-obj \ --package wiggle \ --package wiggle-generate \ - --package wiggle-runtime \ --package wiggle-test \ --package wasi-common \ From 8a52484c39d4372e92b476131837bacd11f32e4a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 26 Mar 2020 09:24:26 -0700 Subject: [PATCH 2/4] Remove the `crates/wiggle/crates` directory Move everything into `crates/wiggle` directly, like `wasi-common` --- crates/wiggle/Cargo.toml | 4 ++-- crates/wiggle/{crates => }/generate/Cargo.toml | 2 +- crates/wiggle/{crates => }/generate/LICENSE | 0 crates/wiggle/{crates => }/generate/README.md | 0 crates/wiggle/{crates => }/generate/src/config.rs | 0 crates/wiggle/{crates => }/generate/src/funcs.rs | 0 crates/wiggle/{crates => }/generate/src/lib.rs | 0 crates/wiggle/{crates => }/generate/src/lifetimes.rs | 0 crates/wiggle/{crates => }/generate/src/module_trait.rs | 0 crates/wiggle/{crates => }/generate/src/names.rs | 0 crates/wiggle/{crates => }/generate/src/types/enum.rs | 0 crates/wiggle/{crates => }/generate/src/types/flags.rs | 0 crates/wiggle/{crates => }/generate/src/types/handle.rs | 0 crates/wiggle/{crates => }/generate/src/types/int.rs | 0 crates/wiggle/{crates => }/generate/src/types/mod.rs | 0 crates/wiggle/{crates => }/generate/src/types/struct.rs | 0 crates/wiggle/{crates => }/generate/src/types/union.rs | 0 crates/wiggle/{crates => }/macro/Cargo.toml | 4 ++-- crates/wiggle/{crates => }/macro/LICENSE | 0 crates/wiggle/{crates => }/macro/src/lib.rs | 0 crates/wiggle/{crates/test => test-helpers}/Cargo.toml | 2 +- crates/wiggle/{crates/test => test-helpers}/LICENSE | 0 crates/wiggle/{crates/test => test-helpers}/src/lib.rs | 0 23 files changed, 6 insertions(+), 6 deletions(-) rename crates/wiggle/{crates => }/generate/Cargo.toml (89%) rename crates/wiggle/{crates => }/generate/LICENSE (100%) rename crates/wiggle/{crates => }/generate/README.md (100%) rename crates/wiggle/{crates => }/generate/src/config.rs (100%) rename crates/wiggle/{crates => }/generate/src/funcs.rs (100%) rename crates/wiggle/{crates => }/generate/src/lib.rs (100%) rename crates/wiggle/{crates => }/generate/src/lifetimes.rs (100%) rename crates/wiggle/{crates => }/generate/src/module_trait.rs (100%) rename crates/wiggle/{crates => }/generate/src/names.rs (100%) rename crates/wiggle/{crates => }/generate/src/types/enum.rs (100%) rename crates/wiggle/{crates => }/generate/src/types/flags.rs (100%) rename crates/wiggle/{crates => }/generate/src/types/handle.rs (100%) rename crates/wiggle/{crates => }/generate/src/types/int.rs (100%) rename crates/wiggle/{crates => }/generate/src/types/mod.rs (100%) rename crates/wiggle/{crates => }/generate/src/types/struct.rs (100%) rename crates/wiggle/{crates => }/generate/src/types/union.rs (100%) rename crates/wiggle/{crates => }/macro/Cargo.toml (85%) rename crates/wiggle/{crates => }/macro/LICENSE (100%) rename crates/wiggle/{crates => }/macro/src/lib.rs (100%) rename crates/wiggle/{crates/test => test-helpers}/Cargo.toml (92%) rename crates/wiggle/{crates/test => test-helpers}/LICENSE (100%) rename crates/wiggle/{crates/test => test-helpers}/src/lib.rs (100%) diff --git a/crates/wiggle/Cargo.toml b/crates/wiggle/Cargo.toml index 4ef105d952c4..0633c07fd0a1 100644 --- a/crates/wiggle/Cargo.toml +++ b/crates/wiggle/Cargo.toml @@ -13,13 +13,13 @@ include = ["src/**/*", "LICENSE"] [dependencies] thiserror = "1" witx = { path = "../wasi-common/wig/WASI/tools/witx", version = "0.8.4", optional = true } -wiggle-macro = { path = "crates/macro", version = "0.13.0" } +wiggle-macro = { path = "macro", version = "0.13.0" } [badges] maintenance = { status = "actively-developed" } [dev-dependencies] -wiggle-test = { path = "crates/test", version = "0.13.0" } +wiggle-test = { path = "test-helpers", version = "0.13.0" } proptest = "0.9" [features] diff --git a/crates/wiggle/crates/generate/Cargo.toml b/crates/wiggle/generate/Cargo.toml similarity index 89% rename from crates/wiggle/crates/generate/Cargo.toml rename to crates/wiggle/generate/Cargo.toml index 98b5415b61d5..2be70669b03b 100644 --- a/crates/wiggle/crates/generate/Cargo.toml +++ b/crates/wiggle/generate/Cargo.toml @@ -14,7 +14,7 @@ include = ["src/**/*", "LICENSE"] [lib] [dependencies] -witx = { version = "0.8.4", path = "../../../wasi-common/wig/WASI/tools/witx" } +witx = { version = "0.8.4", path = "../../wasi-common/wig/WASI/tools/witx" } quote = "1.0" proc-macro2 = "1.0" heck = "0.3" diff --git a/crates/wiggle/crates/generate/LICENSE b/crates/wiggle/generate/LICENSE similarity index 100% rename from crates/wiggle/crates/generate/LICENSE rename to crates/wiggle/generate/LICENSE diff --git a/crates/wiggle/crates/generate/README.md b/crates/wiggle/generate/README.md similarity index 100% rename from crates/wiggle/crates/generate/README.md rename to crates/wiggle/generate/README.md diff --git a/crates/wiggle/crates/generate/src/config.rs b/crates/wiggle/generate/src/config.rs similarity index 100% rename from crates/wiggle/crates/generate/src/config.rs rename to crates/wiggle/generate/src/config.rs diff --git a/crates/wiggle/crates/generate/src/funcs.rs b/crates/wiggle/generate/src/funcs.rs similarity index 100% rename from crates/wiggle/crates/generate/src/funcs.rs rename to crates/wiggle/generate/src/funcs.rs diff --git a/crates/wiggle/crates/generate/src/lib.rs b/crates/wiggle/generate/src/lib.rs similarity index 100% rename from crates/wiggle/crates/generate/src/lib.rs rename to crates/wiggle/generate/src/lib.rs diff --git a/crates/wiggle/crates/generate/src/lifetimes.rs b/crates/wiggle/generate/src/lifetimes.rs similarity index 100% rename from crates/wiggle/crates/generate/src/lifetimes.rs rename to crates/wiggle/generate/src/lifetimes.rs diff --git a/crates/wiggle/crates/generate/src/module_trait.rs b/crates/wiggle/generate/src/module_trait.rs similarity index 100% rename from crates/wiggle/crates/generate/src/module_trait.rs rename to crates/wiggle/generate/src/module_trait.rs diff --git a/crates/wiggle/crates/generate/src/names.rs b/crates/wiggle/generate/src/names.rs similarity index 100% rename from crates/wiggle/crates/generate/src/names.rs rename to crates/wiggle/generate/src/names.rs diff --git a/crates/wiggle/crates/generate/src/types/enum.rs b/crates/wiggle/generate/src/types/enum.rs similarity index 100% rename from crates/wiggle/crates/generate/src/types/enum.rs rename to crates/wiggle/generate/src/types/enum.rs diff --git a/crates/wiggle/crates/generate/src/types/flags.rs b/crates/wiggle/generate/src/types/flags.rs similarity index 100% rename from crates/wiggle/crates/generate/src/types/flags.rs rename to crates/wiggle/generate/src/types/flags.rs diff --git a/crates/wiggle/crates/generate/src/types/handle.rs b/crates/wiggle/generate/src/types/handle.rs similarity index 100% rename from crates/wiggle/crates/generate/src/types/handle.rs rename to crates/wiggle/generate/src/types/handle.rs diff --git a/crates/wiggle/crates/generate/src/types/int.rs b/crates/wiggle/generate/src/types/int.rs similarity index 100% rename from crates/wiggle/crates/generate/src/types/int.rs rename to crates/wiggle/generate/src/types/int.rs diff --git a/crates/wiggle/crates/generate/src/types/mod.rs b/crates/wiggle/generate/src/types/mod.rs similarity index 100% rename from crates/wiggle/crates/generate/src/types/mod.rs rename to crates/wiggle/generate/src/types/mod.rs diff --git a/crates/wiggle/crates/generate/src/types/struct.rs b/crates/wiggle/generate/src/types/struct.rs similarity index 100% rename from crates/wiggle/crates/generate/src/types/struct.rs rename to crates/wiggle/generate/src/types/struct.rs diff --git a/crates/wiggle/crates/generate/src/types/union.rs b/crates/wiggle/generate/src/types/union.rs similarity index 100% rename from crates/wiggle/crates/generate/src/types/union.rs rename to crates/wiggle/generate/src/types/union.rs diff --git a/crates/wiggle/crates/macro/Cargo.toml b/crates/wiggle/macro/Cargo.toml similarity index 85% rename from crates/wiggle/crates/macro/Cargo.toml rename to crates/wiggle/macro/Cargo.toml index 7869b2f0687c..fb69d003ccb9 100644 --- a/crates/wiggle/crates/macro/Cargo.toml +++ b/crates/wiggle/macro/Cargo.toml @@ -16,11 +16,11 @@ proc-macro = true [dependencies] wiggle-generate = { path = "../generate", version = "0.13.0" } -witx = { path = "../../../wasi-common/wig/WASI/tools/witx", version = "0.8.4" } +witx = { path = "../../wasi-common/wig/WASI/tools/witx", version = "0.8.4" } syn = { version = "1.0", features = ["full"] } [dev-dependencies] -wiggle = { path = "../.." } +wiggle = { path = ".." } [features] wiggle_metadata = [] diff --git a/crates/wiggle/crates/macro/LICENSE b/crates/wiggle/macro/LICENSE similarity index 100% rename from crates/wiggle/crates/macro/LICENSE rename to crates/wiggle/macro/LICENSE diff --git a/crates/wiggle/crates/macro/src/lib.rs b/crates/wiggle/macro/src/lib.rs similarity index 100% rename from crates/wiggle/crates/macro/src/lib.rs rename to crates/wiggle/macro/src/lib.rs diff --git a/crates/wiggle/crates/test/Cargo.toml b/crates/wiggle/test-helpers/Cargo.toml similarity index 92% rename from crates/wiggle/crates/test/Cargo.toml rename to crates/wiggle/test-helpers/Cargo.toml index 6ebe4cc6a188..bba0892b6d7b 100644 --- a/crates/wiggle/crates/test/Cargo.toml +++ b/crates/wiggle/test-helpers/Cargo.toml @@ -12,7 +12,7 @@ include = ["src/**/*", "LICENSE"] [dependencies] proptest = "0.9" -wiggle = { path = "../..", version = "0.13.0" } +wiggle = { path = "..", version = "0.13.0" } [badges] maintenance = { status = "actively-developed" } diff --git a/crates/wiggle/crates/test/LICENSE b/crates/wiggle/test-helpers/LICENSE similarity index 100% rename from crates/wiggle/crates/test/LICENSE rename to crates/wiggle/test-helpers/LICENSE diff --git a/crates/wiggle/crates/test/src/lib.rs b/crates/wiggle/test-helpers/src/lib.rs similarity index 100% rename from crates/wiggle/crates/test/src/lib.rs rename to crates/wiggle/test-helpers/src/lib.rs From 3f012b2162f201fffb3e915efacf3d7872109f7a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 26 Mar 2020 09:27:41 -0700 Subject: [PATCH 3/4] Add wiggle-macro to test-all script --- scripts/test-all.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test-all.sh b/scripts/test-all.sh index bcdbbce75bc6..9ebfb5926dc0 100755 --- a/scripts/test-all.sh +++ b/scripts/test-all.sh @@ -63,6 +63,7 @@ RUST_BACKTRACE=1 cargo test \ --package wiggle \ --package wiggle-generate \ --package wiggle-test \ + --package wiggle-macro \ --package wasi-common \ # Test wasmtime-wasi-c, which doesn't support Windows. From 04da847b40c493912c86dc339c198afe366dcf93 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 26 Mar 2020 15:57:32 -0700 Subject: [PATCH 4/4] Fixup a test --- crates/wiggle/macro/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/wiggle/macro/src/lib.rs b/crates/wiggle/macro/src/lib.rs index dd983e1b4ef3..2cd1c27b5332 100644 --- a/crates/wiggle/macro/src/lib.rs +++ b/crates/wiggle/macro/src/lib.rs @@ -39,7 +39,7 @@ use syn::parse_macro_input; /// /// full-fledged example with runtime tests, see `tests/arrays.rs` and /// /// the rest of the files in that directory. /// wiggle::from_witx!({ -/// witx: ["../../tests/arrays.witx"], +/// witx: ["../tests/arrays.witx"], /// ctx: YourCtxType, /// }); ///