mirror of
https://github.com/fluencelabs/interface-types
synced 2024-12-04 15:20:20 +00:00
feat(interface-types) Re-implement Type
.
The semantics of “types” have changed since the previous draft. Now, a type is like a regular WebAssembly type but with Interface Types.
This commit is contained in:
parent
165a8ca585
commit
410d8d4476
65
src/ast.rs
65
src/ast.rs
@ -60,6 +60,16 @@ pub(crate) enum AdapterKind {
|
||||
Export,
|
||||
}
|
||||
|
||||
/// Represents a type signature.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Type {
|
||||
/// Types for the parameters.
|
||||
pub inputs: Vec<InterfaceType>,
|
||||
|
||||
/// Types for the results.
|
||||
pub outputs: Vec<InterfaceType>,
|
||||
}
|
||||
|
||||
/// Represents an exported function signature.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Export<'input> {
|
||||
@ -89,55 +99,6 @@ pub struct Import<'input> {
|
||||
pub output_types: Vec<InterfaceType>,
|
||||
}
|
||||
|
||||
/// Represents a structural type.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Type<'input> {
|
||||
/// The type name.
|
||||
pub name: &'input str,
|
||||
|
||||
/// The field names.
|
||||
field_names: Vec<&'input str>,
|
||||
|
||||
/// The field types.
|
||||
field_types: Vec<InterfaceType>,
|
||||
}
|
||||
|
||||
impl<'input> Type<'input> {
|
||||
/// Creates a new `Type`.
|
||||
///
|
||||
/// The constructor panics if there is the length of `names` is
|
||||
/// different than the length of `types`.
|
||||
pub fn new(type_name: &'input str, names: Vec<&'input str>, types: Vec<InterfaceType>) -> Self {
|
||||
assert_eq!(
|
||||
names.len(),
|
||||
types.len(),
|
||||
"There must be the same number of field names than field types."
|
||||
);
|
||||
|
||||
Self {
|
||||
name: type_name,
|
||||
field_names: names,
|
||||
field_types: types,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a new field to the type.
|
||||
pub fn add_field(&mut self, name: &'input str, ty: InterfaceType) {
|
||||
self.field_names.push(name);
|
||||
self.field_types.push(ty);
|
||||
}
|
||||
|
||||
/// Returns the field names.
|
||||
pub fn field_names(&self) -> &Vec<&'input str> {
|
||||
&self.field_names
|
||||
}
|
||||
|
||||
/// Returns the field types.
|
||||
pub fn field_types(&self) -> &Vec<InterfaceType> {
|
||||
&self.field_types
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an adapter.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum Adapter<'input> {
|
||||
@ -179,12 +140,12 @@ pub enum Adapter<'input> {
|
||||
/// definition.
|
||||
#[derive(PartialEq, Default, Debug)]
|
||||
pub struct Interfaces<'input> {
|
||||
/// All the types.
|
||||
pub types: Vec<Type>,
|
||||
|
||||
/// All the exported functions.
|
||||
pub exports: Vec<Export<'input>>,
|
||||
|
||||
/// All the types.
|
||||
pub types: Vec<Type<'input>>,
|
||||
|
||||
/// All the imported functions.
|
||||
pub imports: Vec<Import<'input>>,
|
||||
|
||||
|
@ -295,11 +295,10 @@ fn types<'input, E: ParseError<&'input [u8]>>(
|
||||
let mut types = Vec::with_capacity(number_of_types as usize);
|
||||
|
||||
for _ in 0..number_of_types {
|
||||
consume!((input, type_name) = string(input)?);
|
||||
consume!((input, type_fields) = list(input, string)?);
|
||||
consume!((input, type_types) = list(input, ty)?);
|
||||
consume!((input, inputs) = list(input, ty)?);
|
||||
consume!((input, outputs) = list(input, ty)?);
|
||||
|
||||
types.push(Type::new(type_name, type_fields, type_types));
|
||||
types.push(Type { inputs, outputs });
|
||||
}
|
||||
|
||||
Ok((input, types))
|
||||
@ -424,16 +423,11 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>(
|
||||
/// 0x01, // list of 1 item
|
||||
/// 0x02, // S32
|
||||
/// 0x01, // 1 type
|
||||
/// 0x02, // string of 2 bytes
|
||||
/// 0x61, 0x62, // "a", "b"
|
||||
/// 0x02, // list of 2 items
|
||||
/// 0x02, // string of 2 bytes
|
||||
/// 0x63, 0x64, // "c", "d"
|
||||
/// 0x01, // string of 1 byte
|
||||
/// 0x65, // "e"
|
||||
/// 0x02, // list of 2 items
|
||||
/// 0x02, // S32
|
||||
/// 0x02, // S32
|
||||
/// 0x01, // list of 1 item
|
||||
/// 0x02, // S32
|
||||
/// 0x01, // 1 import
|
||||
/// 0x01, // string of 1 byte
|
||||
/// 0x61, // "a"
|
||||
@ -464,11 +458,10 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>(
|
||||
/// input_types: vec![InterfaceType::S32],
|
||||
/// output_types: vec![InterfaceType::S32],
|
||||
/// }],
|
||||
/// types: vec![Type::new(
|
||||
/// "ab",
|
||||
/// vec!["cd", "e"],
|
||||
/// vec![InterfaceType::S32, InterfaceType::S32],
|
||||
/// )],
|
||||
/// types: vec![Type {
|
||||
/// inputs: vec![InterfaceType::S32, InterfaceType::S32],
|
||||
/// outputs: vec![InterfaceType::S32],
|
||||
/// }],
|
||||
/// imports: vec![Import {
|
||||
/// namespace: "a",
|
||||
/// name: "b",
|
||||
@ -740,24 +733,18 @@ mod tests {
|
||||
fn test_types() {
|
||||
let input = &[
|
||||
0x01, // 1 type
|
||||
0x02, // string of 2 bytes
|
||||
0x61, 0x62, // "a", "b"
|
||||
0x02, // list of 2 items
|
||||
0x02, // string of 2 bytes
|
||||
0x63, 0x64, // "c", "d"
|
||||
0x01, // string of 1 byte
|
||||
0x65, // "e"
|
||||
0x02, // list of 2 items
|
||||
0x02, // S32
|
||||
0x02, // S32
|
||||
0x01, // list of 2 items
|
||||
0x02, // S32
|
||||
];
|
||||
let output = Ok((
|
||||
&[] as &[u8],
|
||||
vec![Type::new(
|
||||
"ab",
|
||||
vec!["cd", "e"],
|
||||
vec![InterfaceType::S32, InterfaceType::S32],
|
||||
)],
|
||||
vec![Type {
|
||||
inputs: vec![InterfaceType::S32, InterfaceType::S32],
|
||||
outputs: vec![InterfaceType::S32],
|
||||
}],
|
||||
));
|
||||
|
||||
assert_eq!(types::<()>(input), output);
|
||||
@ -863,16 +850,10 @@ mod tests {
|
||||
0x01, // list of 1 item
|
||||
0x0c, // I32
|
||||
0x01, // 1 type
|
||||
0x02, // string of 2 bytes
|
||||
0x61, 0x62, // "a", "b"
|
||||
0x02, // list of 2 items
|
||||
0x02, // string of 2 bytes
|
||||
0x63, 0x64, // "c", "d"
|
||||
0x01, // string of 1 byte
|
||||
0x65, // "e"
|
||||
0x02, // list of 2 items
|
||||
0x0c, // I32
|
||||
0x0c, // I32
|
||||
0x00, // list of 0 item
|
||||
0x01, // 1 import
|
||||
0x01, // string of 1 byte
|
||||
0x61, // "a"
|
||||
@ -903,11 +884,10 @@ mod tests {
|
||||
input_types: vec![InterfaceType::I32],
|
||||
output_types: vec![InterfaceType::I32],
|
||||
}],
|
||||
types: vec![Type::new(
|
||||
"ab",
|
||||
vec!["cd", "e"],
|
||||
vec![InterfaceType::I32, InterfaceType::I32],
|
||||
)],
|
||||
types: vec![Type {
|
||||
inputs: vec![InterfaceType::I32, InterfaceType::I32],
|
||||
outputs: vec![],
|
||||
}],
|
||||
imports: vec![Import {
|
||||
namespace: "a",
|
||||
name: "b",
|
||||
|
@ -15,6 +15,7 @@ mod keyword {
|
||||
|
||||
// New keywords.
|
||||
custom_keyword!(adapt);
|
||||
custom_keyword!(r#type = "type");
|
||||
|
||||
// New types.
|
||||
custom_keyword!(s8);
|
||||
@ -283,8 +284,7 @@ impl Parse<'_> for FunctionType {
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum Interface<'a> {
|
||||
Export(Export<'a>),
|
||||
#[allow(dead_code)]
|
||||
Type(Type<'a>),
|
||||
Type(Type),
|
||||
Import(Import<'a>),
|
||||
Adapter(Adapter<'a>),
|
||||
}
|
||||
@ -305,6 +305,8 @@ impl<'a> Parse<'a> for Interface<'a> {
|
||||
Ok(Interface::Import(parser.parse()?))
|
||||
} else if lookahead.peek::<keyword::adapt>() {
|
||||
Ok(Interface::Adapter(parser.parse()?))
|
||||
} else if lookahead.peek::<keyword::r#type>() {
|
||||
Ok(Interface::Type(parser.parse()?))
|
||||
} else {
|
||||
Err(lookahead.error())
|
||||
}
|
||||
@ -315,6 +317,32 @@ impl<'a> Parse<'a> for Interface<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Parse<'a> for Type {
|
||||
fn parse(parser: Parser<'a>) -> Result<Self> {
|
||||
parser.parse::<keyword::r#type>()?;
|
||||
|
||||
let (inputs, outputs) = parser.parens(|parser| {
|
||||
parser.parse::<keyword::func>()?;
|
||||
|
||||
let mut input_types = vec![];
|
||||
let mut output_types = vec![];
|
||||
|
||||
while !parser.is_empty() {
|
||||
let function_type = parser.parse::<FunctionType>()?;
|
||||
|
||||
match function_type {
|
||||
FunctionType::Input(mut inputs) => input_types.append(&mut inputs),
|
||||
FunctionType::Output(mut outputs) => output_types.append(&mut outputs),
|
||||
}
|
||||
}
|
||||
|
||||
Ok((input_types, output_types))
|
||||
})?;
|
||||
|
||||
Ok(Type { inputs, outputs })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Parse<'a> for Export<'a> {
|
||||
fn parse(parser: Parser<'a>) -> Result<Self> {
|
||||
parser.parse::<keyword::export>()?;
|
||||
@ -663,6 +691,17 @@ mod tests {
|
||||
assert_eq!(parser::parse::<FunctionType>(&input).unwrap(), output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type() {
|
||||
let input = buffer(r#"(@interface type (func (param i32 i32) (result i32)))"#);
|
||||
let output = Interface::Type(Type {
|
||||
inputs: vec![InterfaceType::I32, InterfaceType::I32],
|
||||
outputs: vec![InterfaceType::I32],
|
||||
});
|
||||
|
||||
assert_eq!(parser::parse::<Interface>(&input).unwrap(), output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_export_with_no_param_no_result() {
|
||||
let input = buffer(r#"(@interface export "foo")"#);
|
||||
|
@ -147,14 +147,13 @@ where
|
||||
/// Encode a `Type` into bytes.
|
||||
///
|
||||
/// Decoder is in `decoders::binary::types`.
|
||||
impl<W> ToBytes<W> for Type<'_>
|
||||
impl<W> ToBytes<W> for Type
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
|
||||
self.name.to_bytes(writer)?;
|
||||
self.field_names().to_bytes(writer)?;
|
||||
self.field_types().to_bytes(writer)?;
|
||||
self.inputs.to_bytes(writer)?;
|
||||
self.outputs.to_bytes(writer)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -468,22 +467,16 @@ mod tests {
|
||||
#[test]
|
||||
fn test_type() {
|
||||
assert_to_bytes!(
|
||||
Type::new(
|
||||
"a",
|
||||
vec!["b", "c"],
|
||||
vec![InterfaceType::I32, InterfaceType::I64],
|
||||
),
|
||||
Type {
|
||||
inputs: vec![InterfaceType::I32, InterfaceType::I64],
|
||||
outputs: vec![InterfaceType::S32],
|
||||
},
|
||||
&[
|
||||
0x01, // string of length 1
|
||||
0x61, // "a"
|
||||
0x02, // list of 2 items
|
||||
0x01, // string of length 1
|
||||
0x62, // "b"
|
||||
0x01, // string of length 1
|
||||
0x63, // "c"
|
||||
0x02, // list of 2 items
|
||||
0x0c, // I32
|
||||
0x0d, // I64
|
||||
0x01, // list of 1 items
|
||||
0x02, // I64
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -571,11 +564,10 @@ mod tests {
|
||||
input_types: vec![InterfaceType::I32],
|
||||
output_types: vec![InterfaceType::I32],
|
||||
}],
|
||||
types: vec![Type::new(
|
||||
"ab",
|
||||
vec!["cd", "e"],
|
||||
vec![InterfaceType::I32, InterfaceType::I32],
|
||||
)],
|
||||
types: vec![Type {
|
||||
inputs: vec![InterfaceType::I32, InterfaceType::I32],
|
||||
outputs: vec![InterfaceType::S32],
|
||||
}],
|
||||
imports: vec![Import {
|
||||
namespace: "a",
|
||||
name: "b",
|
||||
@ -599,16 +591,11 @@ mod tests {
|
||||
0x01, // list of 1 item
|
||||
0x0c, // I32
|
||||
0x01, // 1 type
|
||||
0x02, // string of 2 bytes
|
||||
0x61, 0x62, // "a", "b"
|
||||
0x02, // list of 2 items
|
||||
0x02, // string of 2 bytes
|
||||
0x63, 0x64, // "c", "d"
|
||||
0x01, // string of 1 byte
|
||||
0x65, // "e"
|
||||
0x02, // list of 2 items
|
||||
0x0c, // I32
|
||||
0x0c, // I32
|
||||
0x01, // list of 1 item
|
||||
0x02, // S32
|
||||
0x01, // 1 import
|
||||
0x01, // string of 1 byte
|
||||
0x61, // "a"
|
||||
|
@ -211,9 +211,13 @@ impl<'input> ToString for &Export<'input> {
|
||||
}
|
||||
|
||||
/// Encode a `Type` into a string.
|
||||
impl<'input> ToString for &Type<'input> {
|
||||
impl<'input> ToString for &Type {
|
||||
fn to_string(&self) -> String {
|
||||
todo!("To be implemented.")
|
||||
format!(
|
||||
r#"(@interface type (func{inputs}{outputs}))"#,
|
||||
inputs = input_types_to_param(&self.inputs),
|
||||
outputs = output_types_to_result(&self.outputs),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,7 +301,6 @@ impl<'input> ToString for &Interfaces<'input> {
|
||||
.types
|
||||
.iter()
|
||||
.fold(String::new(), |mut accumulator, ty| {
|
||||
accumulator.push_str(&format!("\n\n;; Interface, Ty {}\n", ty.name));
|
||||
accumulator.push_str(&ty.to_string());
|
||||
accumulator
|
||||
});
|
||||
@ -426,6 +429,44 @@ mod tests {
|
||||
assert_eq!(inputs, outputs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_types() {
|
||||
let inputs: Vec<String> = vec![
|
||||
(&Type {
|
||||
inputs: vec![InterfaceType::I32, InterfaceType::F32],
|
||||
outputs: vec![InterfaceType::I32],
|
||||
})
|
||||
.to_string(),
|
||||
(&Type {
|
||||
inputs: vec![InterfaceType::I32],
|
||||
outputs: vec![],
|
||||
})
|
||||
.to_string(),
|
||||
(&Type {
|
||||
inputs: vec![],
|
||||
outputs: vec![InterfaceType::I32],
|
||||
})
|
||||
.to_string(),
|
||||
(&Type {
|
||||
inputs: vec![],
|
||||
outputs: vec![],
|
||||
})
|
||||
.to_string(),
|
||||
];
|
||||
let outputs = vec![
|
||||
r#"(@interface type (func
|
||||
(param i32 f32)
|
||||
(result i32)))"#,
|
||||
r#"(@interface type (func
|
||||
(param i32)))"#,
|
||||
r#"(@interface type (func
|
||||
(result i32)))"#,
|
||||
r#"(@interface type (func))"#,
|
||||
];
|
||||
|
||||
assert_eq!(inputs, outputs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exports() {
|
||||
let inputs: Vec<String> = vec![
|
||||
|
@ -11,11 +11,10 @@ fn test_binary_encoding_decoding_roundtrip() {
|
||||
input_types: vec![InterfaceType::I32],
|
||||
output_types: vec![InterfaceType::I32],
|
||||
}],
|
||||
types: vec![Type::new(
|
||||
"ab",
|
||||
vec!["cd", "e"],
|
||||
vec![InterfaceType::I32, InterfaceType::I32],
|
||||
)],
|
||||
types: vec![Type {
|
||||
inputs: vec![InterfaceType::I32, InterfaceType::I32],
|
||||
outputs: vec![InterfaceType::S32],
|
||||
}],
|
||||
imports: vec![Import {
|
||||
namespace: "a",
|
||||
name: "b",
|
||||
|
Loading…
Reference in New Issue
Block a user