diff options
Diffstat (limited to 'vendor/tabled/src/grid/records')
10 files changed, 849 insertions, 0 deletions
diff --git a/vendor/tabled/src/grid/records/empty_records.rs b/vendor/tabled/src/grid/records/empty_records.rs new file mode 100644 index 000000000..77ebc812d --- /dev/null +++ b/vendor/tabled/src/grid/records/empty_records.rs @@ -0,0 +1,41 @@ +//! An empty [`Records`] implementation. + +use core::iter::{repeat, Repeat, Take}; + +use super::Records; + +/// Empty representation of [`Records`]. +#[derive(Debug, Default, Clone)] +pub struct EmptyRecords { + rows: usize, + cols: usize, +} + +impl EmptyRecords { + /// Constructs an empty representation of [`Records`] with a given shape. + pub fn new(rows: usize, cols: usize) -> Self { + Self { rows, cols } + } +} + +impl From<(usize, usize)> for EmptyRecords { + fn from((count_rows, count_columns): (usize, usize)) -> Self { + Self::new(count_rows, count_columns) + } +} + +impl Records for EmptyRecords { + type Iter = Take<Repeat<Take<Repeat<&'static str>>>>; + + fn iter_rows(self) -> Self::Iter { + repeat(repeat("").take(self.cols)).take(self.rows) + } + + fn count_columns(&self) -> usize { + self.cols + } + + fn hint_count_rows(&self) -> Option<usize> { + Some(self.rows) + } +} diff --git a/vendor/tabled/src/grid/records/into_records/buf_records.rs b/vendor/tabled/src/grid/records/into_records/buf_records.rs new file mode 100644 index 000000000..2db3e45bf --- /dev/null +++ b/vendor/tabled/src/grid/records/into_records/buf_records.rs @@ -0,0 +1,213 @@ +//! A module contains [`BufRows`] and [`BufColumns`] iterators. +//! +//! Almoust always they both can be used interchangeably but [`BufRows`] is supposed to be lighter cause it +//! does not reads columns. + +use crate::grid::records::IntoRecords; + +use super::either_string::EitherString; + +/// BufRecords inspects [`IntoRecords`] iterator and keeps read data buffered. +/// So it can be checking before hand. +#[derive(Debug)] +pub struct BufRows<I, T> { + iter: I, + buf: Vec<T>, +} + +impl BufRows<(), ()> { + /// Creates a new [`BufRows`] structure, filling the buffer. + pub fn new<I: IntoRecords>( + records: I, + sniff: usize, + ) -> BufRows<<I::IterRows as IntoIterator>::IntoIter, I::IterColumns> { + let mut buf = vec![]; + + let mut iter = records.iter_rows().into_iter(); + for _ in 0..sniff { + match iter.next() { + Some(row) => buf.push(row), + None => break, + } + } + + BufRows { iter, buf } + } +} + +impl<I, T> BufRows<I, T> { + /// Returns a slice of a record buffer. + pub fn as_slice(&self) -> &[T] { + &self.buf + } +} + +impl<I, T> From<BufRows<I, T>> for BufColumns<I> +where + T: IntoIterator, + T::Item: AsRef<str>, +{ + fn from(value: BufRows<I, T>) -> Self { + let buf = value + .buf + .into_iter() + .map(|row| row.into_iter().map(|s| s.as_ref().to_string()).collect()) + .collect(); + + BufColumns { + iter: value.iter, + buf, + } + } +} + +impl<I, T> IntoRecords for BufRows<I, T> +where + I: Iterator<Item = T>, + T: IntoIterator, + T::Item: AsRef<str>, +{ + type Cell = T::Item; + type IterColumns = T; + type IterRows = BufRowIter<I, T>; + + fn iter_rows(self) -> Self::IterRows { + BufRowIter { + buf: self.buf.into_iter(), + iter: self.iter, + } + } +} + +/// Buffered [`Iterator`]. +#[derive(Debug)] +pub struct BufRowIter<I, T> { + buf: std::vec::IntoIter<T>, + iter: I, +} + +impl<I, T> Iterator for BufRowIter<I, T> +where + I: Iterator<Item = T>, + T: IntoIterator, + T::Item: AsRef<str>, +{ + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + match self.buf.next() { + Some(i) => Some(i), + None => self.iter.next(), + } + } +} + +/// BufRecords inspects [`IntoRecords`] iterator and keeps read data buffered. +/// So it can be checking before hand. +/// +/// In contrast to [`BufRows`] it keeps records by columns. +#[derive(Debug)] +pub struct BufColumns<I> { + iter: I, + buf: Vec<Vec<String>>, +} + +impl BufColumns<()> { + /// Creates new [`BufColumns`] structure, filling the buffer. + pub fn new<I: IntoRecords>( + records: I, + sniff: usize, + ) -> BufColumns<<I::IterRows as IntoIterator>::IntoIter> { + let mut buf = vec![]; + + let mut iter = records.iter_rows().into_iter(); + for _ in 0..sniff { + match iter.next() { + Some(row) => { + let row = row + .into_iter() + .map(|cell| cell.as_ref().to_string()) + .collect::<Vec<_>>(); + buf.push(row) + } + None => break, + } + } + + BufColumns { iter, buf } + } +} + +impl<I> BufColumns<I> { + /// Returns a slice of a keeping buffer. + pub fn as_slice(&self) -> &[Vec<String>] { + &self.buf + } +} + +impl<I> IntoRecords for BufColumns<I> +where + I: Iterator, + I::Item: IntoIterator, + <I::Item as IntoIterator>::Item: AsRef<str>, +{ + type Cell = EitherString<<I::Item as IntoIterator>::Item>; + type IterColumns = EitherRowIterator<<I::Item as IntoIterator>::IntoIter>; + type IterRows = BufColumnIter<I>; + + fn iter_rows(self) -> Self::IterRows { + BufColumnIter { + buf: self.buf.into_iter(), + iter: self.iter, + } + } +} + +/// A row iterator for [`BufColumns`] +#[derive(Debug)] +pub struct BufColumnIter<I> { + buf: std::vec::IntoIter<Vec<String>>, + iter: I, +} + +impl<I> Iterator for BufColumnIter<I> +where + I: Iterator, + I::Item: IntoIterator, + <I::Item as IntoIterator>::Item: AsRef<str>, +{ + type Item = EitherRowIterator<<I::Item as IntoIterator>::IntoIter>; + + fn next(&mut self) -> Option<Self::Item> { + match self.buf.next() { + Some(i) => Some(EitherRowIterator::Owned(i.into_iter())), + None => self + .iter + .next() + .map(|i| EitherRowIterator::Some(i.into_iter())), + } + } +} + +/// An iterator over some iterator or allocated buffer. +#[derive(Debug)] +pub enum EitherRowIterator<I> { + /// Allocated iterator. + Owned(std::vec::IntoIter<String>), + /// Given iterator. + Some(I), +} + +impl<I> Iterator for EitherRowIterator<I> +where + I: Iterator, +{ + type Item = EitherString<I::Item>; + + fn next(&mut self) -> Option<Self::Item> { + match self { + EitherRowIterator::Owned(iter) => iter.next().map(EitherString::Owned), + EitherRowIterator::Some(iter) => iter.next().map(EitherString::Some), + } + } +} diff --git a/vendor/tabled/src/grid/records/into_records/either_string.rs b/vendor/tabled/src/grid/records/into_records/either_string.rs new file mode 100644 index 000000000..f4d97290d --- /dev/null +++ b/vendor/tabled/src/grid/records/into_records/either_string.rs @@ -0,0 +1,22 @@ +//! A module with a utility enum [`EitherString`]. + +/// Either allocated string or some type which can be used as a string. +#[derive(Debug)] +pub enum EitherString<T> { + /// Allocated string. + Owned(String), + /// Something which can be used as a string. + Some(T), +} + +impl<T> AsRef<str> for EitherString<T> +where + T: AsRef<str>, +{ + fn as_ref(&self) -> &str { + match self { + EitherString::Owned(s) => s.as_ref(), + EitherString::Some(s) => s.as_ref(), + } + } +} diff --git a/vendor/tabled/src/grid/records/into_records/limit_column_records.rs b/vendor/tabled/src/grid/records/into_records/limit_column_records.rs new file mode 100644 index 000000000..89b2b89ed --- /dev/null +++ b/vendor/tabled/src/grid/records/into_records/limit_column_records.rs @@ -0,0 +1,82 @@ +//! The module contains [`LimitColumns`] records iterator. + +use crate::grid::records::IntoRecords; + +/// An iterator which limits amount of columns. +#[derive(Debug)] +pub struct LimitColumns<I> { + records: I, + limit: usize, +} + +impl LimitColumns<()> { + /// Creates new [`LimitColumns`]. + pub fn new<I: IntoRecords>(records: I, limit: usize) -> LimitColumns<I> { + LimitColumns { records, limit } + } +} + +impl<I> IntoRecords for LimitColumns<I> +where + I: IntoRecords, +{ + type Cell = I::Cell; + type IterColumns = LimitColumnsColumnsIter<<I::IterColumns as IntoIterator>::IntoIter>; + type IterRows = LimitColumnsIter<<I::IterRows as IntoIterator>::IntoIter>; + + fn iter_rows(self) -> Self::IterRows { + LimitColumnsIter { + iter: self.records.iter_rows().into_iter(), + limit: self.limit, + } + } +} + +/// An iterator over rows for [`LimitColumns`]. +#[derive(Debug)] +pub struct LimitColumnsIter<I> { + iter: I, + limit: usize, +} + +impl<I> Iterator for LimitColumnsIter<I> +where + I: Iterator, + I::Item: IntoIterator, + <I::Item as IntoIterator>::Item: AsRef<str>, +{ + type Item = LimitColumnsColumnsIter<<I::Item as IntoIterator>::IntoIter>; + + fn next(&mut self) -> Option<Self::Item> { + let iter = self.iter.next()?; + Some(LimitColumnsColumnsIter { + iter: iter.into_iter(), + limit: self.limit, + }) + } +} + +/// An iterator over columns for [`LimitColumns`]. +#[derive(Debug)] +pub struct LimitColumnsColumnsIter<I> { + iter: I, + limit: usize, +} + +impl<I> Iterator for LimitColumnsColumnsIter<I> +where + I: Iterator, + I::Item: AsRef<str>, +{ + type Item = I::Item; + + fn next(&mut self) -> Option<Self::Item> { + if self.limit == 0 { + return None; + } + + self.limit -= 1; + + self.iter.next() + } +} diff --git a/vendor/tabled/src/grid/records/into_records/limit_row_records.rs b/vendor/tabled/src/grid/records/into_records/limit_row_records.rs new file mode 100644 index 000000000..a461c6682 --- /dev/null +++ b/vendor/tabled/src/grid/records/into_records/limit_row_records.rs @@ -0,0 +1,59 @@ +//! The module contains [`LimitRows`] records iterator. + +use crate::grid::records::IntoRecords; + +/// [`LimitRows`] is an records iterator which limits amount of rows. +#[derive(Debug)] +pub struct LimitRows<I> { + records: I, + limit: usize, +} + +impl LimitRows<()> { + /// Creates new [`LimitRows`] iterator. + pub fn new<I: IntoRecords>(records: I, limit: usize) -> LimitRows<I> { + LimitRows { records, limit } + } +} + +impl<I> IntoRecords for LimitRows<I> +where + I: IntoRecords, +{ + type Cell = I::Cell; + type IterColumns = I::IterColumns; + type IterRows = LimitRowsIter<<I::IterRows as IntoIterator>::IntoIter>; + + fn iter_rows(self) -> Self::IterRows { + LimitRowsIter { + iter: self.records.iter_rows().into_iter(), + limit: self.limit, + } + } +} + +/// A rows iterator for [`LimitRows`] +#[derive(Debug)] +pub struct LimitRowsIter<I> { + iter: I, + limit: usize, +} + +impl<I> Iterator for LimitRowsIter<I> +where + I: Iterator, + I::Item: IntoIterator, + <I::Item as IntoIterator>::Item: AsRef<str>, +{ + type Item = I::Item; + + fn next(&mut self) -> Option<Self::Item> { + if self.limit == 0 { + return None; + } + + self.limit -= 1; + + self.iter.next() + } +} diff --git a/vendor/tabled/src/grid/records/into_records/mod.rs b/vendor/tabled/src/grid/records/into_records/mod.rs new file mode 100644 index 000000000..0a52c41c1 --- /dev/null +++ b/vendor/tabled/src/grid/records/into_records/mod.rs @@ -0,0 +1,26 @@ +//! The module contains a list of helpers for [`IntoRecords`] +//! +//! [`IntoRecords`]: crate::grid::records::IntoRecords + +pub mod limit_column_records; +pub mod limit_row_records; + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub mod buf_records; +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub mod either_string; +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub mod truncate_records; + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub use buf_records::{BufColumns, BufRows}; +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub use truncate_records::TruncateContent; + +pub use limit_column_records::LimitColumns; +pub use limit_row_records::LimitRows; diff --git a/vendor/tabled/src/grid/records/into_records/truncate_records.rs b/vendor/tabled/src/grid/records/into_records/truncate_records.rs new file mode 100644 index 000000000..17e7e533e --- /dev/null +++ b/vendor/tabled/src/grid/records/into_records/truncate_records.rs @@ -0,0 +1,136 @@ +//! The module contains [`TruncateContent`] records iterator. + +use std::borrow::Cow; + +use crate::{ + grid::records::IntoRecords, grid::util::string::string_width_multiline, + settings::width::Truncate, +}; + +use super::either_string::EitherString; + +/// A records iterator which truncates all cells to a given width. +#[derive(Debug)] +pub struct TruncateContent<'a, I> { + records: I, + width: ExactValue<'a>, +} + +impl TruncateContent<'_, ()> { + /// Creates new [`TruncateContent`] object. + pub fn new<I: IntoRecords>(records: I, width: ExactValue<'_>) -> TruncateContent<'_, I> { + TruncateContent { records, width } + } +} + +impl<'a, I> IntoRecords for TruncateContent<'a, I> +where + I: IntoRecords, +{ + type Cell = EitherString<I::Cell>; + type IterColumns = TruncateContentColumnsIter<'a, <I::IterColumns as IntoIterator>::IntoIter>; + type IterRows = TruncateContentIter<'a, <I::IterRows as IntoIterator>::IntoIter>; + + fn iter_rows(self) -> Self::IterRows { + TruncateContentIter { + iter: self.records.iter_rows().into_iter(), + width: self.width.clone(), + } + } +} + +/// A row iterator for [`TruncateContent`]. +#[derive(Debug)] +pub struct TruncateContentIter<'a, I> { + iter: I, + width: ExactValue<'a>, +} + +impl<'a, I> Iterator for TruncateContentIter<'a, I> +where + I: Iterator, + I::Item: IntoIterator, + <I::Item as IntoIterator>::Item: AsRef<str>, +{ + type Item = TruncateContentColumnsIter<'a, <I::Item as IntoIterator>::IntoIter>; + + fn next(&mut self) -> Option<Self::Item> { + let iter = self.iter.next()?; + Some(TruncateContentColumnsIter { + iter: iter.into_iter(), + current: 0, + width: self.width.clone(), + }) + } +} + +/// A column iterator for [`TruncateContent`]. +#[derive(Debug)] +pub struct TruncateContentColumnsIter<'a, I> { + iter: I, + width: ExactValue<'a>, + current: usize, +} + +impl<I> Iterator for TruncateContentColumnsIter<'_, I> +where + I: Iterator, + I::Item: AsRef<str>, +{ + type Item = EitherString<I::Item>; + + fn next(&mut self) -> Option<Self::Item> { + let s = self.iter.next()?; + + let width = self.width.get(self.current); + self.current += 1; + + let text_width = string_width_multiline(s.as_ref()); + if text_width <= width { + return Some(EitherString::Some(s)); + } + + let text = Truncate::truncate_text(s.as_ref(), width); + let text = text.into_owned(); + let text = EitherString::Owned(text); + + Some(text) + } +} + +/// A width value. +#[derive(Debug, Clone)] +pub enum ExactValue<'a> { + /// Const width value. + Exact(usize), + /// A list of width values for columns. + List(Cow<'a, [usize]>), +} + +impl<'a> From<&'a [usize]> for ExactValue<'a> { + fn from(value: &'a [usize]) -> Self { + Self::List(value.into()) + } +} + +impl From<Vec<usize>> for ExactValue<'_> { + fn from(value: Vec<usize>) -> Self { + Self::List(value.into()) + } +} + +impl From<usize> for ExactValue<'_> { + fn from(value: usize) -> Self { + Self::Exact(value) + } +} + +impl ExactValue<'_> { + /// Get a width by column. + pub fn get(&self, col: usize) -> usize { + match self { + ExactValue::Exact(val) => *val, + ExactValue::List(cols) => cols[col], + } + } +} diff --git a/vendor/tabled/src/grid/records/mod.rs b/vendor/tabled/src/grid/records/mod.rs new file mode 100644 index 000000000..494002346 --- /dev/null +++ b/vendor/tabled/src/grid/records/mod.rs @@ -0,0 +1,19 @@ +//! The module contains [`Records`], [`ExactRecords`], [`RecordsMut`], [`Resizable`] traits +//! and its implementations. +//! +//! Also it provies a list of helpers for a user built [`Records`] via [`into_records`]. + +mod empty_records; +mod records_mut; +mod resizable; + +pub mod into_records; + +pub use empty_records::EmptyRecords; +pub use papergrid::records::{ExactRecords, IntoRecords, IterRecords, PeekableRecords, Records}; +pub use records_mut::RecordsMut; +pub use resizable::Resizable; + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub use papergrid::records::vec_records; diff --git a/vendor/tabled/src/grid/records/records_mut.rs b/vendor/tabled/src/grid/records/records_mut.rs new file mode 100644 index 000000000..38c42d2c7 --- /dev/null +++ b/vendor/tabled/src/grid/records/records_mut.rs @@ -0,0 +1,34 @@ +use crate::grid::config::Position; +#[cfg(feature = "std")] +use crate::grid::records::vec_records::{CellInfo, VecRecords}; + +/// A [`Records`] representation which can modify cell by (row, column) index. +/// +/// [`Records`]: crate::grid::records::Records +pub trait RecordsMut<Text> { + /// Sets a text to a given cell by index. + fn set(&mut self, pos: Position, text: Text); +} + +impl<T, Text> RecordsMut<Text> for &'_ mut T +where + T: RecordsMut<Text>, +{ + fn set(&mut self, pos: Position, text: Text) { + T::set(self, pos, text) + } +} + +#[cfg(feature = "std")] +impl RecordsMut<String> for VecRecords<CellInfo<String>> { + fn set(&mut self, (row, col): Position, text: String) { + self[row][col] = CellInfo::new(text); + } +} + +#[cfg(feature = "std")] +impl RecordsMut<&str> for VecRecords<CellInfo<String>> { + fn set(&mut self, (row, col): Position, text: &str) { + self[row][col] = CellInfo::new(text.to_string()); + } +} diff --git a/vendor/tabled/src/grid/records/resizable.rs b/vendor/tabled/src/grid/records/resizable.rs new file mode 100644 index 000000000..29ab38038 --- /dev/null +++ b/vendor/tabled/src/grid/records/resizable.rs @@ -0,0 +1,217 @@ +use papergrid::config::Position; + +#[cfg(feature = "std")] +use crate::grid::records::vec_records::VecRecords; + +/// A records representation which can be modified by moving rows/columns around. +pub trait Resizable { + /// Swap cells with one another. + fn swap(&mut self, lhs: Position, rhs: Position); + /// Swap rows with one another. + fn swap_row(&mut self, lhs: usize, rhs: usize); + /// Swap columns with one another. + fn swap_column(&mut self, lhs: usize, rhs: usize); + /// Adds a new row to a data set. + fn push_row(&mut self); + /// Adds a new column to a data set. + fn push_column(&mut self); + /// Removes a row from a data set by index. + fn remove_row(&mut self, row: usize); + /// Removes a column from a data set by index. + fn remove_column(&mut self, column: usize); + /// Inserts a row at index. + fn insert_row(&mut self, row: usize); + /// Inserts column at index. + fn insert_column(&mut self, column: usize); +} + +impl<T> Resizable for &'_ mut T +where + T: Resizable, +{ + fn swap(&mut self, lhs: Position, rhs: Position) { + T::swap(self, lhs, rhs) + } + + fn swap_row(&mut self, lhs: usize, rhs: usize) { + T::swap_row(self, lhs, rhs) + } + + fn swap_column(&mut self, lhs: usize, rhs: usize) { + T::swap_column(self, lhs, rhs) + } + + fn push_row(&mut self) { + T::push_row(self) + } + + fn push_column(&mut self) { + T::push_column(self) + } + + fn remove_row(&mut self, row: usize) { + T::remove_row(self, row) + } + + fn remove_column(&mut self, column: usize) { + T::remove_column(self, column) + } + + fn insert_row(&mut self, row: usize) { + T::insert_row(self, row) + } + + fn insert_column(&mut self, column: usize) { + T::insert_column(self, column) + } +} + +#[cfg(feature = "std")] +impl<T> Resizable for Vec<Vec<T>> +where + T: Default + Clone, +{ + fn swap(&mut self, lhs: Position, rhs: Position) { + if lhs == rhs { + return; + } + + let t = std::mem::take(&mut self[lhs.0][lhs.1]); + let t = std::mem::replace(&mut self[rhs.0][rhs.1], t); + let _ = std::mem::replace(&mut self[lhs.0][lhs.1], t); + } + + fn swap_row(&mut self, lhs: usize, rhs: usize) { + let t = std::mem::take(&mut self[lhs]); + let t = std::mem::replace(&mut self[rhs], t); + let _ = std::mem::replace(&mut self[lhs], t); + } + + fn swap_column(&mut self, lhs: usize, rhs: usize) { + for row in self.iter_mut() { + row.swap(lhs, rhs); + } + } + + fn push_row(&mut self) { + let count_columns = self.get(0).map(|l| l.len()).unwrap_or(0); + self.push(vec![T::default(); count_columns]); + } + + fn push_column(&mut self) { + for row in self.iter_mut() { + row.push(T::default()); + } + } + + fn remove_row(&mut self, row: usize) { + let _ = self.remove(row); + } + + fn remove_column(&mut self, column: usize) { + for row in self.iter_mut() { + let _ = row.remove(column); + } + } + + fn insert_row(&mut self, row: usize) { + let count_columns = self.get(0).map(|l| l.len()).unwrap_or(0); + self.insert(row, vec![T::default(); count_columns]); + } + + fn insert_column(&mut self, column: usize) { + for row in self { + row.insert(column, T::default()); + } + } +} + +#[cfg(feature = "std")] +impl<T> Resizable for VecRecords<T> +where + T: Default + Clone, +{ + fn swap(&mut self, lhs: Position, rhs: Position) { + if lhs == rhs { + return; + } + + let t = std::mem::take(&mut self[lhs.0][lhs.1]); + let t = std::mem::replace(&mut self[rhs.0][rhs.1], t); + let _ = std::mem::replace(&mut self[lhs.0][lhs.1], t); + } + + fn swap_row(&mut self, lhs: usize, rhs: usize) { + let t = std::mem::take(&mut self[lhs]); + let t = std::mem::replace(&mut self[rhs], t); + let _ = std::mem::replace(&mut self[lhs], t); + } + + fn swap_column(&mut self, lhs: usize, rhs: usize) { + for row in self.iter_mut() { + row.swap(lhs, rhs); + } + } + + fn push_row(&mut self) { + let records = std::mem::replace(self, VecRecords::new(vec![])); + let mut data: Vec<Vec<_>> = records.into(); + + let count_columns = data.get(0).map(|l| l.len()).unwrap_or(0); + data.push(vec![T::default(); count_columns]); + + *self = VecRecords::new(data); + } + + fn push_column(&mut self) { + let records = std::mem::replace(self, VecRecords::new(vec![])); + let mut data: Vec<Vec<_>> = records.into(); + + for row in &mut data { + row.push(T::default()); + } + + *self = VecRecords::new(data); + } + + fn remove_row(&mut self, row: usize) { + let records = std::mem::replace(self, VecRecords::new(vec![])); + let mut data: Vec<Vec<_>> = records.into(); + + let _ = data.remove(row); + + *self = VecRecords::new(data); + } + + fn remove_column(&mut self, column: usize) { + let records = std::mem::replace(self, VecRecords::new(vec![])); + let mut data: Vec<Vec<_>> = records.into(); + + for row in &mut data { + let _ = row.remove(column); + } + + *self = VecRecords::new(data); + } + + fn insert_row(&mut self, row: usize) { + let records = std::mem::replace(self, VecRecords::new(vec![])); + let mut data: Vec<Vec<_>> = records.into(); + + let count_columns = data.get(0).map(|l| l.len()).unwrap_or(0); + data.insert(row, vec![T::default(); count_columns]); + + *self = VecRecords::new(data); + } + + fn insert_column(&mut self, column: usize) { + let records = std::mem::replace(self, VecRecords::new(vec![])); + let mut data: Vec<Vec<_>> = records.into(); + + for row in &mut data { + row.insert(column, T::default()); + } + + *self = VecRecords::new(data); + } +} |