windows are range based
This commit is contained in:
parent
ae0f10b48c
commit
487dd03713
4 changed files with 95 additions and 51 deletions
|
|
@ -1,10 +1,10 @@
|
|||
use crate::{
|
||||
DataRef, DisplayBitVec, Grid, GridMut, Payload, ValueGrid, Window,
|
||||
WindowMut, PIXEL_HEIGHT, PIXEL_WIDTH,
|
||||
containers::absolute_bounds_to_abs_range, DataRef, DisplayBitVec, Grid,
|
||||
GridMut, Payload, ValueGrid, Window, WindowMut, PIXEL_HEIGHT, PIXEL_WIDTH,
|
||||
};
|
||||
use ::bitvec::{order::Msb0, prelude::BitSlice, slice::IterMut};
|
||||
use inherent::inherent;
|
||||
use std::ops::{Index, Range};
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
/// A fixed-size 2D grid of booleans.
|
||||
///
|
||||
|
|
@ -184,9 +184,11 @@ impl Bitmap {
|
|||
#[must_use]
|
||||
pub fn window(
|
||||
&self,
|
||||
xs: Range<usize>,
|
||||
ys: Range<usize>,
|
||||
xs: impl RangeBounds<usize>,
|
||||
ys: impl RangeBounds<usize>,
|
||||
) -> Option<Window<bool, Self>> {
|
||||
let xs = absolute_bounds_to_abs_range(xs, self.width)?;
|
||||
let ys = absolute_bounds_to_abs_range(ys, self.height)?;
|
||||
Window::new(self, xs, ys)
|
||||
}
|
||||
|
||||
|
|
@ -195,9 +197,11 @@ impl Bitmap {
|
|||
/// Returns None in case the window does not fit.
|
||||
pub fn window_mut(
|
||||
&mut self,
|
||||
xs: Range<usize>,
|
||||
ys: Range<usize>,
|
||||
xs: impl RangeBounds<usize>,
|
||||
ys: impl RangeBounds<usize>,
|
||||
) -> Option<WindowMut<bool, Self>> {
|
||||
let xs = absolute_bounds_to_abs_range(xs, self.width)?;
|
||||
let ys = absolute_bounds_to_abs_range(ys, self.height)?;
|
||||
WindowMut::new(self, xs, ys)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,3 +22,43 @@ pub use value_grid::{
|
|||
Value, ValueGrid,
|
||||
};
|
||||
pub use window::{Window, WindowMut};
|
||||
|
||||
use std::{
|
||||
collections::Bound,
|
||||
ops::{Range, RangeBounds},
|
||||
};
|
||||
|
||||
pub(crate) fn absolute_bounds_to_abs_range(
|
||||
bounds: impl RangeBounds<usize>,
|
||||
len: usize,
|
||||
) -> Option<Range<usize>> {
|
||||
let start = match bounds.start_bound() {
|
||||
Bound::Included(start) => *start,
|
||||
Bound::Excluded(start) => start + 1,
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
|
||||
let end = match bounds.end_bound() {
|
||||
Bound::Included(end) => end + 1,
|
||||
Bound::Excluded(end) => *end,
|
||||
Bound::Unbounded => len,
|
||||
};
|
||||
if end > len {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(start..end)
|
||||
}
|
||||
|
||||
pub(crate) fn relative_bounds_to_abs_range(
|
||||
bounds: impl RangeBounds<usize>,
|
||||
range: Range<usize>,
|
||||
) -> Option<Range<usize>> {
|
||||
let relative = absolute_bounds_to_abs_range(bounds, range.len())?;
|
||||
let start = range.start + relative.start;
|
||||
let end = range.start + relative.end;
|
||||
if end > range.end {
|
||||
return None;
|
||||
}
|
||||
Some(start..end)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use crate::{DataRef, Grid, GridMut, Window, WindowMut};
|
||||
use crate::{
|
||||
containers::absolute_bounds_to_abs_range, DataRef, Grid, GridMut, Window,
|
||||
WindowMut,
|
||||
};
|
||||
use inherent::inherent;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
ops::Range,
|
||||
ops::RangeBounds,
|
||||
slice::{Iter, IterMut},
|
||||
};
|
||||
|
||||
|
|
@ -320,9 +323,11 @@ impl<T: Value> ValueGrid<T> {
|
|||
/// Returns None in case the window does not fit.
|
||||
pub fn window(
|
||||
&self,
|
||||
xs: Range<usize>,
|
||||
ys: Range<usize>,
|
||||
xs: impl RangeBounds<usize>,
|
||||
ys: impl RangeBounds<usize>,
|
||||
) -> Option<Window<T, Self>> {
|
||||
let xs = absolute_bounds_to_abs_range(xs, self.width)?;
|
||||
let ys = absolute_bounds_to_abs_range(ys, self.height)?;
|
||||
Window::new(self, xs, ys)
|
||||
}
|
||||
|
||||
|
|
@ -331,9 +336,11 @@ impl<T: Value> ValueGrid<T> {
|
|||
/// Returns None in case the window does not fit.
|
||||
pub fn window_mut(
|
||||
&mut self,
|
||||
xs: Range<usize>,
|
||||
ys: Range<usize>,
|
||||
xs: impl RangeBounds<usize>,
|
||||
ys: impl RangeBounds<usize>,
|
||||
) -> Option<WindowMut<T, Self>> {
|
||||
let xs = absolute_bounds_to_abs_range(xs, self.width)?;
|
||||
let ys = absolute_bounds_to_abs_range(ys, self.height)?;
|
||||
WindowMut::new(self, xs, ys)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,15 @@
|
|||
use crate::{
|
||||
containers::char_grid::{CharGridExt, CharGridMutExt},
|
||||
containers::{
|
||||
absolute_bounds_to_abs_range,
|
||||
char_grid::{CharGridExt, CharGridMutExt},
|
||||
relative_bounds_to_abs_range,
|
||||
},
|
||||
Grid, GridMut,
|
||||
};
|
||||
use std::{marker::PhantomData, ops::Range};
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
ops::{Range, RangeBounds},
|
||||
};
|
||||
|
||||
macro_rules! define_window {
|
||||
($name:ident, $grid:ty) => {
|
||||
|
|
@ -26,13 +33,11 @@ macro_rules! define_window {
|
|||
#[allow(unused, reason = "False positive because of #[inherent]")]
|
||||
pub fn new(
|
||||
grid: $grid,
|
||||
xs: Range<usize>,
|
||||
ys: Range<usize>,
|
||||
xs: impl RangeBounds<usize>,
|
||||
ys: impl RangeBounds<usize>,
|
||||
) -> Option<Self> {
|
||||
if !grid.is_in_bounds(xs.end - 1, ys.end - 1) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let xs = absolute_bounds_to_abs_range(xs, grid.width())?;
|
||||
let ys = absolute_bounds_to_abs_range(ys, grid.height())?;
|
||||
Some(Self {
|
||||
grid,
|
||||
xs,
|
||||
|
|
@ -47,18 +52,12 @@ macro_rules! define_window {
|
|||
/// Returns None in case the window does not fit.
|
||||
pub fn window(
|
||||
&self,
|
||||
xs: Range<usize>,
|
||||
ys: Range<usize>,
|
||||
xs: impl RangeBounds<usize>,
|
||||
ys: impl RangeBounds<usize>,
|
||||
) -> Option<Window<TElement, TGrid>> {
|
||||
if !self.is_in_bounds(xs.end - 1, ys.end - 1) {
|
||||
return None;
|
||||
}
|
||||
Window::new(
|
||||
self.grid,
|
||||
// TODO off by one
|
||||
(self.xs.start + xs.start)..(self.xs.end + xs.end),
|
||||
(self.ys.start + ys.start)..(self.ys.end + ys.end),
|
||||
)
|
||||
let xs = relative_bounds_to_abs_range(xs, self.xs.clone())?;
|
||||
let ys = relative_bounds_to_abs_range(ys, self.ys.clone())?;
|
||||
Window::new(self.grid, xs, ys)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
@ -159,18 +158,12 @@ impl<TElement: Copy, TGrid: GridMut<TElement>> WindowMut<'_, TElement, TGrid> {
|
|||
/// Returns None in case the window does not fit.
|
||||
pub fn window_mut(
|
||||
&mut self,
|
||||
xs: Range<usize>,
|
||||
ys: Range<usize>,
|
||||
xs: impl RangeBounds<usize>,
|
||||
ys: impl RangeBounds<usize>,
|
||||
) -> Option<WindowMut<TElement, TGrid>> {
|
||||
if self.is_in_bounds(xs.end - 1, ys.end - 1) {
|
||||
return None;
|
||||
}
|
||||
|
||||
WindowMut::new(
|
||||
self.grid,
|
||||
(self.xs.start + xs.start)..(self.xs.end + xs.end),
|
||||
(self.ys.start + ys.start)..(self.ys.end + ys.end),
|
||||
)
|
||||
let xs = relative_bounds_to_abs_range(xs, self.xs.clone())?;
|
||||
let ys = relative_bounds_to_abs_range(ys, self.ys.clone())?;
|
||||
WindowMut::new(self.grid, xs, ys)
|
||||
}
|
||||
|
||||
pub fn deref_assign<O: Grid<TElement>>(&mut self, other: &O) {
|
||||
|
|
@ -296,7 +289,7 @@ mod tests {
|
|||
#[test]
|
||||
fn split_horizontal() {
|
||||
let grid = ByteGrid::new(4, 5);
|
||||
let window = grid.window(0..grid.width(), 0..grid.height()).unwrap();
|
||||
let window = grid.window(.., ..).unwrap();
|
||||
|
||||
let (top, bottom) = window.split_horizontal(3).unwrap();
|
||||
assert_eq!(3, top.width());
|
||||
|
|
@ -311,23 +304,23 @@ mod tests {
|
|||
grid.fill(1);
|
||||
|
||||
let mut w1 = grid
|
||||
.window_mut(1..grid.width() - 2, 1..grid.height() - 2)
|
||||
.window_mut(1..grid.width() - 1, 1..grid.height() - 1)
|
||||
.unwrap();
|
||||
w1.fill(2);
|
||||
|
||||
let w1_1 = w1.window(0..w1.width(), 0..w1.height()).unwrap();
|
||||
let w1_1 = w1.window(.., ..).unwrap();
|
||||
assert_eq!(w1_1.get(0, 0), 2);
|
||||
|
||||
assert!(matches!(w1.window(0..w1.width(), 1..w1.height()), None));
|
||||
assert!(matches!(w1.window(.., 0..=w1.height()), None));
|
||||
|
||||
let mut w2 = w1
|
||||
.window_mut(1..w1.width() - 2, 1..w1.height() - 2)
|
||||
.window_mut(1..w1.width() - 1, 1..w1.height() - 1)
|
||||
.unwrap();
|
||||
w2.fill(3);
|
||||
|
||||
// zero-sized
|
||||
let mut w3 = w2
|
||||
.window_mut(1..w2.width() - 2, 1..w2.height() - 2)
|
||||
.window_mut(1..w2.width() - 1, 1..w2.height() - 1)
|
||||
.unwrap();
|
||||
w3.fill(4);
|
||||
|
||||
|
|
@ -349,10 +342,10 @@ mod tests {
|
|||
#[test]
|
||||
fn width_height() {
|
||||
let grid = ByteGrid::new(4, 4);
|
||||
let w1 = grid.window(0..grid.width(), 0..grid.height()).unwrap();
|
||||
let w1 = grid.window(0.., ..grid.height()).unwrap();
|
||||
assert_eq!(grid.width(), w1.width());
|
||||
assert_eq!(grid.height(), w1.height());
|
||||
let w2 = w1.window(0..w1.width(), 0..w1.height()).unwrap();
|
||||
let w2 = w1.window(.., 0..w1.height()).unwrap();
|
||||
assert_eq!(grid.width(), w2.width());
|
||||
assert_eq!(grid.height(), w2.height());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue