Implementation of the Haystack 4 spec in the Rust programming language.
The library covers extensive parts of the specification, and it uses the cargo features to allow opt-in on features such as decoders, filter, units, timezone, and the C FFI API.
The library requires the allocator feature and the standard library, but it can be compiled to WASM as a non OS target.
Using cargo cargo build
creates a debug version, cargo build --release
creates a release version.
Specialize builds for each feature set can be compiled as cargo build --release --no-default-features --features "encoders, zinc"
, which will compile only the core types
and the zinc encoding modules, resulting in a small binary (12KB on Windows x86-64)
Run unit and integration tests with cargo test
The library fundamental type is Value. It can hold any of the Haystack supported data-types.
Create a Str
Value from a &str
```rust
use libhaystack::val::*;
// Creates a Str Value
let value = Value::from("Hello");
// Get a std::String from the value assert!(String::try_form(value).expect("String"), "Hello"); ```
Create a Number Value with a unit ```rust use libhaystack::val::; use libhaystack::units::;
// Creates a Number Value using the Value helper function let a = Value::makenumberunit(42, get_unit("m³"));
// Creates the Number scalar let b = Number::makewithunit(100.0, "m³".into());
// Add numbers with units asserteq!(Number::tryform(a).expect("Number") + b, Number::makewithunit(142.0, get_unit("m³"))); ```
Create a Haystack Dict ```rust use libhaystack::val::*;
// Create the Dict type let dict = Value::from(dict! { "site" => Value::makemarker(), "name" => Value::makestr("Foo") });
assert!(dict.has("site")); asserteq!(dictvalue.get_str("name"), Some(&"Foo".into()));
// Wrap the type as a Value let value: Value = dict.into(); assert!(value.is_dict()); ```
A Haystack 4 compliant filter parser and evaluator is provided that uses the ontology definitions from Project Haystack.
```rust use libhaystack::dict; use libhaystack::val::; use libhaystack::filter::;
// Parse the filter from a string let filter = Filter::try_from(r#"site and dis=="Test""#).expect("Filter");
// Define a Dict to apply the filter against let dict = dict!{"site" => Value::make_marker(), "dis" => Value::from("Test")};
// Verify that the filter matched the Dict assert_eq!(dict.filter(&filter), true);
// Filter using advanced ontology query let filter = Filter::try_from(r#"^geoPlace and dis=="Test""#).expect("Filter");
// Sites are geoPlaces let dict = dict!{"site" => Value::make_marker(), "dis" => Value::from("Test")};
// Verify that the filter matched the Dict assert_eq!(dict.filter(&filter), true);
```
The library provides support for JSON and Zinc encoding.
JSON is provided through the excellent Serde library, and Zinc is provided as a hand tuned decoder and encoder, with a performance oriented streaming lazy Grid rows parser.
rust
use libhaystack::val::*;
// Decode a `Str` haystack `Value` from JSON encoding
let value: Value = serde_json::from_str("'hello'").unwrap();
rust
use libhaystack::val::*;
use libhaystack::encoding::zinc::*;
// Decode a `Number` haystack `Value` from Zinc encoding
let value: Value = decode::from_str("42s").unwrap();
This library exposes a C based API that allows it to be consumed by other programming languages with a C FFI. The header file generation is done using cbindgen
Building the header file:
cbindgen --lang c -q --crate libhaystack --output src/c_api/libhaystack.h
By leveraging the C API, the function exposed can be called in browsers, Node.js, or Deno.
For this wasm-pack is used to generate the wasm binary file, the JS wrapper for initialization, and a typescript file with the API definitions.
wasm-pack build --out-dir wasm --target web