Crate vestaboard

Source
Expand description

§vestaboard-rs

vestaboard-rs is a VBML (Vestaboard Markup Language) parser and api client for the Vestaboard. It supports the v2 read/write api, subscription api, and local api.

the full docs can be found at https://docs.rs/vestaboard

§features

  • VBML parser
  • read/write api
  • subscription api
  • local api
  • serialization and deserialization of Vestaboard messages
  • async/await
  • support for multiple Vestaboard sizes (if another size is released)

§installation

cargo add vestaboard -F full

§feature flags

  • full: enables all features
  • parser: enables the VBML parser (Vestaboard Markup Language) (default)
  • rw: enables the read/write api
  • subscription: enables the subscription api
  • local: enables the local api

§helpful type and structs

  • board::FLAGSHIP_ROWS and board::FLAGSHIP_COLS: the dimensions of the flagship Vestaboard
  • board::Board<ROWS, COLS>: a type equivalent to [[u8; COLS]; ROWS] which represents a Vestaboard state
  • BoardData<ROWS, COLS>: a struct that wraps a Board<ROWS, COLS> and has several helper methods
  • VBML: a struct that represents a VBML message and can be parsed into a BoardData<ROWS, COLS>
  • Vestaboard<Config>: the main struct that is used to interact with the Vestaboard api

§VBML usage

with ROWS and COLS specified:

let string = "{\"props\":{},\"style\":{},\"components\":[]}"; // any valid VBML string
let vbml: Vbml<6, 22> = string.parse().unwrap();

let board_data: Result<BoardData<6, 22>, VbmlError> = vbml.parse();

when ROWS and COLS are not specified, the default is board::FLAGSHIP_ROWS and board::FLAGSHIP_COLS:

let string = "{\"props\":{},\"style\":{},\"components\":[]}"; // any valid VBML string
let vbml: Vbml = string.parse().unwrap();

let board_data: Result<BoardData, VbmlError> = vbml.parse();

§api usage

use vestaboard::{Vestaboard, RWConfig, SubscriptionConfig, LocalConfig};

#[tokio::main]
async fn main() {
  let rw_config = RWConfig { read_write_key: "<YOUR_RW_API_KEY>" };
  let rw_api: Vestaboard<RWConfig> = Vestaboard::new_rw_api(rw_config);

  let subscription_config = SubscriptionConfig {
    api_key: "<YOUR_SUBSCRIPTION_API_KEY>",
    api_secret: "<YOUR_SUBSCRIPTION_API_SECRET>",
  };
  let subscription_api: Vestaboard<SubscriptionConfig> = Vestaboard::new_subscription_api(subscription_config);

  let local_config = LocalConfig {
    api_key: "<YOUR_LOCAL_API_KEY>",
    host: "<YOUR_VESTABOARD_IP_ADDRESS>",
  };
  let local_api: Vestaboard<LocalConfig> = Vestaboard::new_local_api(local_config);
}

(note that you must have the Vestaboard<Config> type specified due to this rust issue)

§read/write api

use vestaboard::{Vestaboard, RWConfig};

#[tokio::main]
async fn main() {
  let rw_config = RWConfig { read_write_key: "<YOUR_RW_API_KEY>" };
  let rw_api: Vestaboard<RWConfig> = Vestaboard::new_rw_api(rw_config);

  let message: Result<RWApiReadMessage, RWApiError> = rw_api.read().await;
  let write_res: Result<String, RWApiError> = rw_api.write(BoardData<ROWS, COLS>).await;
}

§subscription api

use vestaboard::{Vestaboard, SubscriptionConfig};

#[tokio::main]
async fn main() {
  let subscription_config = SubscriptionConfig {
    api_key: "<YOUR_SUBSCRIPTION_API_KEY>",
    api_secret: "<YOUR_SUBSCRIPTION_API_SECRET>",
  };
  let subscription_api: Vestaboard<SubscriptionConfig> = Vestaboard::new_subscription_api(subscription_config);

  let subscriptions: Result<SubscriptionsList, SubscriptionApiError> = subscription_api.get_subscriptions().await;
  let write_res: Result<SubscriptionMessageResponse, SubscriptionApiError> = subscription_api.write(BoardData<ROWS, COLS>).await;
}

§local api

use vestaboard::{Vestaboard, LocalConfig};

#[tokio::main]
async fn main() {
  // if you have not enabled the local api, you can use the following method to do so.
  // note that the local api can only be enabled once per board, so make sure to save
  // the resulting api key. to get the enablement token, visit https://www.vestaboard.com/local-api
  let local_api_enablement: Result<String, LocalApiError> = Vestaboard.get_local_api_key(
      Some("<YOUR_VESTABOARD_IP_ADDRESS>".parse().unwrap()),
      "<YOUR_LOCAL_API_ENABLEMENT_KEY>",
    ).await;

  let local_config = LocalConfig {
    api_key: "<YOUR_LOCAL_API_KEY>",
    ip_address: "<YOUR_VESTABOARD_IP_ADDRESS>".parse().unwrap(),
  };

  let local_api: Vestaboard<LocalConfig> = Vestaboard::new_local_api(local_config);

  let message: Result<BoardData<ROWS, COLS>, LocalApiError> = local_api.read().await;
  let write_res: Result<(), LocalApiError> = local_api.write(BoardData<ROWS, COLS>).await;
}

§benchmarks

this library is set up to be benchmarked against the official JavaScript VBML parsing library. benchmarks can be run using just with the following command:

just bench

on a Ryzen 9 7950X on Arch Linux with Node v18.20.0 and rustc 1.77.2, the benchmark results are as follows:

test namejs μs/itrs μs/itdifference% faster
Default Template21.23μs0.40μs-20.83μs5,338%
Half Height Center19.07μs0.40μs-18.68μs4,792%
Justify Left18.33μs0.39μs-17.94μs4,669%
Justify Right19.07μs0.39μs-18.68μs4,838%
Justify Center21.23μs0.39μs-20.84μs5,483%
Justify Justified20.11μs0.39μs-19.73μs5,192%
Align Center21.43μs0.39μs-21.05μs5,535%
Align Top18.98μs0.39μs-18.58μs4,812%
Align Bottom21.39μs0.39μs-21.00μs5,511%
Align Justified21.36μs0.39μs-20.97μs5,415%
Justify Justified Align Justified20.11μs0.38μs-19.73μs5,277%
Split Align Justify24.49μs0.42μs-24.08μs5,897%
Uneven Split23.85μs0.41μs-23.43μs5,770%
Uneven Split 221.64μs0.35μs-21.29μs6,244%
Rev Split Align Justify24.55μs0.42μs-24.13μs5,850%
Two Column21.61μs0.35μs-21.26μs6,153%
All Justified27.32μs0.42μs-26.90μs6,490%
Justified Right15.76μs0.24μs-15.51μs6,438%
Centered Right15.69μs0.24μs-15.45μs6,472%
2x2x2x2 Grid37.68μs0.76μs-36.91μs4,933%
2x2 Neighbors18.90μs0.37μs-18.53μs5,046%
Plain Text13.44μs0.24μs-13.20μs5,564%
Centered17.02μs0.24μs-16.78μs7,055%
Newline16.02μs0.26μs-15.76μs6,230%
Character Codes227.70μs17.94μs-209.77μs1,270%
Character Codes with Characters34.43μs1.52μs-32.91μs2,269%
Dynamic Props14.48μs0.65μs-13.82μs2,223%
Dynamic Props with Character Codes17.75μs1.13μs-16.62μs1,571%
Multiple Components49.01μs2.34μs-46.68μs2,099%
Raw Characters0.90μs0.04μs-0.86μs2,126%
Absolute Position Components24.33μs0.73μs-23.60μs3,311%
Complex Layout with Multiple Components70.41μs1.95μs-68.46μs3,619%
Complex Layout with Multiple Components 276.98μs2.12μs-74.86μs3,634%
Diff Height Components Newline30.00μs0.60μs-29.41μs5,028%
JS Spec: Absolute Layout18.19μs0.32μs-17.87μs5,714%
JS Spec: Absolute Layout 218.15μs0.32μs-17.83μs5,704%
JS Spec: Absolute and Raw Components12.08μs0.48μs-11.59μs2,496%

there is definitely further room for optimization, but the current performance is decent.

Re-exports§

pub use board::BoardData;
pub use board::CharacterCode;
pub use local::LocalApiError;local
pub use local::LocalConfig;local
pub use rw::RWApiError;rw
pub use rw::RWApiReadMessage;rw
pub use rw::RWApiWriteResponse;rw
pub use rw::RWConfig;rw
pub use subscription::SubscriptionApiError;subscription
pub use subscription::SubscriptionConfig;subscription
pub use subscription::SubscriptionMessageResponse;subscription
pub use subscription::SubscriptionsList;subscription
pub use vbml::Vbml;parser

Modules§

board
module for working with Vestaboard board representations.
locallocal
local api (requires the local feature)
rwrw
Vestaboard Read/Write api (requires the rw feature)
subscriptionsubscription
Vestaboard subscription api (requires the subscription feature)
vbmlparser
VBML Parser (requires parser feature)

Structs§

Vestaboardrw or subscription or local
the main struct for interacting with the Vestaboard api.
can interact with the r/w api, the subscription api, or the local api.