diff --git a/Cargo.lock b/Cargo.lock index a04c4ef..05e1a6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "arrayvec" version = "0.5.2" @@ -14,9 +16,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "cfg-if" -version = "0.1.10" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "fluence-it-types" @@ -46,9 +48,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "lexical-core" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" +checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" dependencies = [ "arrayvec", "bitflags", @@ -59,9 +61,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", ] @@ -83,6 +85,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "proc-macro2" version = "1.0.24" @@ -94,9 +105,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -109,24 +120,42 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "safe-transmute" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d95e7284b4bd97e24af76023904cd0157c9cc9da0310beb4139a1e88a748d47" + +[[package]] +name = "semver" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b8b2cd387f744f69469aaed197954ba4c0ecdb31e02edf99b023e0df11178a" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] [[package]] name = "serde" -version = "1.0.118" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" dependencies = [ "proc-macro2", "quote", @@ -135,9 +164,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", @@ -152,15 +181,21 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "1.0.56" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72" +checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-xid" version = "0.2.1" @@ -175,13 +210,14 @@ checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "wasmer-interface-types-fl" -version = "0.17.24" +version = "0.18.3" dependencies = [ "fluence-it-types", "it-to-bytes", "log", "nom", "safe-transmute", + "semver", "serde", "serde_json", "wast", diff --git a/crates/to-bytes/src/lib.rs b/crates/to-bytes/src/lib.rs index e35fd8d..0f6a448 100644 --- a/crates/to-bytes/src/lib.rs +++ b/crates/to-bytes/src/lib.rs @@ -72,13 +72,7 @@ where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - // Size first. - writer.write_all(&[self.len() as u8])?; - - // Then the string. - writer.write_all(self.as_bytes())?; - - Ok(()) + self.as_str().to_bytes(writer) } } diff --git a/wasmer-it/Cargo.toml b/wasmer-it/Cargo.toml index c75b34b..89b6f4e 100644 --- a/wasmer-it/Cargo.toml +++ b/wasmer-it/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-interface-types-fl" -version = "0.17.24" +version = "0.18.3" description = "WebAssembly Interface Types library for Wasmer" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -22,5 +22,7 @@ serde_json = "1.0" safe-transmute = "0.11.0" log = "0.4.11" +semver = "0.11.0" + [features] default = ["serde"] diff --git a/wasmer-it/src/ast.rs b/wasmer-it/src/ast.rs index e332ce0..4be9751 100644 --- a/wasmer-it/src/ast.rs +++ b/wasmer-it/src/ast.rs @@ -98,6 +98,9 @@ pub struct Implementation { /// Represents the kind of interface. #[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)] pub enum InterfaceKind { + /// A version. + Version, + /// A type. Type, @@ -116,8 +119,11 @@ pub enum InterfaceKind { /// Represents a set of interfaces, i.e. it entirely describes a WIT /// definition. -#[derive(PartialEq, Eq, Debug, Default, Clone, Hash)] +#[derive(PartialEq, Eq, Debug, Clone, Hash)] pub struct Interfaces<'input> { + /// Version of IT. + pub version: semver::Version, + /// All the types. pub types: Vec, @@ -133,3 +139,40 @@ pub struct Interfaces<'input> { /// All the implementations. pub implementations: Vec, } + +impl Interfaces<'_> { + /// Creates a new Interfaces where version comes from this package version. + pub fn new() -> Self { + use std::str::FromStr; + + // it's safe because otherwise it won't compile + let version = semver::Version::from_str(env!("CARGO_PKG_VERSION")).unwrap(); + + Self { + version, + types: Vec::new(), + imports: Vec::new(), + adapters: Vec::new(), + exports: Vec::new(), + implementations: Vec::new(), + } + } + + /// Creates a new Interfaces from the provided version. + pub fn from_version(version: semver::Version) -> Self { + Self { + version, + types: Vec::new(), + imports: Vec::new(), + adapters: Vec::new(), + exports: Vec::new(), + implementations: Vec::new(), + } + } +} + +impl Default for Interfaces<'_> { + fn default() -> Self { + Self::new() + } +} diff --git a/wasmer-it/src/decoders/binary.rs b/wasmer-it/src/decoders/binary.rs index 77482ff..aeff345 100644 --- a/wasmer-it/src/decoders/binary.rs +++ b/wasmer-it/src/decoders/binary.rs @@ -35,6 +35,7 @@ impl TryFrom for InterfaceKind { 0x02 => Self::Adapter, 0x03 => Self::Export, 0x04 => Self::Implementation, + 0x05 => Self::Version, _ => return Err("Unknown interface kind code."), }) } @@ -487,6 +488,7 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>( ) -> IResult<&'input [u8], Interfaces, E> { let mut input = bytes; + let mut all_versions = vec![]; let mut all_types = vec![]; let mut all_imports = vec![]; let mut all_adapters = vec![]; @@ -500,6 +502,10 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>( .map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?; match interface_kind { + InterfaceKind::Version => { + consume!((input, new_version) = string(input)?); + all_versions.push(new_version); + } InterfaceKind::Type => { consume!((input, mut new_types) = types(input)?); all_types.append(&mut new_types); @@ -527,9 +533,12 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>( } } + let version = try_into_version(all_versions).map_err(|e| Err::Error(make_error(input, e)))?; + Ok(( input, Interfaces { + version, types: all_types, imports: all_imports, adapters: all_adapters, @@ -539,6 +548,22 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>( )) } +fn try_into_version(versions: Vec<&str>) -> Result { + use std::str::FromStr; + + if versions.is_empty() { + return Err(ErrorKind::NoneOf); + } + + if versions.len() != 1 { + return Err(ErrorKind::Many0); + } + + let version = semver::Version::from_str(&versions[0]).map_err(|_| ErrorKind::IsNot)?; + + Ok(version) +} + /// Parse a sequence of bytes, expecting it to be a valid WIT binary /// representation, into an [`Interfaces`](crate::ast::Interfaces) /// structure. diff --git a/wasmer-it/src/decoders/wat.rs b/wasmer-it/src/decoders/wat.rs index 668a30f..b1fb492 100644 --- a/wasmer-it/src/decoders/wat.rs +++ b/wasmer-it/src/decoders/wat.rs @@ -18,6 +18,7 @@ mod keyword { custom_keyword!(r#type = "type"); custom_keyword!(record); custom_keyword!(field); + custom_keyword!(it_version); // Special symbols custom_keyword!(comma = ","); @@ -378,8 +379,21 @@ impl Parse<'_> for FunctionType { } } +#[derive(PartialEq, Debug)] +struct Version(pub String); + +impl Parse<'_> for Version { + fn parse(parser: Parser<'_>) -> Result { + parser.parse::()?; + let version = parser.parse()?; + + Ok(Version(version)) + } +} + #[derive(PartialEq, Debug)] enum Interface<'a> { + Version(Version), Type(Type), Import(Import<'a>), Adapter(Adapter), @@ -397,7 +411,9 @@ impl<'a> Parse<'a> for Interface<'a> { let mut lookahead = parser.lookahead1(); - if lookahead.peek::() { + if lookahead.peek::() { + Ok(Interface::Version(parser.parse()?)) + } else if lookahead.peek::() { Ok(Interface::Type(parser.parse()?)) } else if lookahead.peek::() { Ok(Interface::Import(parser.parse()?)) @@ -548,26 +564,66 @@ impl<'a> Parse<'a> for Adapter { impl<'a> Parse<'a> for Interfaces<'a> { fn parse(parser: Parser<'a>) -> Result { - let mut interfaces: Interfaces = Default::default(); + let mut version: Option = None; + let mut types = vec![]; + let mut imports = vec![]; + let mut adapters = vec![]; + let mut exports = vec![]; + let mut implementations = vec![]; while !parser.is_empty() { let interface = parser.parse::()?; match interface { - Interface::Type(ty) => interfaces.types.push(ty), - Interface::Import(import) => interfaces.imports.push(import), - Interface::Adapter(adapter) => interfaces.adapters.push(adapter), - Interface::Export(export) => interfaces.exports.push(export), - Interface::Implementation(implementation) => { - interfaces.implementations.push(implementation) + Interface::Version(version_str) => { + try_handle_version(&version_str, &mut version, &parser)? } + Interface::Type(ty) => types.push(ty), + Interface::Import(import) => imports.push(import), + Interface::Adapter(adapter) => adapters.push(adapter), + Interface::Export(export) => exports.push(export), + Interface::Implementation(implementation) => implementations.push(implementation), } } + let version = version.ok_or_else(|| { + wast::Error::new(parser.cur_span(), String::from("version must be specified, probably this module was built with old version of fce, please rebuild it")) + })?; + + let interfaces = Interfaces { + version, + types, + imports, + adapters, + exports, + implementations, + }; + Ok(interfaces) } } +fn try_handle_version( + sdk_version: &Version, + version: &mut Option, + parser: &Parser<'_>, +) -> Result<()> { + use std::str::FromStr; + + if version.is_some() { + return Err(wast::Error::new( + parser.cur_span(), + String::from("only one version directive is possible"), + )); + } + + let parsed_version = semver::Version::from_str(&sdk_version.0) + .map_err(|e| wast::Error::new(parser.cur_span(), format!("version is corrupted: {}", e)))?; + *version = Some(parsed_version); + + Ok(()) +} + /// Parse a WIT definition in its textual format, and produces an /// [AST](crate::ast) with the [`Interfaces`](crate::ast::Interfaces) /// structure upon succesful. diff --git a/wasmer-it/src/encoders/binary.rs b/wasmer-it/src/encoders/binary.rs index 260c428..7857dc6 100644 --- a/wasmer-it/src/encoders/binary.rs +++ b/wasmer-it/src/encoders/binary.rs @@ -33,6 +33,7 @@ where Self::Adapter => 0x02_u8.to_bytes(writer), Self::Export => 0x03_u8.to_bytes(writer), Self::Implementation => 0x04_u8.to_bytes(writer), + Self::Version => 0x05_u8.to_bytes(writer), } } } @@ -144,6 +145,9 @@ where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { + InterfaceKind::Version.to_bytes(writer)?; + self.version.to_string().to_bytes(writer)?; + if !self.types.is_empty() { InterfaceKind::Type.to_bytes(writer)?; self.types.to_bytes(writer)?; diff --git a/wasmer-it/src/encoders/wat.rs b/wasmer-it/src/encoders/wat.rs index cff8aa1..766c405 100644 --- a/wasmer-it/src/encoders/wat.rs +++ b/wasmer-it/src/encoders/wat.rs @@ -296,6 +296,9 @@ impl<'input> ToString for &Interfaces<'input> { } }; + output.push_str(&format!(r#"(@interface it_version "{}""#, self.version)); + separator(&mut output); + if !types.is_empty() { output.push_str(";; Types"); output.push_str(&types);