summaryrefslogtreecommitdiffstats
path: root/vendor/tabled/src/settings/extract
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tabled/src/settings/extract')
-rw-r--r--vendor/tabled/src/settings/extract/mod.rs257
1 files changed, 257 insertions, 0 deletions
diff --git a/vendor/tabled/src/settings/extract/mod.rs b/vendor/tabled/src/settings/extract/mod.rs
new file mode 100644
index 000000000..bba90a0db
--- /dev/null
+++ b/vendor/tabled/src/settings/extract/mod.rs
@@ -0,0 +1,257 @@
+//! This module contains an [`Extract`] structure which is used to
+//! obtain an ordinary segment from the [`Table`].
+//!
+//! There's a similar structure [`Highlight`] which does a highlighting a of segments.
+//!
+//! [`Table`]: crate::Table
+//! [`Highlight`]: crate::settings::highlight::Highlight
+
+use core::cmp::min;
+use core::ops::{Bound, RangeBounds, RangeFull};
+
+use crate::{
+ grid::records::{ExactRecords, Records, Resizable},
+ settings::TableOption,
+};
+
+/// Returns a new [`Table`] that reflects a segment of the referenced [`Table`]
+///
+/// # Example
+///
+#[cfg_attr(feature = "std", doc = "```")]
+#[cfg_attr(not(feature = "std"), doc = "```ignore")]
+/// use tabled::{Table, settings::{Format, object::Rows, Modify, Extract}};
+///
+/// let data = vec![
+/// (0, "Grodno", true),
+/// (1, "Minsk", true),
+/// (2, "Hamburg", false),
+/// (3, "Brest", true),
+/// ];
+///
+/// let table = Table::new(&data)
+/// .with(Modify::new(Rows::new(1..)).with(Format::content(|s| format!(": {} :", s))))
+/// .with(Extract::segment(1..=2, 1..))
+/// .to_string();
+///
+/// assert_eq!(table, "+------------+----------+\n\
+/// | : Grodno : | : true : |\n\
+/// +------------+----------+\n\
+/// | : Minsk : | : true : |\n\
+/// +------------+----------+");
+/// ```
+///
+/// [`Table`]: crate::Table
+#[derive(Debug)]
+pub struct Extract<R, C> {
+ rows: R,
+ columns: C,
+}
+
+impl<R, C> Extract<R, C>
+where
+ R: RangeBounds<usize>,
+ C: RangeBounds<usize>,
+{
+ /// Returns a new [`Table`] that reflects a segment of the referenced [`Table`]
+ ///
+ /// ```rust,no_run
+ /// # use tabled::settings::Extract;
+ /// let rows = 1..3;
+ /// let columns = 1..;
+ /// Extract::segment(rows, columns);
+ /// ```
+ ///
+ /// # Range
+ ///
+ /// A [`RangeBounds`] argument can be less than or equal to the shape of a [`Table`]
+ ///
+ /// If a [`RangeBounds`] argument is malformed or too large the thread will panic
+ ///
+ /// ```text
+ /// // Empty Full Out of bounds
+ /// Extract::segment(0..0, 0..0) Extract::segment(.., ..) Extract::segment(0..1, ..4)
+ /// []. . . [O O O [O O O X] //ERROR
+ /// . . . O O O . . .
+ /// . . . O O O] . . .
+ /// ```
+ ///
+ /// [`Table`]: crate::Table
+ pub fn segment(rows: R, columns: C) -> Self {
+ Extract { rows, columns }
+ }
+}
+
+impl<R> Extract<R, RangeFull>
+where
+ R: RangeBounds<usize>,
+{
+ /// Returns a new [`Table`] that reflects a segment of the referenced [`Table`]
+ ///
+ /// The segment is defined by [`RangeBounds`] for Rows
+ ///
+ /// ```rust,no_run
+ /// # use tabled::settings::Extract;
+ /// Extract::rows(1..3);
+ /// ```
+ ///
+ /// # Range
+ ///
+ /// A [`RangeBounds`] argument can be less than or equal to the shape of a [`Table`]
+ ///
+ /// If a [`RangeBounds`] argument is malformed or too large the thread will panic
+ ///
+ /// ```text
+ /// // Empty Full Out of bounds
+ /// Extract::rows(0..0) Extract::rows(..) Extract::rows(0..4)
+ /// []. . . [O O O [O O O
+ /// . . . O O O O O O
+ /// . . . O O O] O O O
+ /// X X X] // ERROR
+ /// ```
+ ///
+ /// [`Table`]: crate::Table
+ pub fn rows(rows: R) -> Self {
+ Extract { rows, columns: .. }
+ }
+}
+
+impl<C> Extract<RangeFull, C>
+where
+ C: RangeBounds<usize>,
+{
+ /// Returns a new [`Table`] that reflects a segment of the referenced [`Table`]
+ ///
+ /// The segment is defined by [`RangeBounds`] for columns.
+ ///
+ /// ```rust,no_run
+ /// # use tabled::settings::Extract;
+ /// Extract::columns(1..3);
+ /// ```
+ ///
+ /// # Range
+ ///
+ /// A [`RangeBounds`] argument can be less than or equal to the shape of a [`Table`]
+ ///
+ /// If a [`RangeBounds`] argument is malformed or too large the thread will panic
+ ///
+ /// ```text
+ /// // Empty Full Out of bounds
+ /// Extract::columns(0..0) Extract::columns(..) Extract::columns(0..4)
+ /// []. . . [O O O [O O O X
+ /// . . . O O O O O O X
+ /// . . . O O O] O O O X] // ERROR
+ /// ```
+ ///
+ /// [`Table`]: crate::Table
+ pub fn columns(columns: C) -> Self {
+ Extract { rows: .., columns }
+ }
+}
+
+impl<R, C, RR, D, Cfg> TableOption<RR, D, Cfg> for Extract<R, C>
+where
+ R: RangeBounds<usize> + Clone,
+ C: RangeBounds<usize> + Clone,
+ RR: Records + ExactRecords + Resizable,
+{
+ fn change(self, records: &mut RR, _: &mut Cfg, _: &mut D) {
+ let count_rows = records.count_rows();
+ let count_columns = records.count_columns();
+
+ let mut rows = bounds_to_usize(self.rows.start_bound(), self.rows.end_bound(), count_rows);
+ let mut cols = bounds_to_usize(
+ self.columns.start_bound(),
+ self.columns.end_bound(),
+ count_columns,
+ );
+
+ // Cleanup table in case if boundaries are exceeded.
+ //
+ // todo: can be optimized by adding a clear() method to Resizable
+ rows.0 = min(rows.0, count_rows);
+ cols.0 = min(cols.0, count_columns);
+
+ extract(records, (count_rows, count_columns), rows, cols);
+ }
+}
+
+/// Returns a new [`Grid`] that reflects a segment of the referenced [`Grid`].
+///
+/// # Example
+///
+/// ```text
+/// grid
+/// +---+---+---+
+/// |0-0|0-1|0-2|
+/// +---+---+---+
+/// |1-0|1-1|1-2|
+/// +---+---+---+
+/// |2-0|2-1|2-2|
+/// +---+---+---+
+///
+/// let rows = ..;
+/// let columns = ..1;
+/// grid.extract(rows, columns)
+///
+/// grid
+/// +---+
+/// |0-0|
+/// +---+
+/// |1-0|
+/// +---+
+/// |2-0|
+/// +---+
+/// ```
+fn extract<R>(
+ records: &mut R,
+ (count_rows, count_cols): (usize, usize),
+ (start_row, end_row): (usize, usize),
+ (start_col, end_col): (usize, usize),
+) where
+ R: Resizable,
+{
+ for (i, row) in (0..start_row).enumerate() {
+ let row = row - i;
+ records.remove_row(row);
+ }
+
+ let count_rows = count_rows - start_row;
+ let end_row = end_row - start_row;
+ for (i, row) in (end_row..count_rows).enumerate() {
+ let row = row - i;
+ records.remove_row(row);
+ }
+
+ for (i, col) in (0..start_col).enumerate() {
+ let col = col - i;
+ records.remove_column(col);
+ }
+
+ let count_cols = count_cols - start_col;
+ let end_col = end_col - start_col;
+ for (i, col) in (end_col..count_cols).enumerate() {
+ let col = col - i;
+ records.remove_column(col);
+ }
+}
+
+fn bounds_to_usize(
+ left: Bound<&usize>,
+ right: Bound<&usize>,
+ count_elements: usize,
+) -> (usize, usize) {
+ match (left, right) {
+ (Bound::Included(x), Bound::Included(y)) => (*x, y + 1),
+ (Bound::Included(x), Bound::Excluded(y)) => (*x, *y),
+ (Bound::Included(x), Bound::Unbounded) => (*x, count_elements),
+ (Bound::Unbounded, Bound::Unbounded) => (0, count_elements),
+ (Bound::Unbounded, Bound::Included(y)) => (0, y + 1),
+ (Bound::Unbounded, Bound::Excluded(y)) => (0, *y),
+ (Bound::Excluded(_), Bound::Unbounded)
+ | (Bound::Excluded(_), Bound::Included(_))
+ | (Bound::Excluded(_), Bound::Excluded(_)) => {
+ unreachable!("A start bound can't be excluded")
+ }
+ }
+}