License: Apache 2.0

Rust

BGrid for Rust

A safe, idiomatic Rust implementation of the BGrid protocol. It provides strongly-typed conversions between geographic coordinates and BGrid indices with comprehensive error handling via Result types. The single-file library has minimal dependencies and is suitable for CLI tools, backend services, and WebAssembly targets.

Features

  • Minimal Dependencies: Only depends on serde_json for wordlist parsing.
  • Strongly Typed: All functions return Result<T, BGridError> with descriptive error variants.
  • Safe: No unsafe code; all operations are bounds-checked.
  • BIP39 Word Support: Encode and decode grid indices as human-readable words in 9 languages.
  • Cross-Platform: Works on any target supported by the Rust toolchain, including WASM.
  • Test Vector Parity: Passes the same test vectors as the JavaScript implementation.

Installation

Add bgrid to your Cargo.toml:

[dependencies]
bgrid = "0.1"

Or via the command line:

cargo add bgrid

Source repository:

git clone https://github.com/bgrid-maps/bgrid-rust.git

Quick Start

use std::path::Path;
use bgrid::{coords_to_bgrid, bgrid_to_cell, load_language, grid_to_display, DisplayMode};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Encode coordinates to BGrid indices
    let grid = coords_to_bgrid(40.7128, -74.0060, 3)?;
    println!("{:?}", grid); // [531, 1563, 1600]

    // Decode back to cell center and bounds
    let cell = bgrid_to_cell(&grid)?;
    println!("Center: ({}, {})", cell.lat, cell.lon);
    println!("Bounds: {:?}", cell.bounds);

    // Display as numbers
    let display = grid_to_display(&grid, DisplayMode::Numbers, None)?;
    println!("{}", display); // "531,1563,1600"

    // Display as BIP39 words
    let words = load_language("en", Path::new("bip39-wordlist"))?;
    let display = grid_to_display(&grid, DisplayMode::Words, Some(&words))?;
    println!("{}", display); // "word1,word2,word3"

    Ok(())
}

API Reference

Types

Cell

Represents a decoded BGrid cell with its center point and geographic bounds.

pub struct Cell {
    pub lat: f64,               // Center latitude
    pub lon: f64,               // Center longitude
    pub bounds: [[f64; 2]; 2],  // [[minLat, minLon], [maxLat, maxLon]]
}

GridCell

Represents a cell within a hierarchical grid query, including its full path.

pub struct GridCell {
    pub index: u16,             // Cell index at this level (1–2048)
    pub grid: Vec<u16>,         // Full grid path from root
    pub center: (f64, f64),     // (latitude, longitude)
    pub bounds: [[f64; 2]; 2],  // [[minLat, minLon], [maxLat, maxLon]]
}

DisplayMode

Controls the output format of grid_to_display.

pub enum DisplayMode {
    Numbers,  // Comma-separated numeric indices
    Words,    // Comma-separated BIP39 words
}

BGridError

Error type returned by all fallible functions.

pub enum BGridError {
    InvalidLatLon,            // lat/lon must be finite
    InvalidLevels,            // levels must be a positive integer
    InvalidGrid,              // bgrid array must be non-empty with valid indices
    InvalidLanguage(String),  // unsupported language code
    InvalidWords,             // word list must contain exactly 2048 entries
    MissingWords,             // word list required for Words display mode
    Io(String),               // file I/O error
    Json(String),             // JSON parsing error
}

Functions

coords_to_bgrid

Converts geographic coordinates to a BGrid index vector.

pub fn coords_to_bgrid(lat: f64, lon: f64, levels: usize) -> Result<Vec<u16>, BGridError>
ParameterTypeDescription
latf64Latitude (-90 to 90), must be finite
lonf64Longitude (-180 to 180), must be finite
levelsusizePositive integer for subdivision depth

Returns: Vec<u16> of 1-based grid indices (1–2048 per level).

Errors: InvalidLatLon if coordinates are not finite; InvalidLevels if levels is 0.


bgrid_to_cell

Converts a BGrid index slice back to geographic bounds and center.

pub fn bgrid_to_cell(bgrid: &[u16]) -> Result<Cell, BGridError>
ParameterTypeDescription
bgrid&[u16]Slice of grid indices (1–2048)

Returns: Cell with center coordinates and bounding box.

Errors: InvalidGrid if the slice is empty or contains out-of-range indices.


get_grid_cells

Generates all sub-cells for a given level under a parent grid.

pub fn get_grid_cells(
    level: usize,
    parent_grid: &[u16],
    max_level: usize,
) -> Result<Vec<GridCell>, BGridError>
ParameterTypeDescription
levelusizeTarget level (1+)
parent_grid&[u16]Parent grid path for sub-queries
max_levelusizeMaximum level to generate

Returns: Vec<GridCell> containing all cells at the specified level.


load_language

Loads a BIP39 wordlist from a JSON file on disk.

pub fn load_language(lang: &str, base_path: &Path) -> Result<Vec<String>, BGridError>
ParameterTypeDescription
lang&strLanguage code (e.g. "en", "es", "ja")
base_path&PathDirectory containing bip39-*.json files

Returns: Vec<String> of 2048 words.

Errors: InvalidLanguage if code is unsupported; Io / Json for file or parsing failures; InvalidWords if the list does not contain exactly 2048 entries.


number_to_word

Converts a single grid index to its BIP39 word.

pub fn number_to_word(number: u16, words: &[String]) -> Option<&str>
ParameterTypeDescription
numberu16Grid index (1–2048)
words&[String]Word list from load_language

Returns: Some(&str) with the word, or None if out of range.


word_to_number

Converts a BIP39 word to its grid index.

pub fn word_to_number(word: &str, words: &[String]) -> Option<u16>
ParameterTypeDescription
word&strBIP39 word (case-insensitive lookup)
words&[String]Word list from load_language

Returns: Some(u16) with the 1-based index, or None if not found.


grid_to_display

Formats a grid index slice as a display string.

pub fn grid_to_display(
    grid: &[u16],
    mode: DisplayMode,
    words: Option<&[String]>,
) -> Result<String, BGridError>
ParameterTypeDescription
grid&[u16]Slice of grid indices
modeDisplayModeNumbers or Words
wordsOption<&[String]>Required when mode is Words

Returns: Comma-separated string.

Errors: MissingWords if mode is Words and no word list provided; InvalidWords if list is not 2048 entries.

Constants

SUPPORTED_LANGS

pub const SUPPORTED_LANGS: [&str; 9]

Array of supported language codes: ["cs", "en", "es", "fr", "it", "ja", "ko", "pt", "zh"].

BIP39 Word Support

The library supports 9 languages for BIP39 word encoding:

cs, en, es, fr, it, ja, ko, pt, zh

Word lists are loaded from JSON files via load_language(). Each file must contain a JSON array of exactly 2048 strings.

Resources