#haystack #iot #bas

libhaystack

Rust implementation of the Haystack 4 data types, defs, filter, units, and encodings

14 stable releases

1.0.14 Feb 26, 2024
1.0.13 Nov 17, 2023
1.0.12 Sep 6, 2023
1.0.11 Jun 13, 2023
0.9.9 Feb 20, 2022

#100 in Encoding

Download history 394/week @ 2024-02-12 316/week @ 2024-02-19 537/week @ 2024-02-26 502/week @ 2024-03-04 330/week @ 2024-03-11 353/week @ 2024-03-18 141/week @ 2024-03-25 355/week @ 2024-04-01 247/week @ 2024-04-08 394/week @ 2024-04-15 246/week @ 2024-04-22 439/week @ 2024-04-29 406/week @ 2024-05-06 436/week @ 2024-05-13 386/week @ 2024-05-20 246/week @ 2024-05-27

1,478 downloads per month
Used in logic-mesh

BSD-3-Clause

655KB
17K SLoC

GitHub CI crates.io License

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 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

use libhaystack::val::*;
use libhaystack::units::*;

// Creates a Number Value using the Value helper function
let a = Value::make_number_unit(42, get_unit(""));

// Creates the Number scalar
let b = Number::make_with_unit(100.0, "".into());

// Add numbers with units
assert_eq!(Number::try_form(a).expect("Number") + b, Number::make_with_unit(142.0, get_unit("")));

Complex types

Create a Haystack Dict

use libhaystack::val::*;

// Create the Dict type
let dict = Value::from(dict! {
    "site" => Value::make_marker(),
    "name" => Value::make_str("Foo")
});

assert!(dict.has("site"));
assert_eq!(dict_value.get_str("name"), Some(&"Foo".into()));

// Wrap the type as a Value
let value: Value = dict.into();
assert!(value.is_dict());

Filter

A Haystack 4 compliant filter parser and evaluator is provided that uses the ontology definitions from Project Haystack.

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](https://project-haystack.org/doc/lib-phIoT/site)
let dict = dict!{"site" => Value::make_marker(), "dis" => Value::from("Test")};

// Verify that the filter matched the Dict
assert_eq!(dict.filter(&filter), true);

Encoding

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.

use libhaystack::val::*;
// Decode a `Str` haystack `Value` from JSON encoding
let value: Value = serde_json::from_str("'hello'").unwrap();
use libhaystack::val::*;
use libhaystack::encoding::zinc::*;
// Decode a `Number` haystack `Value` from Zinc encoding
let value: Value = decode::from_str("42s").unwrap();

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

Dependencies

~5–14MB
~155K SLoC