-
Notifications
You must be signed in to change notification settings - Fork 103
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9fa202e
commit 6a45a00
Showing
5 changed files
with
60 additions
and
164 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,20 @@ | ||
package api | ||
|
||
// #include "bindings.h" | ||
/* | ||
#include "bindings.h" | ||
*/ | ||
import "C" | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
// LibwasmvmVersion returns the version of the loaded library | ||
// at runtime. This can be used to verify if the loaded version | ||
// at runtime. This can be used for debugging to verify the loaded version | ||
// matches the expected version. | ||
func LibwasmvmVersion() (string, error) { | ||
version, err := C.version_number() | ||
version_ptr, err := C.version_str() | ||
if err != nil { | ||
return "", err | ||
} | ||
patch := version >> 0 & 0xFFFF | ||
minor := version >> 16 & 0xFFFF | ||
major := version >> 32 & 0xFFFF | ||
error := version >> 48 & 0xFFFF | ||
if error != 0 { | ||
return "", fmt.Errorf("Error code from version_number call: %d", error) | ||
} | ||
return fmt.Sprintf("%d.%d.%d", major, minor, patch), nil | ||
// For C.GoString documentation see https://pkg.go.dev/cmd/cgo and | ||
// https://gist.github.com/helinwang/2c7bd2867ea5110f70e6431a7c80cd9b | ||
version_copy := C.GoString(version_ptr) | ||
return version_copy, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,56 @@ | ||
/// Returns a version number of this library in the form 0xEEEEXXXXYYYYZZZZ | ||
/// with two-byte hexadecimal values EEEE, XXXX, YYYY, ZZZZ from 0 to 65535 each. | ||
/// | ||
/// EEEE represents the error value with 0 meaning no error. | ||
/// XXXX is the major version, YYYY is the minor version and ZZZZ is the patch version. | ||
/// | ||
/// ## Examples | ||
/// | ||
/// The version number can be decomposed like this: | ||
/// | ||
/// ``` | ||
/// # use wasmvm::version_number; | ||
/// let version = version_number(); | ||
/// let patch = version >> 0 & 0xFFFF; | ||
/// let minor = version >> 16 & 0xFFFF; | ||
/// let major = version >> 32 & 0xFFFF; | ||
/// let error = version >> 48 & 0xFFFF; | ||
/// assert_eq!(error, 0); | ||
/// assert_eq!(major, 1); | ||
/// assert!(minor < 70); | ||
/// assert!(patch < 70); | ||
/// ``` | ||
/// | ||
/// And compared like this: | ||
/// | ||
/// ``` | ||
/// # use wasmvm::{make_version_number, version_number}; | ||
/// let min_version = make_version_number(0, 17, 25); | ||
/// let version = version_number(); | ||
/// let error = version >> 48 & 0xFFFF; | ||
/// assert_eq!(error, 0); | ||
/// assert!(version >= min_version); | ||
/// ``` | ||
#[no_mangle] | ||
pub extern "C" fn version_number() -> u64 { | ||
match version_number_impl() { | ||
Ok([major, minor, patch]) => make_version_number(major, minor, patch), | ||
Err(err) => { | ||
let error = err as u16; | ||
let [b0, b1] = error.to_be_bytes(); | ||
u64::from_be_bytes([b0, b1, 0, 0, 0, 0, 0, 0]) | ||
} | ||
} | ||
} | ||
use std::os::raw::c_char; | ||
|
||
/// Creates a version number from the three components major.minor.patch. | ||
/// | ||
/// See [`version_number`] for more details. | ||
pub fn make_version_number(major: u16, minor: u16, patch: u16) -> u64 { | ||
let [b2, b3] = major.to_be_bytes(); | ||
let [b4, b5] = minor.to_be_bytes(); | ||
let [b6, b7] = patch.to_be_bytes(); | ||
u64::from_be_bytes([0, 0, b2, b3, b4, b5, b6, b7]) | ||
} | ||
static VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0"); // Add trailing NULL byte for C string | ||
|
||
// Errors will be converted to u16 and passed over the FFI | ||
// using big endian encoding. | ||
enum VersionNumberError { | ||
CannotParseMajor = 1, | ||
CannotParseMinor, | ||
CannotParsePatch, | ||
} | ||
|
||
fn version_number_impl() -> Result<[u16; 3], VersionNumberError> { | ||
let major: u16 = env!("CARGO_PKG_VERSION_MAJOR") | ||
.parse() | ||
.map_err(|_| VersionNumberError::CannotParseMajor)?; | ||
let minor: u16 = env!("CARGO_PKG_VERSION_MINOR") | ||
.parse() | ||
.map_err(|_| VersionNumberError::CannotParseMinor)?; | ||
let patch: u16 = env!("CARGO_PKG_VERSION_PATCH") | ||
.parse() | ||
.map_err(|_| VersionNumberError::CannotParsePatch)?; | ||
Ok([major, minor, patch]) | ||
/// Returns a version number of this library as a C string. | ||
/// | ||
/// The string is owned by libwasmvm and must not be mutated or destroyed by the caller. | ||
#[no_mangle] | ||
pub extern "C" fn version_str() -> *const c_char { | ||
VERSION.as_ptr() as *const _ | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use std::ffi::CStr; | ||
|
||
#[test] | ||
fn version_number_works() { | ||
let version = version_number(); | ||
let patch = version >> 0 & 0xFFFF; | ||
let minor = version >> 16 & 0xFFFF; | ||
let major = version >> 32 & 0xFFFF; | ||
let error = version >> 48 & 0xFFFF; | ||
assert_eq!(error, 0); | ||
assert_eq!(major, 1); | ||
assert!(minor < 70); | ||
assert!(patch < 70); | ||
fn version_works() { | ||
// Returns the same pointer every time | ||
let ptr1 = version_str(); | ||
let ptr2 = version_str(); | ||
assert_eq!(ptr1, ptr2); | ||
|
||
// Contains correct data | ||
let version_ptr = version_str(); | ||
let version_str = unsafe { CStr::from_ptr(version_ptr) }.to_str().unwrap(); | ||
// assert_eq!(version_str, "1.2.3"); | ||
|
||
let mut parts = version_str.split("-"); | ||
let version_core = parts.next().unwrap(); | ||
let components = version_core.split(".").collect::<Vec<_>>(); | ||
assert_eq!(components.len(), 3); | ||
assert!( | ||
components[0].chars().all(|c| c.is_ascii_digit()), | ||
"Invalid major component: '{}'", | ||
components[0] | ||
); | ||
assert!( | ||
components[1].chars().all(|c| c.is_ascii_digit()), | ||
"Invalid minor component: '{}'", | ||
components[1] | ||
); | ||
assert!( | ||
components[2].chars().all(|c| c.is_ascii_digit()), | ||
"Invalid patch component: '{}'", | ||
components[2] | ||
); | ||
if let Some(prerelease) = parts.next() { | ||
assert!(prerelease | ||
.chars() | ||
.all(|c| c == '.' || c.is_ascii_alphanumeric())); | ||
} | ||
assert_eq!(parts.next(), None); | ||
} | ||
} |