Skip to content

Commit

Permalink
Use string version
Browse files Browse the repository at this point in the history
  • Loading branch information
webmaster128 committed May 3, 2022
1 parent 9fa202e commit 6a45a00
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 164 deletions.
36 changes: 3 additions & 33 deletions api/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -478,38 +478,8 @@ struct UnmanagedVector new_unmanaged_vector(bool nil, const uint8_t *ptr, uintpt
void destroy_unmanaged_vector(struct UnmanagedVector v);

/**
* 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.
* Returns a version number of this library as a C string.
*
* 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);
* ```
* The string is owned by libwasmvm and must not be mutated or destroyed by the caller.
*/
uint64_t version_number(void);
const char *version_str(void);
24 changes: 9 additions & 15 deletions api/version.go
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
}
36 changes: 3 additions & 33 deletions libwasmvm/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -478,38 +478,8 @@ struct UnmanagedVector new_unmanaged_vector(bool nil, const uint8_t *ptr, uintpt
void destroy_unmanaged_vector(struct UnmanagedVector v);

/**
* 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.
* Returns a version number of this library as a C string.
*
* 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);
* ```
* The string is owned by libwasmvm and must not be mutated or destroyed by the caller.
*/
uint64_t version_number(void);
const char *version_str(void);
1 change: 0 additions & 1 deletion libwasmvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,3 @@ pub use memory::{
};
pub use querier::GoQuerier;
pub use storage::GoStorage;
pub use version::{make_version_number, version_number};
127 changes: 45 additions & 82 deletions libwasmvm/src/version.rs
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);
}
}

0 comments on commit 6a45a00

Please sign in to comment.