Grid9 Rust Implementation
The Rust implementation of Grid9 combines memory safety with maximum performance. With comprehensive error handling using Result types and zero-allocation design, it's perfect for systems programming, WebAssembly, and safety-critical applications.
Key Features: Memory safe by design • Zero allocations • Result-based error handling • WebAssembly ready • Serde integration • No unsafe code • Comprehensive documentation
Installation
Cargo Package
# Add to Cargo.toml
[dependencies]
grid9 = "1.0.0"
# Install via cargo
cargo add grid9
# Install with Serde support
grid9 = { version = "1.0.0", features = ["serde"] }
From Source
git clone https://github.com/pedrof69/Grid9.git
cd Grid9/rust
cargo build --release
Quick Start
Basic Usage
use grid9::{encode, decode, Grid9Error};
fn main() -> Result<(), Grid9Error> {
// Encode coordinates to Grid9 code
let code = encode(40.7128, -74.0060, false)?;
println!("Grid9 Code: {}", code); // "Q7KH2BBYF"
// Decode Grid9 code to coordinates
let (latitude, longitude) = decode(&code)?;
println!("Lat: {}, Lon: {}", latitude, longitude);
// Result: Lat: 40.712779, Lon: -74.005988
// Human-readable format
let readable = encode(40.7128, -74.0060, true)?;
println!("Human readable: {}", readable); // "Q7K-H2B-BYF"
Ok(())
}
Error Handling
use grid9::{encode, decode, Grid9Error};
fn safe_coordinate_processing(lat: f64, lon: f64) -> Result<String, Grid9Error> {
// Grid9 uses Result types for comprehensive error handling
match encode(lat, lon, false) {
Ok(code) => {
println!("Successfully encoded: {}", code);
// Verify by decoding
match decode(&code) {
Ok((decoded_lat, decoded_lon)) => {
println!("Decoded: {}, {}", decoded_lat, decoded_lon);
Ok(code)
},
Err(e) => {
eprintln!("Decode error: {}", e);
Err(e)
}
}
},
Err(Grid9Error::InvalidLatitude(lat)) => {
eprintln!("Invalid latitude: {}", lat);
Err(Grid9Error::InvalidLatitude(lat))
},
Err(Grid9Error::InvalidLongitude(lon)) => {
eprintln!("Invalid longitude: {}", lon);
Err(Grid9Error::InvalidLongitude(lon))
},
Err(e) => Err(e)
}
}
High-Performance Batch Processing
use grid9::coordinate_operations::{batch_encode, batch_decode};
use rayon::prelude::*; // For parallel processing
fn process_large_dataset(coordinates: Vec<(f64, f64)>) -> Vec<String> {
// Sequential batch processing
let codes: Result<Vec<String>, _> = batch_encode(&coordinates);
match codes {
Ok(codes) => {
println!("Encoded {} coordinates", codes.len());
codes
},
Err(e) => {
eprintln!("Batch encoding failed: {}", e);
Vec::new()
}
}
}
// Parallel processing for maximum performance
fn parallel_encode(coordinates: Vec<(f64, f64)>) -> Vec<Option<String>> {
coordinates.par_iter()
.map(|(lat, lon)| grid9::encode(*lat, *lon, false).ok())
.collect()
}
API Reference
Core Functions
| Function | Description | Returns |
|---|---|---|
encode(lat: f64, lon: f64, human_readable: bool) |
Encode coordinates to Grid9 code | Result<String, Grid9Error> |
decode(code: &str) |
Decode Grid9 code to coordinates | Result<(f64, f64), Grid9Error> |
calculate_distance(code1: &str, code2: &str) |
Calculate distance in meters | Result<f64, Grid9Error> |
get_neighbors(code: &str) |
Get adjacent Grid9 codes | Result<Vec<String>, Grid9Error> |
is_valid_encoding(code: &str) |
Validate Grid9 code format | bool |
get_actual_precision(lat: f64, lon: f64) |
Get precision information | Result<(f64, f64, f64), Grid9Error> |
Error Types
| Error | Description |
|---|---|
Grid9Error::InvalidLatitude(f64) |
Latitude outside -90 to 90 range |
Grid9Error::InvalidLongitude(f64) |
Longitude outside -180 to 180 range |
Grid9Error::InvalidCode(String) |
Malformed Grid9 code |
Grid9Error::InvalidLength |
Code length is not 9 or 11 characters |
Grid9Error::InvalidCharacter(char) |
Code contains invalid Base32 character |
Advanced Features
Serde Integration
use grid9::{encode, decode};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Location {
name: String,
grid9_code: String,
}
impl Location {
fn new(name: String, latitude: f64, longitude: f64) -> Result<Self, grid9::Grid9Error> {
let grid9_code = encode(latitude, longitude, false)?;
Ok(Location { name, grid9_code })
}
fn coordinates(&self) -> Result<(f64, f64), grid9::Grid9Error> {
decode(&self.grid9_code)
}
}
// JSON serialization
fn serialize_location() -> Result<String, Box<dyn std::error::Error>> {
let location = Location::new("New York".to_string(), 40.7128, -74.0060)?;
let json = serde_json::to_string(&location)?;
Ok(json)
}
WebAssembly Integration
use wasm_bindgen::prelude::*;
use grid9::{encode, decode};
#[wasm_bindgen]
pub struct Grid9Wasm;
#[wasm_bindgen]
impl Grid9Wasm {
#[wasm_bindgen]
pub fn encode(latitude: f64, longitude: f64, human_readable: bool) -> Result<String, JsValue> {
encode(latitude, longitude, human_readable)
.map_err(|e| JsValue::from_str(&e.to_string()))
}
#[wasm_bindgen]
pub fn decode(code: &str) -> Result<js_sys::Array, JsValue> {
match decode(code) {
Ok((lat, lon)) => {
let array = js_sys::Array::new();
array.push(&JsValue::from_f64(lat));
array.push(&JsValue::from_f64(lon));
Ok(array)
},
Err(e) => Err(JsValue::from_str(&e.to_string()))
}
}
}
// Build for WebAssembly
// wasm-pack build --target web
Async Processing
use tokio;
use grid9::{encode, decode};
use futures::stream::{self, StreamExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let coordinates = vec![
(40.7128, -74.0060),
(51.5074, -0.1278),
(35.6762, 139.6503),
];
// Process coordinates asynchronously
let codes: Vec<Result<String, _>> = stream::iter(coordinates)
.map(|(lat, lon)| async move {
// Simulate async processing (e.g., fetching from database)
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
encode(lat, lon, false)
})
.buffer_unordered(10) // Process up to 10 concurrently
.collect()
.await;
for (i, result) in codes.iter().enumerate() {
match result {
Ok(code) => println!("Location {}: {}", i + 1, code),
Err(e) => eprintln!("Error encoding location {}: {}", i + 1, e),
}
}
Ok(())
}
Performance
Encoding Speed
18M+ operations/second
Decoding Speed
22M+ operations/second
Memory Usage
Zero heap allocations
Benchmarking
# Run benchmarks with Criterion
cargo bench
# Run specific benchmark
cargo bench encode
# Generate benchmark report
cargo bench -- --output-format html
Profile-Guided Optimization
# Build with PGO for maximum performance
export RUSTFLAGS="-Cprofile-generate=/tmp/pgo-data"
cargo build --release
./target/release/examples/demo
export RUSTFLAGS="-Cprofile-use=/tmp/pgo-data -Cllvm-args=-pgo-warn-missing-function"
cargo build --release
Systems Programming Integration
Embedded Systems (no_std)
#![no_std]
#![no_main]
use grid9_no_std::{encode, decode}; // Hypothetical no_std version
use heapless::String; // Stack-allocated strings
#[no_mangle]
pub extern "C" fn process_gps_update(lat: f64, lon: f64) -> i32 {
let mut buffer: String<16> = String::new();
match encode(lat, lon, false) {
Ok(code) => {
// Process the Grid9 code in embedded context
buffer.push_str(&code).ok();
transmit_location(&buffer);
0 // Success
},
Err(_) => -1 // Error
}
}
fn transmit_location(code: &str) {
// Send via LoRa, satellite, etc.
}
FFI Integration
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use grid9::{encode, decode};
#[no_mangle]
pub extern "C" fn grid9_encode(
latitude: f64,
longitude: f64,
human_readable: bool
) -> *mut c_char {
match encode(latitude, longitude, human_readable) {
Ok(code) => {
match CString::new(code) {
Ok(c_string) => c_string.into_raw(),
Err(_) => std::ptr::null_mut(),
}
},
Err(_) => std::ptr::null_mut(),
}
}
#[no_mangle]
pub extern "C" fn grid9_decode(
code: *const c_char,
latitude: *mut f64,
longitude: *mut f64
) -> bool {
if code.is_null() || latitude.is_null() || longitude.is_null() {
return false;
}
let c_str = unsafe { CStr::from_ptr(code) };
let code_str = match c_str.to_str() {
Ok(s) => s,
Err(_) => return false,
};
match decode(code_str) {
Ok((lat, lon)) => {
unsafe {
*latitude = lat;
*longitude = lon;
}
true
},
Err(_) => false,
}
}
#[no_mangle]
pub extern "C" fn grid9_free_string(s: *mut c_char) {
if !s.is_null() {
unsafe {
let _ = CString::from_raw(s);
}
}
}
Testing
Unit Tests
# Run all tests
cargo test
# Run tests with output
cargo test -- --nocapture
# Run specific test
cargo test test_encode_decode
# Run tests with coverage
cargo tarpaulin --out Html
Property-Based Testing
use proptest::prelude::*;
use grid9::{encode, decode};
proptest! {
#[test]
fn encode_decode_roundtrip(
lat in -90.0f64..90.0f64,
lon in -180.0f64..180.0f64
) {
if let Ok(encoded) = encode(lat, lon, false) {
if let Ok((decoded_lat, decoded_lon)) = decode(&encoded) {
// Check that roundtrip preserves coordinates within precision
prop_assert!((lat - decoded_lat).abs() < 0.002);
prop_assert!((lon - decoded_lon).abs() < 0.002);
}
}
}
}
Integration Examples
Actix Web Server
use actix_web::{web, App, HttpServer, Result, HttpResponse};
use grid9::{encode, decode, Grid9Error};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct EncodeRequest {
latitude: f64,
longitude: f64,
}
#[derive(Serialize)]
struct EncodeResponse {
grid9_code: String,
}
#[derive(Serialize)]
struct DecodeResponse {
latitude: f64,
longitude: f64,
}
async fn encode_endpoint(req: web::Json<EncodeRequest>) -> Result<HttpResponse> {
match encode(req.latitude, req.longitude, false) {
Ok(code) => Ok(HttpResponse::Ok().json(EncodeResponse { grid9_code: code })),
Err(Grid9Error::InvalidLatitude(_)) => {
Ok(HttpResponse::BadRequest().json("Invalid latitude"))
},
Err(Grid9Error::InvalidLongitude(_)) => {
Ok(HttpResponse::BadRequest().json("Invalid longitude"))
},
Err(_) => Ok(HttpResponse::InternalServerError().json("Encoding failed")),
}
}
async fn decode_endpoint(path: web::Path<String>) -> Result<HttpResponse> {
let code = path.into_inner();
match decode(&code) {
Ok((lat, lon)) => Ok(HttpResponse::Ok().json(DecodeResponse {
latitude: lat,
longitude: lon,
})),
Err(_) => Ok(HttpResponse::BadRequest().json("Invalid Grid9 code")),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/encode", web::post().to(encode_endpoint))
.route("/decode/{code}", web::get().to(decode_endpoint))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Requirements
- Rust 1.56+ (2021 edition) ✓
- No external runtime dependencies
- Optional: Serde for serialization
- Optional: wasm-bindgen for WebAssembly
Cross-Compilation
# WebAssembly
cargo build --target wasm32-unknown-unknown
# ARM64
cargo build --target aarch64-unknown-linux-gnu
# Windows from Linux
cargo build --target x86_64-pc-windows-gnu
# macOS from Linux (with osxcross)
cargo build --target x86_64-apple-darwin
Need help? Check out the full source code and examples on GitHub or open an issue.