tabled/features/disable.rs
1//! This module contains a [`Disable`] structure which helps to
2//! remove an etheir column or row from a [`Table`].
3//!
4//! Generally you should avoid use of [`Disable`] because it's a slow function and modifies the underlying records.
5//! Providing correct data right away is better.
6//!
7//! # Example
8//!
9//! ```
10//! use tabled::{Disable, TableIteratorExt, object::Rows};
11//!
12//! let data = vec!["Hello", "World", "!!!"];
13//!
14//! let table = data.table().with(Disable::row(Rows::new(1..2))).to_string();
15//!
16//! assert_eq!(
17//! table,
18//! "+-------+\n\
19//! | &str |\n\
20//! +-------+\n\
21//! | World |\n\
22//! +-------+\n\
23//! | !!! |\n\
24//! +-------+"
25//! );
26//! ```
27//!
28//! [`Table`]: crate::Table
29
30use std::marker::PhantomData;
31
32use papergrid::records::{Records, Resizable};
33
34use crate::{locator::Locator, Table, TableOption};
35
36/// Disable removes particular rows/columns from a [`Table`].
37///
38/// It tries to keeps track of style changes which may occur.
39/// But it's not guaranteed will be the way you would expect it to be.
40///
41/// # Example
42///
43/// ```rust,no_run
44/// # use tabled::{Disable, Table, object::Rows};
45/// # let data: Vec<&'static str> = Vec::new();
46/// let table = Table::new(&data).with(Disable::row(Rows::first()));
47/// ```
48///
49/// [`Table`]: crate::Table
50#[derive(Debug)]
51pub struct Disable<L, Target> {
52 locator: L,
53 target: PhantomData<Target>,
54}
55
56impl<L> Disable<L, TargetColumn> {
57 /// Disable columns.
58 ///
59 /// Available locators are:
60 ///
61 /// - [`Columns`]
62 /// - [`Column`]
63 /// - [`FirstColumn`]
64 /// - [`LastColumn`]
65 /// - [`ByColumnName`]
66 ///
67 /// ```rust
68 /// use tabled::{Disable, locator::ByColumnName, builder::Builder, object::Columns};
69 ///
70 /// let mut builder = Builder::default();
71 ///
72 /// builder.add_record(["col1", "col2", "col3"]);
73 /// builder.add_record(["Hello", "World", "1"]);
74 ///
75 /// let table = builder.build()
76 /// .with(Disable::column(ByColumnName::new("col3")))
77 /// .to_string();
78 ///
79 /// assert_eq!(
80 /// table,
81 /// "+-------+-------+\n\
82 /// | col1 | col2 |\n\
83 /// +-------+-------+\n\
84 /// | Hello | World |\n\
85 /// +-------+-------+"
86 /// );
87 /// ```
88 ///
89 /// [`Columns`]: crate::object::Columns
90 /// [`Column`]: crate::object::Column
91 /// [`FirstColumn`]: crate::object::FirstColumn
92 /// [`LastColumn`]: crate::object::LastColumn
93 /// [`ByColumnName`]: crate::locator::ByColumnName
94 pub fn column(locator: L) -> Self
95 where
96 L: Locator<Coordinate = usize>,
97 {
98 Self {
99 locator,
100 target: PhantomData,
101 }
102 }
103}
104
105impl<L> Disable<L, TargetRow> {
106 /// Disable rows.
107 ///
108 /// Available locators are:
109 ///
110 /// - [`Rows`]
111 /// - [`Row`]
112 /// - [`FirstRow`]
113 /// - [`LastRow`]
114 ///
115 /// ```rust
116 /// use tabled::{Disable, builder::Builder, object::Rows};
117 ///
118 /// let mut builder = Builder::default();
119 ///
120 /// builder.add_record(["col1", "col2", "col3"]);
121 /// builder.add_record(["Hello", "World", "1"]);
122 ///
123 /// let table = builder.build()
124 /// .with(Disable::row(Rows::first()))
125 /// .to_string();
126 ///
127 /// assert_eq!(
128 /// table,
129 /// "+-------+-------+---+\n\
130 /// | Hello | World | 1 |\n\
131 /// +-------+-------+---+"
132 /// );
133 /// ```
134 ///
135 /// [`Rows`]: crate::object::Rows
136 /// [`Row`]: crate::object::Row
137 /// [`FirstRow`]: crate::object::FirstRow
138 /// [`LastRow`]: crate::object::LastRow
139 pub fn row(locator: L) -> Self
140 where
141 L: Locator<Coordinate = usize>,
142 {
143 Self {
144 locator,
145 target: PhantomData,
146 }
147 }
148}
149
150/// A marker struct for [`Disable`].
151#[derive(Debug)]
152pub struct TargetRow;
153
154/// A marker struct for [`Disable`].
155#[derive(Debug)]
156pub struct TargetColumn;
157
158impl<L, D> TableOption<D> for Disable<L, TargetColumn>
159where
160 L: Locator<Coordinate = usize>,
161 D: Records + Resizable,
162{
163 fn change(&mut self, table: &mut Table<D>) {
164 let columns = self.locator.locate(table.get_records());
165 let records = table.get_records_mut();
166 let mut shift = 0;
167 for col in columns.into_iter() {
168 if col - shift > records.count_columns() {
169 continue;
170 }
171
172 records.remove_column(col - shift);
173 shift += 1;
174 }
175
176 table.destroy_width_cache();
177 table.destroy_height_cache();
178
179 // fixme: I am pretty sure that we violate span constrains by removing rows/cols
180 // Because span may be bigger then the max number of rows/cols
181 }
182}
183
184impl<L, D> TableOption<D> for Disable<L, TargetRow>
185where
186 L: Locator<Coordinate = usize>,
187 D: Records + Resizable,
188{
189 fn change(&mut self, table: &mut Table<D>) {
190 let rows = self.locator.locate(table.get_records());
191 let records = table.get_records_mut();
192 let mut shift = 0;
193 for row in rows.into_iter() {
194 if row - shift > records.count_rows() {
195 continue;
196 }
197
198 records.remove_row(row - shift);
199 shift += 1;
200 }
201
202 table.destroy_width_cache();
203 table.destroy_height_cache();
204
205 // fixme: I am pretty sure that we violate span constrains by removing rows/cols
206 // Because span may be bigger then the max number of rows/cols
207 }
208}