remove load_utf8, move methods to trait
Some checks failed
Rust / build (pull_request) Failing after 1m7s
Some checks failed
Rust / build (pull_request) Failing after 1m7s
This commit is contained in:
parent
e45d41e8b1
commit
bbd1d643b9
8 changed files with 304 additions and 282 deletions
|
|
@ -285,43 +285,23 @@ impl From<Bitmap> for DisplayBitVec {
|
|||
impl TryFrom<&ValueGrid<bool>> for Bitmap {
|
||||
type Error = ();
|
||||
|
||||
/// Converts a grid of [bool]s into a [Bitmap].
|
||||
///
|
||||
/// Returns Err if the width of `value` is not dividable by 8
|
||||
fn try_from(value: &ValueGrid<bool>) -> Result<Self, Self::Error> {
|
||||
let mut result = Self::new(value.width(), value.height()).ok_or(())?;
|
||||
for (mut to, from) in result.iter_mut().zip(value.iter()) {
|
||||
*to = *from;
|
||||
}
|
||||
result.deref_assign(value);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Grid<bool>> TryFrom<&Window<'_, bool, G>> for Bitmap {
|
||||
impl<T: Grid<bool>> TryFrom<&Window<'_, bool, T>> for Bitmap {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: &Window<'_, bool, G>) -> Result<Self, Self::Error> {
|
||||
fn try_from(value: &Window<bool, T>) -> Result<Self, Self::Error> {
|
||||
let mut result = Self::new(value.width(), value.height()).ok_or(())?;
|
||||
for y in 0..value.height() {
|
||||
for x in 0..value.width() {
|
||||
result.set(x, y, value.get(x, y));
|
||||
}
|
||||
}
|
||||
result.deref_assign(value);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Bitmap> for ValueGrid<bool> {
|
||||
/// Converts a [Bitmap] into a grid of [bool]s.
|
||||
fn from(value: &Bitmap) -> Self {
|
||||
let mut result = Self::new(value.width(), value.height());
|
||||
for (to, from) in result.iter_mut().zip(value.iter()) {
|
||||
*to = *from;
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Bitmap> for Payload {
|
||||
fn from(value: &Bitmap) -> Self {
|
||||
value.bit_vec.as_raw_slice().into()
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ mod tests {
|
|||
let mut grid = BrightnessGrid::new(2, 2);
|
||||
grid.set(1, 0, Brightness::MIN);
|
||||
grid.set(0, 1, Brightness::MAX);
|
||||
let actual = ValueGrid::from(&grid);
|
||||
let actual: ValueGrid<u8> = ValueGrid::from(&grid);
|
||||
assert_eq!(actual.data_ref(), &[11, 0, 11, 11]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use crate::{
|
||||
Grid, GridMut, SetValueSeriesError, TryLoadValueGridError, ValueGrid,
|
||||
};
|
||||
use crate::{CharGridMutExt, TryLoadValueGridError, ValueGrid};
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
/// A grid containing UTF-8 characters.
|
||||
|
|
@ -60,179 +58,10 @@ impl CharGrid {
|
|||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Loads a [`CharGrid`] with the specified dimensions from the provided UTF-8 bytes.
|
||||
///
|
||||
/// returns: [`CharGrid`] that contains the provided data, or [`FromUtf8Error`] if the data is invalid.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use servicepoint::CharGrid;
|
||||
/// let grid = CharGrid::load_utf8(2, 2, [97u8, 98, 99, 100].to_vec());
|
||||
/// ```
|
||||
pub fn load_utf8(
|
||||
width: usize,
|
||||
height: usize,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<CharGrid, LoadUtf8Error> {
|
||||
let s: Vec<char> = String::from_utf8(bytes)?.chars().collect();
|
||||
CharGrid::load(width, height, &s).ok_or(LoadUtf8Error::TryLoadError(
|
||||
TryLoadValueGridError::InvalidDimensions,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CharGridExt: Grid<char> {
|
||||
/// Copies a column from the grid as a String.
|
||||
///
|
||||
/// Returns [None] if x is out of bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use servicepoint::CharGrid;
|
||||
/// let grid = CharGrid::from("ab\ncd");
|
||||
/// let col = grid.get_col_str(0).unwrap(); // "ac"
|
||||
/// ```
|
||||
#[must_use]
|
||||
fn get_col_str(&self, x: usize) -> Option<String> {
|
||||
Some((0..self.height()).map(|y| self.get(x, y)).collect())
|
||||
}
|
||||
|
||||
/// Copies a row from the grid as a String.
|
||||
///
|
||||
/// Returns [None] if y is out of bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use servicepoint::CharGrid;
|
||||
/// let grid = CharGrid::from("ab\ncd");
|
||||
/// let row = grid.get_row_str(0).unwrap(); // "ab"
|
||||
/// ```
|
||||
#[must_use]
|
||||
fn get_row_str(&self, y: usize) -> Option<String> {
|
||||
Some((0..self.width()).map(|x| self.get(x, y)).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[inherent::inherent]
|
||||
impl CharGridExt for CharGrid {
|
||||
#[must_use]
|
||||
pub fn get_col_str(&self, x: usize) -> Option<String> {
|
||||
Some(String::from_iter(self.get_col(x)?))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_row_str(&self, y: usize) -> Option<String> {
|
||||
Some(String::from_iter(self.get_row(y)?))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CharGridMutExt: GridMut<char> {
|
||||
/// Overwrites a row in the grid with a str.
|
||||
///
|
||||
/// Returns [`SetValueSeriesError`] if y is out of bounds or `row` is not of the correct size.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use servicepoint::{CharGrid, CharGridMutExt};
|
||||
/// let mut grid = CharGrid::from("ab\ncd");
|
||||
/// grid.set_row_str(0, "ef").unwrap();
|
||||
/// ```
|
||||
fn set_row_str(
|
||||
&mut self,
|
||||
y: usize,
|
||||
value: &str,
|
||||
) -> Result<(), SetValueSeriesError> {
|
||||
let width = self.width();
|
||||
|
||||
let len = value.len();
|
||||
if len > width {
|
||||
return Err(SetValueSeriesError::InvalidLength {
|
||||
actual: len,
|
||||
expected: width,
|
||||
});
|
||||
}
|
||||
|
||||
let height = self.height();
|
||||
if y >= height {
|
||||
return Err(SetValueSeriesError::OutOfBounds {
|
||||
index: y,
|
||||
size: height,
|
||||
});
|
||||
}
|
||||
|
||||
let chars = value.chars().take(width);
|
||||
for (x, c) in chars.enumerate() {
|
||||
self.set(x, y, c);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Overwrites a column in the grid with a str.
|
||||
///
|
||||
/// Returns [`SetValueSeriesError`] if y is out of bounds or `row` is not of the correct size.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use servicepoint::CharGrid;
|
||||
/// let mut grid = CharGrid::from("ab\ncd");
|
||||
/// grid.set_col_str(0, "ef").unwrap();
|
||||
/// ```
|
||||
fn set_col_str(
|
||||
&mut self,
|
||||
x: usize,
|
||||
value: &str,
|
||||
) -> Result<(), SetValueSeriesError> {
|
||||
let height = self.height();
|
||||
|
||||
let len = value.len();
|
||||
if len > height {
|
||||
return Err(SetValueSeriesError::InvalidLength {
|
||||
actual: len,
|
||||
expected: height,
|
||||
});
|
||||
}
|
||||
|
||||
let width = self.width();
|
||||
if x >= width {
|
||||
return Err(SetValueSeriesError::OutOfBounds {
|
||||
index: x,
|
||||
size: width,
|
||||
});
|
||||
}
|
||||
|
||||
let chars = value.chars().take(height);
|
||||
for (y, c) in chars.enumerate() {
|
||||
self.set(x, y, c);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inherent::inherent]
|
||||
impl CharGridMutExt for CharGrid {
|
||||
pub fn set_col_str(
|
||||
&mut self,
|
||||
x: usize,
|
||||
value: &str,
|
||||
) -> Result<(), SetValueSeriesError>;
|
||||
|
||||
pub fn set_row_str(
|
||||
&mut self,
|
||||
y: usize,
|
||||
value: &str,
|
||||
) -> Result<(), SetValueSeriesError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum LoadUtf8Error {
|
||||
enum LoadUtf8Error {
|
||||
#[error(transparent)]
|
||||
FromUtf8Error(#[from] FromUtf8Error),
|
||||
#[error(transparent)]
|
||||
|
|
@ -308,7 +137,7 @@ impl From<&CharGrid> for Vec<u8> {
|
|||
/// let grid = CharGrid::from("ab\ncd");
|
||||
/// let height = grid.height();
|
||||
/// let width = grid.width();
|
||||
/// let grid = CharGrid::load_utf8(width, height, grid.into());
|
||||
/// let bytes = Vec::<u8>::from(grid);
|
||||
/// ```
|
||||
fn from(value: &CharGrid) -> Self {
|
||||
value.iter().collect::<String>().into_bytes()
|
||||
|
|
@ -325,6 +154,8 @@ impl From<CharGrid> for Vec<u8> {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::{CharGridExt, SetValueSeriesError};
|
||||
|
||||
#[test]
|
||||
fn col_str() {
|
||||
let mut grid = CharGrid::new(2, 3);
|
||||
|
|
@ -364,8 +195,15 @@ mod test {
|
|||
fn round_trip_bytes() {
|
||||
let grid = CharGrid::from("Hello\0\nWorld!\n...\0\0\0");
|
||||
let bytes: Vec<u8> = grid.clone().into();
|
||||
let copy =
|
||||
CharGrid::load_utf8(grid.width(), grid.height(), bytes).unwrap();
|
||||
let copy = CharGrid::load(
|
||||
grid.width(),
|
||||
grid.height(),
|
||||
&String::from_utf8(bytes)
|
||||
.unwrap()
|
||||
.chars()
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(grid, copy);
|
||||
}
|
||||
|
||||
|
|
|
|||
145
src/containers/char_grid_ext.rs
Normal file
145
src/containers/char_grid_ext.rs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
use crate::{Grid, GridMut, SetValueSeriesError};
|
||||
|
||||
/// Extension methods for any [`Grid<char>`]
|
||||
pub trait CharGridExt {
|
||||
/// Copies a column from the grid as a String.
|
||||
///
|
||||
/// Returns [None] if x is out of bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use servicepoint::{CharGrid, CharGridExt};
|
||||
/// let grid = CharGrid::from("ab\ncd");
|
||||
/// let col = grid.get_col_str(0).unwrap(); // "ac"
|
||||
/// ```
|
||||
#[must_use]
|
||||
fn get_col_str(&self, x: usize) -> Option<String>;
|
||||
|
||||
/// Copies a row from the grid as a String.
|
||||
///
|
||||
/// Returns [None] if y is out of bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use servicepoint::{CharGrid, CharGridExt};
|
||||
/// let grid = CharGrid::from("ab\ncd");
|
||||
/// let row = grid.get_row_str(0).unwrap(); // "ab"
|
||||
/// ```
|
||||
#[must_use]
|
||||
fn get_row_str(&self, y: usize) -> Option<String>;
|
||||
}
|
||||
|
||||
/// Extension methods for any [`GridMut<char>`].
|
||||
pub trait CharGridMutExt {
|
||||
/// Overwrites a row in the grid with a str.
|
||||
///
|
||||
/// Returns [`SetValueSeriesError`] if y is out of bounds or `row` is not of the correct size.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use servicepoint::{CharGrid, CharGridMutExt};
|
||||
/// let mut grid = CharGrid::from("ab\ncd");
|
||||
/// grid.set_row_str(0, "ef").unwrap();
|
||||
/// ```
|
||||
fn set_row_str(
|
||||
&mut self,
|
||||
y: usize,
|
||||
value: &str,
|
||||
) -> Result<(), SetValueSeriesError>;
|
||||
|
||||
/// Overwrites a column in the grid with a str.
|
||||
///
|
||||
/// Returns [`SetValueSeriesError`] if y is out of bounds or `row` is not of the correct size.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use servicepoint::{CharGrid, CharGridMutExt};
|
||||
/// let mut grid = CharGrid::from("ab\ncd");
|
||||
/// grid.set_col_str(0, "ef").unwrap();
|
||||
/// ```
|
||||
fn set_col_str(
|
||||
&mut self,
|
||||
x: usize,
|
||||
value: &str,
|
||||
) -> Result<(), SetValueSeriesError>;
|
||||
}
|
||||
|
||||
impl<G: Grid<char>> CharGridExt for G {
|
||||
#[must_use]
|
||||
fn get_col_str(&self, x: usize) -> Option<String> {
|
||||
Some(String::from_iter(self.get_col(x)?))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn get_row_str(&self, y: usize) -> Option<String> {
|
||||
Some(String::from_iter(self.get_row(y)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: GridMut<char>> CharGridMutExt for G {
|
||||
fn set_row_str(
|
||||
&mut self,
|
||||
y: usize,
|
||||
value: &str,
|
||||
) -> Result<(), SetValueSeriesError> {
|
||||
let width = self.width();
|
||||
|
||||
let len = value.len();
|
||||
if len > width {
|
||||
return Err(SetValueSeriesError::InvalidLength {
|
||||
actual: len,
|
||||
expected: width,
|
||||
});
|
||||
}
|
||||
|
||||
let height = self.height();
|
||||
if y >= height {
|
||||
return Err(SetValueSeriesError::OutOfBounds {
|
||||
index: y,
|
||||
size: height,
|
||||
});
|
||||
}
|
||||
|
||||
let chars = value.chars().take(width);
|
||||
for (x, c) in chars.enumerate() {
|
||||
self.set(x, y, c);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_col_str(
|
||||
&mut self,
|
||||
x: usize,
|
||||
value: &str,
|
||||
) -> Result<(), SetValueSeriesError> {
|
||||
let height = self.height();
|
||||
|
||||
let len = value.len();
|
||||
if len > height {
|
||||
return Err(SetValueSeriesError::InvalidLength {
|
||||
actual: len,
|
||||
expected: height,
|
||||
});
|
||||
}
|
||||
|
||||
let width = self.width();
|
||||
if x >= width {
|
||||
return Err(SetValueSeriesError::OutOfBounds {
|
||||
index: x,
|
||||
size: width,
|
||||
});
|
||||
}
|
||||
|
||||
let chars = value.chars().take(height);
|
||||
for (y, c) in chars.enumerate() {
|
||||
self.set(x, y, c);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +53,40 @@ pub trait Grid<T> {
|
|||
let height = self.height();
|
||||
assert!(y < height, "cannot access index [{x}, {y}] because y is outside of bounds [0..{height})");
|
||||
}
|
||||
|
||||
/// Copies a row from the grid.
|
||||
///
|
||||
/// Returns [None] if y is out of bounds.
|
||||
#[must_use]
|
||||
fn get_row(&self, y: usize) -> Option<Vec<T>> {
|
||||
if y >= self.height() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let width = self.width();
|
||||
let mut row = Vec::with_capacity(width);
|
||||
for x in 0..width {
|
||||
row.push(self.get(x, y));
|
||||
}
|
||||
Some(row)
|
||||
}
|
||||
|
||||
/// Copies a column from the grid.
|
||||
///
|
||||
/// Returns [None] if x is out of bounds.
|
||||
#[must_use]
|
||||
fn get_col(&self, x: usize) -> Option<Vec<T>> {
|
||||
if x >= self.width() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let height = self.height();
|
||||
let mut col = Vec::with_capacity(height);
|
||||
for y in 0..height {
|
||||
col.push(self.get(x, y));
|
||||
}
|
||||
Some(col)
|
||||
}
|
||||
}
|
||||
|
||||
/// A two-dimensional mutable grid of `T`
|
||||
|
|
@ -87,4 +121,33 @@ pub trait GridMut<T>: Grid<T> {
|
|||
|
||||
/// Sets all cells in the grid to the specified value
|
||||
fn fill(&mut self, value: T);
|
||||
|
||||
/// Fills the grid with the values from the provided grid.
|
||||
///
|
||||
/// The grids have to match in size exactly.
|
||||
///
|
||||
/// For 1D slices the equivalent would be `*slice = other_slice`.
|
||||
fn deref_assign<O: Grid<T>>(&mut self, other: &O) {
|
||||
let width = self.width();
|
||||
let height = self.height();
|
||||
assert_eq!(
|
||||
width,
|
||||
other.width(),
|
||||
"Cannot assign grid of width {} to a window of width {}",
|
||||
other.width(),
|
||||
self.width()
|
||||
);
|
||||
assert_eq!(
|
||||
height,
|
||||
other.height(),
|
||||
"Cannot assign grid of height {} to a height of width {}",
|
||||
other.height(),
|
||||
self.height()
|
||||
);
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
self.set(x, y, other.get(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ mod bitmap;
|
|||
mod brightness_grid;
|
||||
mod byte_grid;
|
||||
mod char_grid;
|
||||
mod char_grid_ext;
|
||||
mod cp437_grid;
|
||||
mod data_ref;
|
||||
mod grid;
|
||||
|
|
@ -13,13 +14,13 @@ pub use bit_vec::{bitvec, DisplayBitVec};
|
|||
pub use bitmap::{Bitmap, LoadBitmapError};
|
||||
pub use brightness_grid::BrightnessGrid;
|
||||
pub use byte_grid::ByteGrid;
|
||||
pub use char_grid::{CharGrid, CharGridExt, CharGridMutExt, LoadUtf8Error};
|
||||
pub use char_grid::CharGrid;
|
||||
pub use char_grid_ext::{CharGridExt, CharGridMutExt};
|
||||
pub use cp437_grid::{Cp437Grid, InvalidCharError};
|
||||
pub use data_ref::DataRef;
|
||||
pub use grid::{Grid, GridMut};
|
||||
pub use value_grid::{
|
||||
EnumerateGrid, IterGridRows, SetValueSeriesError, TryLoadValueGridError,
|
||||
Value, ValueGrid,
|
||||
SetValueSeriesError, TryLoadValueGridError, Value, ValueGrid,
|
||||
};
|
||||
pub use window::{Window, WindowMut};
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ impl<T: Value> ValueGrid<T> {
|
|||
}
|
||||
|
||||
/// Iterate over all rows in [`ValueGrid`] top to bottom.
|
||||
pub fn iter_rows(&self) -> IterGridRows<T> {
|
||||
pub fn iter_rows(&self) -> impl Iterator<Item = Iter<T>> + use<'_, T> {
|
||||
IterGridRows { grid: self, row: 0 }
|
||||
}
|
||||
|
||||
|
|
@ -224,28 +224,6 @@ impl<T: Value> ValueGrid<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Copies a row from the grid.
|
||||
///
|
||||
/// Returns [None] if y is out of bounds.
|
||||
#[must_use]
|
||||
pub fn get_row(&self, y: usize) -> Option<Vec<T>> {
|
||||
self.data
|
||||
.chunks_exact(self.width())
|
||||
.nth(y)
|
||||
.map(<[T]>::to_vec)
|
||||
}
|
||||
|
||||
/// Copies a column from the grid.
|
||||
///
|
||||
/// Returns [None] if x is out of bounds.
|
||||
#[must_use]
|
||||
pub fn get_col(&self, x: usize) -> Option<Vec<T>> {
|
||||
self.data
|
||||
.chunks_exact(self.width())
|
||||
.map(|row| row.get(x).copied())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Overwrites a column in the grid.
|
||||
///
|
||||
/// Returns [Err] if x is out of bounds or `col` is not of the correct size.
|
||||
|
|
@ -432,9 +410,19 @@ impl<T: Value> From<&ValueGrid<T>> for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Value, G: Grid<T>> From<&G> for ValueGrid<T> {
|
||||
fn from(grid: &G) -> Self {
|
||||
let width = grid.width();
|
||||
let height = grid.height();
|
||||
let mut result = Self::new(width, height);
|
||||
result.deref_assign(grid);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator iver the rows in a [`ValueGrid`]
|
||||
#[must_use]
|
||||
pub struct IterGridRows<'t, T: Value> {
|
||||
struct IterGridRows<'t, T: Value> {
|
||||
grid: &'t ValueGrid<T>,
|
||||
row: usize,
|
||||
}
|
||||
|
|
@ -455,7 +443,7 @@ impl<'t, T: Value> Iterator for IterGridRows<'t, T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct EnumerateGrid<'t, T: Value> {
|
||||
struct EnumerateGrid<'t, T: Value> {
|
||||
grid: &'t ValueGrid<T>,
|
||||
row: usize,
|
||||
column: usize,
|
||||
|
|
@ -480,18 +468,6 @@ impl<T: Value> Iterator for EnumerateGrid<'_, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: Value> From<&Window<'_, E, Self>> for ValueGrid<E> {
|
||||
fn from(value: &Window<'_, E, Self>) -> Self {
|
||||
let mut result = Self::new(value.width(), value.height());
|
||||
for y in 0..value.height() {
|
||||
for x in 0..value.width() {
|
||||
result.set(x, y, value.get(x, y));
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{SetValueSeriesError, ValueGrid, *};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
use crate::{
|
||||
containers::{
|
||||
absolute_bounds_to_abs_range,
|
||||
char_grid::{CharGridExt, CharGridMutExt},
|
||||
relative_bounds_to_abs_range,
|
||||
},
|
||||
containers::{absolute_bounds_to_abs_range, relative_bounds_to_abs_range},
|
||||
Grid, GridMut,
|
||||
};
|
||||
use std::{
|
||||
|
|
@ -62,7 +58,7 @@ macro_rules! define_window {
|
|||
|
||||
#[must_use]
|
||||
pub fn split_horizontal(
|
||||
self,
|
||||
&'t self,
|
||||
left_width: usize,
|
||||
) -> Option<(
|
||||
Window<'t, TElement, TGrid>,
|
||||
|
|
@ -75,14 +71,17 @@ macro_rules! define_window {
|
|||
self.xs.start..middle_abs,
|
||||
self.ys.clone(),
|
||||
)?;
|
||||
let right =
|
||||
Window::new(self.grid, middle_abs..self.xs.end, self.ys)?;
|
||||
let right = Window::new(
|
||||
self.grid,
|
||||
middle_abs..self.xs.end,
|
||||
self.ys.clone(),
|
||||
)?;
|
||||
Some((left, right))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn split_vertical(
|
||||
self,
|
||||
&'t self,
|
||||
top_height: usize,
|
||||
) -> Option<(
|
||||
Window<'t, TElement, TGrid>,
|
||||
|
|
@ -95,8 +94,11 @@ macro_rules! define_window {
|
|||
self.xs.clone(),
|
||||
self.ys.start..middle_abs,
|
||||
)?;
|
||||
let bottom =
|
||||
Window::new(self.grid, self.xs, middle_abs..self.ys.end)?;
|
||||
let bottom = Window::new(
|
||||
self.grid,
|
||||
self.xs.clone(),
|
||||
middle_abs..self.ys.end,
|
||||
)?;
|
||||
Some((top, bottom))
|
||||
}
|
||||
}
|
||||
|
|
@ -123,9 +125,6 @@ macro_rules! define_window {
|
|||
self.ys.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[inherent::inherent]
|
||||
impl<TGrid: Grid<char>> CharGridExt for $name<'_, char, TGrid> {}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -151,9 +150,6 @@ impl<TElement: Copy, TGrid: GridMut<TElement>> GridMut<TElement>
|
|||
}
|
||||
}
|
||||
|
||||
#[inherent::inherent]
|
||||
impl<TGrid: GridMut<char>> CharGridMutExt for WindowMut<'_, char, TGrid> {}
|
||||
|
||||
impl<TElement: Copy, TGrid: GridMut<TElement>> WindowMut<'_, TElement, TGrid> {
|
||||
/// Creates a mutable window into the grid.
|
||||
///
|
||||
|
|
@ -168,40 +164,47 @@ impl<TElement: Copy, TGrid: GridMut<TElement>> WindowMut<'_, TElement, TGrid> {
|
|||
WindowMut::new(self.grid, xs, ys)
|
||||
}
|
||||
|
||||
pub fn deref_assign<O: Grid<TElement>>(&mut self, other: &O) {
|
||||
let width = self.width();
|
||||
let height = self.height();
|
||||
assert_eq!(width, other.width(), "Cannot assign grid of width {} to a window of width {}", other.width(), self.width());
|
||||
assert_eq!(height, other.height(), "Cannot assign grid of height {} to a height of width {}", other.height(), self.height());
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
self.set(x, y, other.get(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn split_horizontal_mut(
|
||||
self,
|
||||
pub fn split_horizontal_mut<'t>(
|
||||
&'t mut self,
|
||||
left_width: usize,
|
||||
) -> Option<(Self, Self)> {
|
||||
) -> Option<(
|
||||
WindowMut<'t, TElement, TGrid>,
|
||||
WindowMut<'t, TElement, TGrid>,
|
||||
)> {
|
||||
assert!(left_width <= self.width());
|
||||
let (grid1, grid2) = unsafe { Self::duplicate_mutable_ref(self.grid) };
|
||||
let (grid1, grid2): (&'t mut TGrid, &'t mut TGrid) =
|
||||
unsafe { Self::duplicate_mutable_ref(self.grid) };
|
||||
let middle_abs = self.xs.start + left_width;
|
||||
let left =
|
||||
WindowMut::new(grid1, self.xs.start..middle_abs, self.ys.clone())?;
|
||||
let right = WindowMut::new(grid2, middle_abs..self.xs.end, self.ys)?;
|
||||
let right =
|
||||
WindowMut::new(grid2, middle_abs..self.xs.end, self.ys.clone())?;
|
||||
Some((left, right))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn split_vertical_mut(self, top_height: usize) -> Option<(Self, Self)> {
|
||||
pub fn split_vertical_mut<'t>(
|
||||
&'t mut self,
|
||||
top_height: usize,
|
||||
) -> Option<(
|
||||
WindowMut<'t, TElement, TGrid>,
|
||||
WindowMut<'t, TElement, TGrid>,
|
||||
)> {
|
||||
assert!(top_height <= self.height());
|
||||
let (grid1, grid2) = unsafe { Self::duplicate_mutable_ref(self.grid) };
|
||||
let (grid1, grid2): (&'t mut TGrid, &'t mut TGrid) =
|
||||
unsafe { Self::duplicate_mutable_ref(self.grid) };
|
||||
let middle_abs = self.ys.start + top_height;
|
||||
let top =
|
||||
WindowMut::new(grid1, self.xs.clone(), self.ys.start..middle_abs)?;
|
||||
let bottom = WindowMut::new(grid2, self.xs, middle_abs..self.ys.end)?;
|
||||
let top = WindowMut::<'t>::new(
|
||||
grid1,
|
||||
self.xs.clone(),
|
||||
self.ys.start..middle_abs,
|
||||
)?;
|
||||
let bottom = WindowMut::<'t>::new(
|
||||
grid2,
|
||||
self.xs.clone(),
|
||||
middle_abs..self.ys.end,
|
||||
)?;
|
||||
Some((top, bottom))
|
||||
}
|
||||
|
||||
|
|
@ -361,7 +364,23 @@ mod tests {
|
|||
let mut grid = ByteGrid::new(5, 5);
|
||||
grid.fill(1);
|
||||
|
||||
assert_eq!((0..5).len(), 5);
|
||||
//let mut w1 = grid
|
||||
let mut win = grid.window_mut(.., ..).unwrap();
|
||||
let (mut top, mut bottom) = win.split_vertical_mut(2).unwrap();
|
||||
let (mut left, mut right) = bottom.split_horizontal_mut(2).unwrap();
|
||||
|
||||
top.fill(2);
|
||||
left.fill(3);
|
||||
right.fill(4);
|
||||
|
||||
let grid2 = ByteGrid::from(&win.window(1..4, 1..4).unwrap());
|
||||
|
||||
assert_eq!(grid2.data_ref(), &[2, 2, 2, 3, 4, 4, 3, 4, 4,]);
|
||||
assert_eq!(
|
||||
grid.data_ref(),
|
||||
&[
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 4, 3, 3, 4, 4, 4, 3,
|
||||
3, 4, 4, 4,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue