blob: 0bfa88d48536580b9a7b32a9032b92b83044029b [file] [log] [blame]
// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! 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::slice;
use serde::{Deserialize, Serialize};
use crate::grid::GridCell;
use crate::index::Column;
/// A row in the grid
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Row<T> {
inner: Vec<T>,
/// 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<T: PartialEq> PartialEq for Row<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T: Copy> Row<T> {
pub fn new(columns: Column, template: &T) -> Row<T>
where
T: GridCell,
{
let occ = if template.is_empty() { 0 } else { columns.0 };
Row { inner: vec![*template; columns.0], occ }
}
pub fn grow(&mut self, cols: Column, template: &T) {
if self.inner.len() >= cols.0 {
return;
}
self.inner.append(&mut vec![*template; cols.0 - self.len()]);
}
pub fn shrink(&mut self, cols: Column) -> Option<Vec<T>>
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: GridCell + PartialEq,
{
debug_assert!(!self.inner.is_empty());
let template = *template;
// Mark all cells as dirty if template cell changed
let len = self.inner.len();
if !self.inner[len - 1].fast_eq(template) {
self.occ = len;
}
// Reset every dirty in the row
// let template = *template;
for item in &mut self.inner[..self.occ] {
*item = template;
}
self.occ = 0;
}
}
#[allow(clippy::len_without_is_empty)]
impl<T> Row<T> {
#[inline]
pub fn from_vec(vec: Vec<T>, occ: usize) -> Row<T> {
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<T>)
where
T: GridCell,
{
self.occ += vec.len();
self.inner.append(vec);
}
#[inline]
pub fn append_front(&mut self, mut vec: Vec<T>) {
self.occ += vec.len();
vec.append(&mut self.inner);
self.inner = vec;
}
#[inline]
pub fn is_empty(&self) -> bool
where
T: GridCell,
{
self.inner.iter().all(GridCell::is_empty)
}
#[inline]
pub fn front_split_off(&mut self, at: usize) -> Vec<T> {
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<T> {
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<T> Index<Column> for Row<T> {
type Output = T;
#[inline]
fn index(&self, index: Column) -> &T {
&self.inner[index.0]
}
}
impl<T> IndexMut<Column> for Row<T> {
#[inline]
fn index_mut(&mut self, index: Column) -> &mut T {
self.occ = max(self.occ, *index + 1);
&mut self.inner[index.0]
}
}
// -----------------------------------------------------------------------------
// Index ranges of columns
// -----------------------------------------------------------------------------
impl<T> Index<Range<Column>> for Row<T> {
type Output = [T];
#[inline]
fn index(&self, index: Range<Column>) -> &[T] {
&self.inner[(index.start.0)..(index.end.0)]
}
}
impl<T> IndexMut<Range<Column>> for Row<T> {
#[inline]
fn index_mut(&mut self, index: Range<Column>) -> &mut [T] {
self.occ = max(self.occ, *index.end);
&mut self.inner[(index.start.0)..(index.end.0)]
}
}
impl<T> Index<RangeTo<Column>> for Row<T> {
type Output = [T];
#[inline]
fn index(&self, index: RangeTo<Column>) -> &[T] {
&self.inner[..(index.end.0)]
}
}
impl<T> IndexMut<RangeTo<Column>> for Row<T> {
#[inline]
fn index_mut(&mut self, index: RangeTo<Column>) -> &mut [T] {
self.occ = max(self.occ, *index.end);
&mut self.inner[..(index.end.0)]
}
}
impl<T> Index<RangeFrom<Column>> for Row<T> {
type Output = [T];
#[inline]
fn index(&self, index: RangeFrom<Column>) -> &[T] {
&self.inner[(index.start.0)..]
}
}
impl<T> IndexMut<RangeFrom<Column>> for Row<T> {
#[inline]
fn index_mut(&mut self, index: RangeFrom<Column>) -> &mut [T] {
self.occ = self.len();
&mut self.inner[(index.start.0)..]
}
}
impl<T> Index<RangeFull> for Row<T> {
type Output = [T];
#[inline]
fn index(&self, _: RangeFull) -> &[T] {
&self.inner[..]
}
}
impl<T> IndexMut<RangeFull> for Row<T> {
#[inline]
fn index_mut(&mut self, _: RangeFull) -> &mut [T] {
self.occ = self.len();
&mut self.inner[..]
}
}
impl<T> Index<RangeToInclusive<Column>> for Row<T> {
type Output = [T];
#[inline]
fn index(&self, index: RangeToInclusive<Column>) -> &[T] {
&self.inner[..=(index.end.0)]
}
}
impl<T> IndexMut<RangeToInclusive<Column>> for Row<T> {
#[inline]
fn index_mut(&mut self, index: RangeToInclusive<Column>) -> &mut [T] {
self.occ = max(self.occ, *index.end);
&mut self.inner[..=(index.end.0)]
}
}