Haystack library
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.
Building
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)
Testing
Run unit and integration tests with cargo test
Docs
As usual, docs for the library are generate on docs.rs each time we publish.
Features
Types
The library fundamental type is Value. It can hold any of the Haystack supported data-types.
Scalar types
Create a Str
Value from a &str
use *;
// Creates a Str Value
let value = from;
// Get a std::String from the value
assert!;
Create a Number Value with a unit
use *;
use *;
// Creates a Number Value using the Value helper function
let a = make_number_unit;
// Creates the Number scalar
let b = make_with_unit;
// Add numbers with units
assert_eq!;
Complex types
Create a Haystack Dict
use *;
// Create the Dict type
let dict = from;
assert!;
assert_eq!;
// Wrap the type as a Value
let value: Value = dict.into;
assert!;
Filter
A Haystack 4 compliant filter parser and evaluator is provided that uses the ontology definitions from Project Haystack.
use dict;
use *;
use *;
// Parse the filter from a string
let filter = try_from.expect;
// Define a Dict to apply the filter against
let dict = dict!;
// Verify that the filter matched the Dict
assert_eq!;
// Filter using advanced ontology query
let filter = try_from.expect;
// Sites are [geoPlaces](https://project-haystack.org/doc/lib-phIoT/site)
let dict = dict!;
// Verify that the filter matched the Dict
assert_eq!;
Encoding
The library provides support for JSON, Zinc, Trio, and Brio encoding.
JSON is provided through the excellent Serde library. Zinc, Trio, and Brio are hand-tuned decoders and encoders built for performance.
Each format is opt-in via a cargo feature (json, zinc, trio, brio).
JSON
JSON encoding is provided through the excellent Serde library. All Haystack types implement Serialize and Deserialize.
use *;
use dict;
// Decode a Dict from Hayson (Haystack JSON) encoding
let json = r#"{"_kind":"dict","dis":{"_kind":"str","val":"Chiller Plant"},"site":{"_kind":"marker"}}"#;
let value: Value = from_str.expect;
let dict = try_from.expect;
assert_eq!;
use *;
use dict;
// Encode a Dict to Hayson JSON
let value = make_dict;
let json = to_string.expect;
println!;
// {"_kind":"dict","dis":{"_kind":"str","val":"Chiller Plant"},"site":{"_kind":"marker"}}
Zinc
Zinc is a human-readable text format with a performance-oriented streaming Grid parser.
use *;
use decode;
// Decode a Number with unit from Zinc encoding
let value: Value = from_str.expect;
assert_eq!;
use *;
use dict;
use to_zinc_string;
// Encode a Dict to Zinc
let value = make_dict;
let zinc = to_zinc_string.expect;
println!;
// {dis:"Chiller Plant",site:M}
Trio
Trio ("Text Record Input/Output") is a human-friendly plain-text format derived from YAML, used for hand-authoring Haystack records.
use *;
use TrioReader;
// Decode a sequence of dicts from Trio text
let trio = "dis: \"Chiller Plant\"\nsite\n---\ndis: \"AHU-1\"\nequip\n";
let dicts = dicts_from_str.expect;
assert_eq!;
use *;
use dict;
use TrioWriter;
// Encode a dict to Trio text
let mut writer = new;
writer.add_dict;
println!;
// dis: "Chiller Plant"
// site
Brio
Brio is a compact binary format used by the Haxall platform. It provides the most efficient serialization of all supported formats — benchmarks show it decoding ~43% faster than JSON and ~69% faster than Zinc on real-world point grids.
use *;
use dict;
use ToBrio;
use from_brio;
// Encode any Value to a compact binary Vec<u8>
let val = make_dict;
let bytes = val.to_brio_vec.expect;
// Decode back from a byte slice
let decoded = from_brio.expect;
assert_eq!;
C API
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.
Webassembly support
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