//! Defines the Row type which makes up lines in the grid. use std::cmp::{max, min}; use std::ops::{Index, IndexMut}; use std::ops::{Range, RangeFrom, RangeFull, RangeTo, RangeToInclusive}; use std::ptr; use std::slice; use serde::{Deserialize, Serialize}; use crate::grid::GridCell; use crate::index::Column; use crate::term::cell::ResetDiscriminant; /// A row in the grid. #[derive(Serialize, Deserialize, Default, Clone, Debug)] pub struct Row { inner: Vec, /// Maximum number of occupied entries. /// /// This is the upper bound on the number of elements in the row, which have been modified /// since the last reset. All cells after this point are guaranteed to be equal. pub(crate) occ: usize, } impl PartialEq for Row { fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl Row { /// Create a new terminal row. /// /// Ideally the `template` should be `Copy` in all performance sensitive scenarios. pub fn new(columns: Column) -> Row { debug_assert!(columns.0 >= 1); let mut inner: Vec = Vec::with_capacity(columns.0); // This is a slightly optimized version of `std::vec::Vec::resize`. unsafe { let mut ptr = inner.as_mut_ptr(); for _ in 1..columns.0 { ptr::write(ptr, T::default()); ptr = ptr.offset(1); } ptr::write(ptr, T::default()); inner.set_len(columns.0); } Row { inner, occ: 0 } } /// Increase the number of columns in the row. #[inline] pub fn grow(&mut self, cols: Column) { if self.inner.len() >= cols.0 { return; } self.inner.resize_with(cols.0, T::default); } /// Reduce the number of columns in the row. /// /// This will return all non-empty cells that were removed. pub fn shrink(&mut self, cols: Column) -> Option> where T: GridCell, { if self.inner.len() <= cols.0 { return None; } // Split off cells for a new row. let mut new_row = self.inner.split_off(cols.0); let index = new_row.iter().rposition(|c| !c.is_empty()).map(|i| i + 1).unwrap_or(0); new_row.truncate(index); self.occ = min(self.occ, cols.0); if new_row.is_empty() { None } else { Some(new_row) } } /// Reset all cells in the row to the `template` cell. #[inline] pub fn reset(&mut self, template: &T) where T: ResetDiscriminant + GridCell, D: PartialEq, { debug_assert!(!self.inner.is_empty()); // Mark all cells as dirty if template cell changed. let len = self.inner.len(); if self.inner[len - 1].discriminant() != template.discriminant() { self.occ = len; } // Reset every dirty cell in the row. for item in &mut self.inner[0..self.occ] { item.reset(template); } self.occ = 0; } } #[allow(clippy::len_without_is_empty)] impl Row { #[inline] pub fn from_vec(vec: Vec, occ: usize) -> Row { Row { inner: vec, occ } } #[inline] pub fn len(&self) -> usize { self.inner.len() } #[inline] pub fn last(&self) -> Option<&T> { self.inner.last() } #[inline] pub fn last_mut(&mut self) -> Option<&mut T> { self.occ = self.inner.len(); self.inner.last_mut() } #[inline] pub fn append(&mut self, vec: &mut Vec) where T: GridCell, { self.occ += vec.len(); self.inner.append(vec); } #[inline] pub fn append_front(&mut self, mut vec: Vec) { self.occ += vec.len(); vec.append(&mut self.inner); self.inner = vec; } /// Check if all cells in the row are empty. #[inline] pub fn is_clear(&self) -> bool where T: GridCell, { self.inner.iter().all(GridCell::is_empty) } #[inline] pub fn front_split_off(&mut self, at: usize) -> Vec { self.occ = self.occ.saturating_sub(at); let mut split = self.inner.split_off(at); std::mem::swap(&mut split, &mut self.inner); split } } impl<'a, T> IntoIterator for &'a mut Row { type IntoIter = slice::IterMut<'a, T>; type Item = &'a mut T; #[inline] fn into_iter(self) -> slice::IterMut<'a, T> { self.occ = self.len(); self.inner.iter_mut() } } impl Index for Row { type Output = T; #[inline] fn index(&self, index: Column) -> &T { &self.inner[index.0] } } impl IndexMut for Row { #[inline] fn index_mut(&mut self, index: Column) -> &mut T { self.occ = max(self.occ, *index + 1); &mut self.inner[index.0] } } impl Index> for Row { type Output = [T]; #[inline] fn index(&self, index: Range) -> &[T] { &self.inner[(index.start.0)..(index.end.0)] } } impl IndexMut> for Row { #[inline] fn index_mut(&mut self, index: Range) -> &mut [T] { self.occ = max(self.occ, *index.end); &mut self.inner[(index.start.0)..(index.end.0)] } } impl Index> for Row { type Output = [T]; #[inline] fn index(&self, index: RangeTo) -> &[T] { &self.inner[..(index.end.0)] } } impl IndexMut> for Row { #[inline] fn index_mut(&mut self, index: RangeTo) -> &mut [T] { self.occ = max(self.occ, *index.end); &mut self.inner[..(index.end.0)] } } impl Index> for Row { type Output = [T]; #[inline] fn index(&self, index: RangeFrom) -> &[T] { &self.inner[(index.start.0)..] } } impl IndexMut> for Row { #[inline] fn index_mut(&mut self, index: RangeFrom) -> &mut [T] { self.occ = self.len(); &mut self.inner[(index.start.0)..] } } impl Index for Row { type Output = [T]; #[inline] fn index(&self, _: RangeFull) -> &[T] { &self.inner[..] } } impl IndexMut for Row { #[inline] fn index_mut(&mut self, _: RangeFull) -> &mut [T] { self.occ = self.len(); &mut self.inner[..] } } impl Index> for Row { type Output = [T]; #[inline] fn index(&self, index: RangeToInclusive) -> &[T] { &self.inner[..=(index.end.0)] } } impl IndexMut> for Row { #[inline] fn index_mut(&mut self, index: RangeToInclusive) -> &mut [T] { self.occ = max(self.occ, *index.end); &mut self.inner[..=(index.end.0)] } }