Add basic GuestString support to wiggle (#13)
* Add basic GuestString support to wiggle This commit adds basic `GuestString` support to `wiggle`. `GuestString` is a wrapper around `GuestArray<'_, u8>` array type which itself can be made into either an owned (cloned) Rust `String` or borrowed as a reference `&str`. In both cases, `GuestString` ensures that the underlying bytes are valid Unicode code units, throwing a `InvalidUtf8` error if not. This commit adds support *only* for passing in strings as arguments in WASI. Marshalling of the return arg has not yet been implemented. I'm not even sure it's possible without multi-value return args feature of Wasm. It's not a major setback especially since the WASI spec (and this includes even the `ephemeral` snapshot) doesn't return strings anywhere. They are only ever passed in as arguments to interface functions. It should be noted that error returned in case of invalid UTF-8 requires a lot more love as it doesn't include anything besides flagging an event that the string contained an invalid Unicode code unit. * Borrow all of string's memory including nul-byte Borrow all of string's underlying memory including the nul-byte. This perhaps might not have a tremendous impact on anything, but since the nul-byte is technically part of the WASI string, we should include it in the borrow as well. * Fill in wiggle-generate blanks for strings * Print to screen passed string in proptest * Strings are PointerLengthPairs! * Fix generation of strings in compound types * Update test with simple string strategy * Generate better test strings * Finalise proptest for strings * Fix formatting * Update crates/runtime/src/memory/string.rs Removes unnecessary comment in code * Apply Pat's suggestion to wrap Utf8Error as error
This commit is contained in:
@@ -181,7 +181,36 @@ fn marshal_arg(
|
||||
let #name = #name as #interface_typename;
|
||||
}
|
||||
}
|
||||
witx::BuiltinType::String => unimplemented!("string types unimplemented"),
|
||||
witx::BuiltinType::String => {
|
||||
let lifetime = anon_lifetime();
|
||||
let ptr_name = names.func_ptr_binding(¶m.name);
|
||||
let len_name = names.func_len_binding(¶m.name);
|
||||
let name = names.func_param(¶m.name);
|
||||
quote! {
|
||||
let num_elems = match memory.ptr::<u32>(#len_name as u32) {
|
||||
Ok(p) => match p.as_ref() {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
#error_handling
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
#error_handling
|
||||
}
|
||||
};
|
||||
let #name: wiggle_runtime::GuestString<#lifetime> = match memory.ptr::<u8>(#ptr_name as u32) {
|
||||
Ok(p) => match p.array(*num_elems) {
|
||||
Ok(s) => s.into(),
|
||||
Err(e) => {
|
||||
#error_handling
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
#error_handling
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
witx::Type::Pointer(pointee) => {
|
||||
let pointee_type = names.type_ref(pointee, anon_lifetime());
|
||||
|
||||
@@ -22,9 +22,9 @@ impl Names {
|
||||
let ident = format_ident!("{}", id.as_str().to_camel_case());
|
||||
quote!(#ident)
|
||||
}
|
||||
pub fn builtin_type(&self, b: BuiltinType) -> TokenStream {
|
||||
pub fn builtin_type(&self, b: BuiltinType, lifetime: TokenStream) -> TokenStream {
|
||||
match b {
|
||||
BuiltinType::String => quote!(String),
|
||||
BuiltinType::String => quote!(wiggle_runtime::GuestString<#lifetime>),
|
||||
BuiltinType::U8 => quote!(u8),
|
||||
BuiltinType::U16 => quote!(u16),
|
||||
BuiltinType::U32 => quote!(u32),
|
||||
@@ -35,7 +35,7 @@ impl Names {
|
||||
BuiltinType::S64 => quote!(i64),
|
||||
BuiltinType::F32 => quote!(f32),
|
||||
BuiltinType::F64 => quote!(f64),
|
||||
BuiltinType::Char8 => quote!(char),
|
||||
BuiltinType::Char8 => quote!(u8),
|
||||
BuiltinType::USize => quote!(usize),
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ impl Names {
|
||||
}
|
||||
}
|
||||
TypeRef::Value(ty) => match &**ty {
|
||||
witx::Type::Builtin(builtin) => self.builtin_type(*builtin),
|
||||
witx::Type::Builtin(builtin) => self.builtin_type(*builtin, lifetime.clone()),
|
||||
witx::Type::Pointer(pointee) => {
|
||||
let pointee_type = self.type_ref(&pointee, lifetime.clone());
|
||||
quote!(wiggle_runtime::GuestPtrMut<#lifetime, #pointee_type>)
|
||||
|
||||
@@ -285,14 +285,18 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
|
||||
|
||||
fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) -> TokenStream {
|
||||
let ident = names.type_(name);
|
||||
let built = names.builtin_type(builtin);
|
||||
quote!(pub type #ident = #built;)
|
||||
let built = names.builtin_type(builtin, quote!('a));
|
||||
if let witx::BuiltinType::String = builtin {
|
||||
quote!(pub type #ident<'a> = #built;)
|
||||
} else {
|
||||
quote!(pub type #ident = #built;)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_needs_lifetime(tref: &witx::TypeRef) -> bool {
|
||||
match &*tref.type_() {
|
||||
witx::Type::Builtin(b) => match b {
|
||||
witx::BuiltinType::String => unimplemented!(),
|
||||
witx::BuiltinType::String => true,
|
||||
_ => false,
|
||||
},
|
||||
witx::Type::Enum { .. }
|
||||
@@ -392,7 +396,7 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -
|
||||
let type_ = match &m.tref {
|
||||
witx::TypeRef::Name(nt) => names.type_(&nt.name),
|
||||
witx::TypeRef::Value(ty) => match &**ty {
|
||||
witx::Type::Builtin(builtin) => names.builtin_type(*builtin),
|
||||
witx::Type::Builtin(builtin) => names.builtin_type(*builtin, quote!('a)),
|
||||
witx::Type::Pointer(pointee) => {
|
||||
let pointee_type = names.type_ref(&pointee, quote!('a));
|
||||
quote!(wiggle_runtime::GuestPtrMut<'a, #pointee_type>)
|
||||
@@ -410,7 +414,7 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -
|
||||
let type_ = match &ml.member.tref {
|
||||
witx::TypeRef::Name(nt) => names.type_(&nt.name),
|
||||
witx::TypeRef::Value(ty) => match &**ty {
|
||||
witx::Type::Builtin(builtin) => names.builtin_type(*builtin),
|
||||
witx::Type::Builtin(builtin) => names.builtin_type(*builtin, quote!('a)),
|
||||
witx::Type::Pointer(pointee) => {
|
||||
let pointee_type = names.type_ref(&pointee, anon_lifetime());
|
||||
quote!(wiggle_runtime::GuestPtrMut::<#pointee_type>)
|
||||
@@ -453,7 +457,7 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -
|
||||
}
|
||||
witx::TypeRef::Value(ty) => match &**ty {
|
||||
witx::Type::Builtin(builtin) => {
|
||||
let type_ = names.builtin_type(*builtin);
|
||||
let type_ = names.builtin_type(*builtin, anon_lifetime());
|
||||
quote! {
|
||||
let #name = #type_::read_from_guest(&location.cast(#offset)?)?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user