plozone 0.1.2

3D spatial zone engine: geofencing, octree hole-scanning, realtime sync (WebSocket + QUIC + io_uring), voxel pathfinding, and AV sensor fusion.
Documentation
//! `no_std` zone store fallback (feature `embedded`).
//!
//! A linear-scan zone store for embedded / bare-metal targets where `rstar`
//! (which requires `std`) is unavailable. Suitable for < ~500 zones.

extern crate alloc;

use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;

use crate::zone::ZoneShape;

/// `no_std` zone store — linear scan, no R-tree.
pub struct ZoneStoreEmbed {
    zones: Vec<(u32, Box<dyn ZoneShape>)>,
}

impl ZoneStoreEmbed {
    pub fn new() -> Self {
        Self { zones: vec![] }
    }

    pub fn add(&mut self, id: u32, shape: Box<dyn ZoneShape>) {
        self.zones.retain(|(i, _)| *i != id);
        self.zones.push((id, shape));
    }

    pub fn remove(&mut self, id: u32) {
        self.zones.retain(|(i, _)| *i != id);
    }

    pub fn query_enu(&self, p: [f64; 3]) -> Vec<u32> {
        self.zones
            .iter()
            .filter(|(_, s)| s.contains_enu(p))
            .map(|(id, _)| *id)
            .collect()
    }

    pub fn len(&self) -> usize {
        self.zones.len()
    }

    pub fn is_empty(&self) -> bool {
        self.zones.is_empty()
    }
}

impl Default for ZoneStoreEmbed {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::zone::Zone;
    use crate::coord::EnuConverter;
    use crate::zone::zone_to_shape;

    #[test]
    fn embed_add_query_remove() {
        let conv = EnuConverter::new(0.0, 0.0, 0.0);
        let mut store = ZoneStoreEmbed::new();

        let shape = zone_to_shape(
            &Zone::Cylinder {
                center: [0.0, 0.0],
                radius_m: 10.0,
                z_min: 0.0,
                z_max: 5.0,
            },
            &conv,
        );
        store.add(1, shape);
        assert_eq!(store.query_enu([0.0, 0.0, 2.5]), vec![1]);
        assert!(store.query_enu([20.0, 0.0, 2.5]).is_empty());

        store.remove(1);
        assert!(store.is_empty());
    }
}