more tests, move stuff

This commit is contained in:
Vinzenz Schroeter 2024-06-05 20:14:05 +02:00
parent 9a4987787e
commit b08fd97066
4 changed files with 95 additions and 106 deletions

View file

@ -1,6 +1,5 @@
use std::slice::{Iter, IterMut}; use std::slice::{Iter, IterMut};
use crate::grid::RefGrid;
use crate::{DataRef, Grid}; use crate::{DataRef, Grid};
/// A 2D grid of bytes /// A 2D grid of bytes
@ -53,7 +52,7 @@ impl ByteGrid {
/// # let grid = ByteGrid::new(2,2); /// # let grid = ByteGrid::new(2,2);
/// for y in 0..grid.height() { /// for y in 0..grid.height() {
/// for x in 0..grid.width() { /// for x in 0..grid.width() {
/// grid.get(x, y) /// grid.get(x, y);
/// } /// }
/// } /// }
/// ``` /// ```
@ -76,17 +75,37 @@ impl ByteGrid {
self.data.iter_mut() self.data.iter_mut()
} }
fn check_indexes(&self, x: usize, y: usize) { /// Get a mutable reference to the current value at the specified position.
assert!( ///
x < self.width, /// # Arguments
"cannot access byte {x}-{y} because x is outside of bounds 0..{}", ///
self.width /// * `x` and `y`: position of the cell
); ///
assert!( /// # Panics
y < self.height, ///
"cannot access byte {x}-{y} because y is outside of bounds 0..{}", /// When accessing `x` or `y` out of bounds.
self.height pub fn get_ref_mut(&mut self, x: usize, y: usize) -> &mut u8 {
); self.assert_in_bounds(x, y);
&mut self.data[x + y * self.width]
}
/// Get a mutable reference to the current value at the specified position if position is in bounds.
///
/// # Arguments
///
/// * `x` and `y`: position of the cell
///
/// returns: Reference to cell or None
pub fn get_ref_mut_optional(
&mut self,
x: isize,
y: isize,
) -> Option<&mut u8> {
if self.is_in_bounds(x, y) {
Some(&mut self.data[x as usize + y as usize * self.width])
} else {
None
}
} }
} }
@ -102,7 +121,7 @@ impl Grid<u8> for ByteGrid {
/// ///
/// When accessing `x` or `y` out of bounds. /// When accessing `x` or `y` out of bounds.
fn set(&mut self, x: usize, y: usize, value: u8) { fn set(&mut self, x: usize, y: usize, value: u8) {
self.check_indexes(x, y); self.assert_in_bounds(x, y);
self.data[x + y * self.width] = value; self.data[x + y * self.width] = value;
} }
@ -116,7 +135,7 @@ impl Grid<u8> for ByteGrid {
/// ///
/// When accessing `x` or `y` out of bounds. /// When accessing `x` or `y` out of bounds.
fn get(&self, x: usize, y: usize) -> u8 { fn get(&self, x: usize, y: usize) -> u8 {
self.check_indexes(x, y); self.assert_in_bounds(x, y);
self.data[x + y * self.width] self.data[x + y * self.width]
} }
@ -152,34 +171,6 @@ impl From<ByteGrid> for Vec<u8> {
} }
} }
impl RefGrid<u8> for ByteGrid {
fn get_ref(&self, x: usize, y: usize) -> &u8 {
self.check_indexes(x, y);
&self.data[x + y * self.width]
}
fn get_ref_optional(&self, x: isize, y: isize) -> Option<&u8> {
if self.is_in_bounds(x, y) {
Some(&self.data[x as usize + y as usize * self.width])
} else {
None
}
}
fn get_ref_mut(&mut self, x: usize, y: usize) -> &mut u8 {
self.check_indexes(x, y);
&mut self.data[x + y * self.width]
}
fn get_ref_mut_optional(&mut self, x: isize, y: isize) -> Option<&mut u8> {
if self.is_in_bounds(x, y) {
Some(&mut self.data[x as usize + y as usize * self.width])
} else {
None
}
}
}
pub struct IterRows<'t> { pub struct IterRows<'t> {
byte_grid: &'t ByteGrid, byte_grid: &'t ByteGrid,
row: usize, row: usize,
@ -302,4 +293,15 @@ mod tests {
let vec = ByteGrid::load(2, 2, &[0, 1, 2, 3]); let vec = ByteGrid::load(2, 2, &[0, 1, 2, 3]);
vec.get(1, 2); vec.get(1, 2);
} }
#[test]
fn ref_mut() {
let mut vec = ByteGrid::load(2, 2, &[0, 1, 2, 3]);
let top_left = vec.get_ref_mut(0, 0);
*top_left += 5;
assert_eq!(None, vec.get_ref_mut_optional(2, 2));
assert_eq!(Some(&mut 5), vec.get_ref_mut_optional(0, 0));
}
} }

View file

@ -62,54 +62,29 @@ pub trait Grid<T> {
/// the height in y-direction /// the height in y-direction
fn height(&self) -> usize; fn height(&self) -> usize;
/// Checks whether the specified position is /// Checks whether the specified signed position is in grid bounds
fn is_in_bounds(&self, x: isize, y: isize) -> bool { fn is_in_bounds(&self, x: isize, y: isize) -> bool {
x > 0 x >= 0
&& x < self.width() as isize && x < self.width() as isize
&& y > 0 && y >= 0
&& y < self.height() as isize && y < self.height() as isize
} }
}
/// A grid that can return cells as references. /// Asserts that the specified unsigned position is in grid bounds.
pub trait RefGrid<T> {
/// Get a reference to the current value at the specified position
///
/// # Arguments
///
/// * `x` and `y`: position of the cell
/// ///
/// # Panics /// # Panics
/// ///
/// When accessing `x` or `y` out of bounds. /// When the specified position is out of bounds for this grid.
fn get_ref(&self, x: usize, y: usize) -> &T; fn assert_in_bounds(&self, x: usize, y: usize) {
assert!(
/// Get a reference to the current value at the specified position if the position is in bounds. x < self.width(),
/// "cannot access index [{x}, {y}] because x is outside of bounds 0..{}",
/// # Arguments self.width()
/// );
/// * `x` and `y`: position of the cell assert!(
/// y < self.height(),
/// returns: Reference to cell or None "cannot access byte [{x}, {y}] because y is outside of bounds 0..{}",
fn get_ref_optional(&self, x: isize, y: isize) -> Option<&T>; self.height()
);
/// Get a mutable reference to the current value at the specified position }
///
/// # Arguments
///
/// * `x` and `y`: position of the cell
///
/// # Panics
///
/// When accessing `x` or `y` out of bounds.
fn get_ref_mut(&mut self, x: usize, y: usize) -> &mut T;
/// Get a mutable reference to the current value at the specified position if position is in bounds.
///
/// # Arguments
///
/// * `x` and `y`: position of the cell
///
/// returns: Reference to cell or None
fn get_ref_mut_optional(&mut self, x: isize, y: isize) -> Option<&mut T>;
} }

View file

@ -2,16 +2,17 @@
use std::time::Duration; use std::time::Duration;
pub use bitvec;
use bitvec::prelude::{BitVec, Msb0};
pub use crate::byte_grid::ByteGrid; pub use crate::byte_grid::ByteGrid;
pub use crate::command::{Brightness, Command, Offset, Origin}; pub use crate::command::{Brightness, Command, Offset, Origin};
pub use crate::compression_code::CompressionCode; pub use crate::compression_code::CompressionCode;
pub use crate::connection::Connection; pub use crate::connection::Connection;
pub use crate::data_ref::DataRef; pub use crate::data_ref::DataRef;
pub use crate::grid::{Grid, RefGrid}; pub use crate::grid::Grid;
pub use crate::packet::{Header, Packet, Payload}; pub use crate::packet::{Header, Packet, Payload};
pub use crate::pixel_grid::PixelGrid; pub use crate::pixel_grid::PixelGrid;
pub use bitvec;
use bitvec::prelude::{BitVec, Msb0};
type SpBitVec = BitVec<u8, Msb0>; type SpBitVec = BitVec<u8, Msb0>;

View file

@ -1,6 +1,5 @@
use bitvec::order::Msb0; use bitvec::order::Msb0;
use bitvec::prelude::BitSlice; use bitvec::prelude::BitSlice;
use bitvec::ptr::Mutability;
use bitvec::slice::IterMut; use bitvec::slice::IterMut;
use crate::{BitVec, DataRef, Grid, SpBitVec, PIXEL_HEIGHT, PIXEL_WIDTH}; use crate::{BitVec, DataRef, Grid, SpBitVec, PIXEL_HEIGHT, PIXEL_WIDTH};
@ -73,7 +72,7 @@ impl PixelGrid {
/// # let grid = PixelGrid::new(8,2); /// # let grid = PixelGrid::new(8,2);
/// for y in 0..grid.height() { /// for y in 0..grid.height() {
/// for x in 0..grid.width() { /// for x in 0..grid.width() {
/// grid.get(x, y) /// grid.get(x, y);
/// } /// }
/// } /// }
/// ``` /// ```
@ -90,7 +89,7 @@ impl PixelGrid {
/// # let value = false; /// # let value = false;
/// for y in 0..grid.height() { /// for y in 0..grid.height() {
/// for x in 0..grid.width() { /// for x in 0..grid.width() {
/// grid.set(x, y, value) /// grid.set(x, y, value);
/// } /// }
/// } /// }
/// ``` /// ```
@ -115,19 +114,6 @@ impl PixelGrid {
row: 0, row: 0,
} }
} }
fn check_indexes(&self, x: usize, y: usize) {
assert!(
x < self.width,
"cannot access pixel {x}-{y} because x is outside of bounds 0..{}",
self.width
);
assert!(
y < self.height,
"cannot access pixel {x}-{y} because y is outside of bounds 0..{}",
self.height
);
}
} }
impl Grid<bool> for PixelGrid { impl Grid<bool> for PixelGrid {
@ -144,12 +130,12 @@ impl Grid<bool> for PixelGrid {
/// ///
/// When accessing `x` or `y` out of bounds. /// When accessing `x` or `y` out of bounds.
fn set(&mut self, x: usize, y: usize, value: bool) { fn set(&mut self, x: usize, y: usize, value: bool) {
self.check_indexes(x, y); self.assert_in_bounds(x, y);
self.bit_vec.set(x + y * self.width, value) self.bit_vec.set(x + y * self.width, value)
} }
fn get(&self, x: usize, y: usize) -> bool { fn get(&self, x: usize, y: usize) -> bool {
self.check_indexes(x, y); self.assert_in_bounds(x, y);
self.bit_vec[x + y * self.width] self.bit_vec[x + y * self.width]
} }
@ -270,4 +256,29 @@ mod tests {
let mut vec = PixelGrid::new(8, 2); let mut vec = PixelGrid::new(8, 2);
vec.set(1, 2, false); vec.set(1, 2, false);
} }
#[test]
fn iter() {
let grid = PixelGrid::new(8, 2);
assert_eq!(16, grid.iter().count())
}
#[test]
fn iter_rows() {
let grid = PixelGrid::load(8, 2, &[0x04, 0x40]);
let mut iter = grid.iter_rows();
assert_eq!(iter.next().unwrap().count_ones(), 1);
assert_eq!(iter.next().unwrap().count_ones(), 1);
assert_eq!(None, iter.next());
}
#[test]
fn iter_mut() {
let mut grid = PixelGrid::new(8, 2);
for (index, mut pixel) in grid.iter_mut().enumerate() {
pixel.set(index % 2 == 0);
}
assert_eq!(grid.data_ref(), [0xAA, 0xAA]);
}
} }