garray2d 0.4.1

Game development focused 2d array with signed index and offset support.
Documentation
use std::mem;

use mint::Vector2;

pub(crate) const ZERO: Vector2<i32> = Vector2 { x: 0, y: 0 };
pub(crate) const ONE: Vector2<i32> = Vector2 { x: 1, y: 1 };

#[track_caller]
pub(crate) const fn add(left: Vector2<i32>, right: Vector2<i32>) -> Vector2<i32> {
    Vector2 {
        x: left.x + right.x,
        y: left.y + right.y,
    }
}

#[track_caller]
pub(crate) const fn addu(left: Vector2<i32>, right: Vector2<u32>) -> Vector2<i32> {
    Vector2 {
        x: left.x.wrapping_add(right.x as i32),
        y: left.y.wrapping_add(right.y as i32),
    }
}

#[track_caller]
pub(crate) const fn sub(left: Vector2<i32>, right: Vector2<i32>) -> Vector2<i32> {
    Vector2 {
        x: left.x - right.x,
        y: left.y - right.y,
    }
}

#[track_caller]
pub(crate) fn vec_min(left: Vector2<i32>, right: Vector2<i32>) -> Vector2<i32> {
    Vector2 {
        x: left.x.min(right.x),
        y: left.y.min(right.y),
    }
}

#[track_caller]
pub(crate) fn vec_max(left: Vector2<i32>, right: Vector2<i32>) -> Vector2<i32> {
    Vector2 {
        x: left.x.max(right.x),
        y: left.y.max(right.y),
    }
}

#[track_caller]
pub(crate) const fn u2i(v: Vector2<u32>) -> Vector2<i32> {
    Vector2 {
        x: v.x as i32,
        y: v.y as i32,
    }
}

#[track_caller]
pub(crate) const fn i2u(v: Vector2<i32>) -> Vector2<u32> {
    Vector2 {
        x: if v.x > 0 { v.x as u32 } else { 0 },
        y: if v.y > 0 { v.y as u32 } else { 0 },
    }
}

#[track_caller]
pub(crate) const fn abs(v: Vector2<i32>) -> Vector2<i32> {
    Vector2 {
        x: v.x.abs(),
        y: v.y.abs(),
    }
}

#[inline]
#[track_caller]
pub const fn offset_of(pos: Vector2<i32>, origin: Vector2<i32>, pitch: usize) -> usize {
    let pos = sub(pos, origin);
    pos.y as usize * pitch + pos.x as usize
}

#[inline]
#[track_caller]
pub fn move_within<T: Default>(slice: &mut [T], from: usize, to: usize, len: usize) {
    if from == to {
    } else if to < from || from + len <= to {
        for i in 0..len {
            slice[to + i] = mem::take(&mut slice[from + i]);
        }
    } else {
        for i in (0..len).rev() {
            slice[to + i] = mem::take(&mut slice[from + i]);
        }
    }
}

pub struct DimensionIter {
    position: Vector2<u32>,
    dimension: Vector2<u32>,
}

impl DimensionIter {
    pub fn new(dimension: Vector2<u32>) -> Self {
        DimensionIter {
            position: Vector2 { x: 0, y: 0 },
            dimension,
        }
    }
}

impl Iterator for DimensionIter {
    type Item = Vector2<i32>;

    fn next(&mut self) -> Option<Self::Item> {
        let out = self.position;
        if self.position.y >= self.dimension.y {
            return None;
        }
        self.position.x += 1;
        if self.position.x >= self.dimension.x {
            self.position.x = 0;
            self.position.y += 1;
        }
        Some(u2i(out))
    }
}

pub(crate) struct IterOwned<T> {
    pub iter: T,
    pub position: Vector2<u32>,
    pub dimension: Vector2<u32>,
    pub pitch: u32,
}

impl<T: Iterator> Iterator for IterOwned<T> {
    type Item = (Vector2<i32>, T::Item);

    fn next(&mut self) -> Option<Self::Item> {
        if self.position.y >= self.dimension.y {
            return None;
        }
        let out = (u2i(self.position), self.iter.next()?);
        self.position.x += 1;
        if self.position.x >= self.dimension.x {
            self.position.x = 0;
            self.position.y += 1;
            for _ in self.dimension.x..self.pitch {
                let _ = self.iter.next();
            }
        }
        Some(out)
    }
}