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