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

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.

View on GitHub Back to Home