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.
This implementation is geared towards constructing high performance haystack application that can also run efficiently on constrained devices, for a more general implementation, J2 Innovations provides a TypeScript implementation also. At the moment, 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
As usual, docs for the library are generate on docs.rs each time we publish.
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
Please consult the pre-generated header file distributed within the repo.
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