diff options
Diffstat (limited to 'vendor/tabled/src/grid/records/into_records')
6 files changed, 538 insertions, 0 deletions
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], + } + } +} |