grid_trait 0.1.1

2D and 3D grids with combinators.
Documentation
//! Grid wrapping around edges.

use crate::{
    grid2::*,
    range::BoundRange,
};
use mint::Vector2;
use std::ops::RangeFull;


pub struct Grid2Wrapping<G> 
where
    G: Grid2,
    <G as Grid2>::XBound: BoundRange,
    <G as Grid2>::YBound: BoundRange,
{
    inner: G,
}

impl<G> Grid2Wrapping<G>
where
    G: Grid2,
    <G as Grid2>::XBound: BoundRange,
    <G as Grid2>::YBound: BoundRange,
{
    pub fn new(inner: G) -> Self {
        Grid2Wrapping {
            inner
        }
    }
    
    pub fn wrap_coord<I>(&self, coord: I) -> I 
    where
        I: From<Vector2<i32>> + Into<Vector2<i32>>
    {
        let Vector2 { mut x, mut y } = coord.into();
        
        let x_start = self.inner.x_bound().lower_inclusive();
        let x_end = self.inner.x_bound().upper_exclusive();
            
        let y_start = self.inner.y_bound().lower_inclusive();
        let y_end = self.inner.y_bound().upper_exclusive();
                
        let x_len = x_end - x_start;
        let y_len = y_end - y_start;
            
        x = ((((x - x_start) % x_len) + x_len) % x_len) + x_start;
        y = ((((y - y_start) % y_len) + y_len) % y_len) + y_start;
        
        I::from(Vector2 { x, y })
    }
}

impl<G> Grid2 for Grid2Wrapping<G>
where
    G: Grid2,
    <G as Grid2>::XBound: BoundRange,
    <G as Grid2>::YBound: BoundRange,
{
    type Item = <G as Grid2>::Item;
    type XBound = RangeFull;
    type YBound = RangeFull;
    
    fn x_bound(&self) -> RangeFull { RangeFull }
    fn y_bound(&self) -> RangeFull { RangeFull }
}

impl<G> Grid2Get for Grid2Wrapping<G> 
where
    G: Grid2 + Grid2Get,
    <G as Grid2>::XBound: BoundRange,
    <G as Grid2>::YBound: BoundRange,
{
    fn get<I>(&self, coord: I) -> Self::Item
    where
        I: Into<Vector2<i32>>
    {
        let coord = self.wrap_coord(coord.into());
        self.inner.get(coord)
    }
}

impl<G> Grid2Set for Grid2Wrapping<G> 
where
    G: Grid2 + Grid2Set,
    <G as Grid2>::XBound: BoundRange,
    <G as Grid2>::YBound: BoundRange,
{
    fn set<I>(&mut self, coord: I, elem: Self::Item)
    where
        I: Into<Vector2<i32>>
    {
        let coord = self.wrap_coord(coord.into());
        self.inner.set(coord, elem);
    }
}

impl<G> Grid2Ref for Grid2Wrapping<G> 
where
    G: Grid2 + Grid2Ref,
    <G as Grid2>::XBound: BoundRange,
    <G as Grid2>::YBound: BoundRange,
{
    fn idx<I>(&self, coord: I) -> &Self::Item
    where
        I: Into<Vector2<i32>>
    {
        let coord = self.wrap_coord(coord.into());
        self.inner.idx(coord)
    }
}

impl<G> Grid2Mut for Grid2Wrapping<G> 
where
    G: Grid2 + Grid2Mut,
    <G as Grid2>::XBound: BoundRange,
    <G as Grid2>::YBound: BoundRange,
{
    fn midx<I>(&mut self, coord: I) -> &mut Self::Item
    where
        I: Into<Vector2<i32>>
    {
        let coord = self.wrap_coord(coord.into());
        self.inner.midx(coord)
    }
}