text_grid/
cells.rs

1use std::marker::PhantomData;
2
3use derive_ex::derive_ex;
4
5use crate::{CellsFormatter, RawCell};
6
7/// Derive [`Cells`].
8///
9/// - enum : the variant name becomes the cell value.
10/// - record struct : the field name becomes the column name, and the field value becomes the cell value.
11/// - tuple struct : the field value becomes the cell value.
12pub use text_grid_macros::Cells;
13
14/// A data structure that can be formatted into cells.
15///
16/// The number of columns must be statically determined from the type.
17///
18/// If the number of columns is dynamically determined, [`CellsSchema`] must be used. See [`cells_schema`] for details.
19pub trait Cells {
20    /// Define columns. see [`CellsFormatter`] for details.
21    fn fmt(f: &mut CellsFormatter<Self>);
22}
23impl Cells for () {
24    fn fmt(_: &mut CellsFormatter<Self>) {}
25}
26impl<T: ?Sized + Cells> Cells for &T {
27    fn fmt(f: &mut CellsFormatter<Self>) {
28        T::fmt(&mut f.unref());
29    }
30}
31impl<T: ?Sized + Cells> Cells for &mut T {
32    fn fmt(f: &mut CellsFormatter<Self>) {
33        T::fmt(&mut f.unref());
34    }
35}
36impl<T: Cells, const N: usize> Cells for [T; N] {
37    fn fmt(f: &mut CellsFormatter<Self>) {
38        for i in 0..N {
39            f.column(i, |x| &x[i]);
40        }
41    }
42}
43impl<T: Cells> Cells for Option<T> {
44    fn fmt(f: &mut CellsFormatter<Self>) {
45        f.filter_map(|x| x.as_ref()).content(|x| x)
46    }
47}
48impl<T: Cells, E: RawCell> Cells for std::result::Result<T, E> {
49    fn fmt(f: &mut CellsFormatter<Self>) {
50        f.try_map_with(|x| x.as_ref(), |f| T::fmt(&mut f.unref()));
51    }
52}
53
54/// Column definitions.
55///
56/// Define columns using [`CellsFormatter`].
57///
58/// To dynamically create a `CellsSchema`, use [`cells_schema`].
59///
60/// # Examples
61/// ```
62/// use text_grid::*;
63///
64/// struct MyCellsSchema {
65///     len: usize,
66/// }
67///
68/// impl CellsSchema for MyCellsSchema {
69///     type Source = [u32; 3];
70///     fn fmt(&self, f: &mut CellsFormatter<[u32; 3]>) {
71///         for i in 0..self.len {
72///             f.column(i, |s| s[i]);
73///         }
74///     }
75/// }
76///
77/// let rows = [
78///    [1, 2, 3],
79///    [4, 5, 6],
80/// ];
81/// let schema = MyCellsSchema { len: 3 };
82/// let g = to_grid_with_schema(rows, schema);
83///
84/// assert_eq!(format!("\n{g}"), r#"
85///  0 | 1 | 2 |
86/// ---|---|---|
87///  1 | 2 | 3 |
88///  4 | 5 | 6 |
89/// "#);
90/// ```
91pub trait CellsSchema {
92    type Source: ?Sized;
93
94    /// Define column information. see [`CellsFormatter`] for details.
95    fn fmt(&self, f: &mut CellsFormatter<Self::Source>);
96}
97
98/// Extension trait for [`CellsSchema`].
99pub trait CellsSchemaExt: CellsSchema {
100    fn as_ref(&self) -> impl CellsSchema<Source = &Self::Source> {
101        self.map_ref()
102    }
103    fn map_ref<'a>(self) -> impl CellsSchema<Source = &'a Self::Source>
104    where
105        Self::Source: 'a;
106}
107impl<T> CellsSchemaExt for T
108where
109    T: CellsSchema,
110{
111    fn map_ref<'a>(self) -> impl CellsSchema<Source = &'a Self::Source>
112    where
113        Self::Source: 'a,
114    {
115        cells_schema(move |f| self.fmt(&mut f.map(|x| *x)))
116    }
117}
118
119impl<T: CellsSchema> CellsSchema for Vec<T> {
120    type Source = T::Source;
121    fn fmt(&self, f: &mut CellsFormatter<Self::Source>) {
122        for s in self {
123            s.fmt(f);
124        }
125    }
126}
127impl<T: CellsSchema> CellsSchema for [T] {
128    type Source = T::Source;
129    fn fmt(&self, f: &mut CellsFormatter<Self::Source>) {
130        for s in self {
131            s.fmt(f);
132        }
133    }
134}
135impl<T: ?Sized + CellsSchema> CellsSchema for &T {
136    type Source = T::Source;
137    fn fmt(&self, f: &mut CellsFormatter<Self::Source>) {
138        T::fmt(self, f)
139    }
140}
141
142/// [`CellsSchema`] implementation that use [`Cells`].
143#[derive(Clone, Copy, Debug)]
144#[derive_ex(Default(bound()))]
145pub struct DefaultCellsSchema<T: ?Sized>(PhantomData<T>);
146
147impl<T: Cells + ?Sized> CellsSchema for DefaultCellsSchema<T> {
148    type Source = T;
149    fn fmt(&self, f: &mut CellsFormatter<Self::Source>) {
150        T::fmt(f);
151    }
152}
153
154/// Create [`CellsSchema`] from closure.
155///
156/// # Examples
157///
158/// By calculating the number of columns at runtime and creating a schema,
159/// it is possible to create tables where the number of columns cannot be obtained statically.
160///
161/// ```rust
162/// use text_grid::*;
163/// let rows = [vec![1, 2, 3], vec![1, 2], vec![1, 2, 3, 4]];
164/// let max_colunm_count = rows.iter().map(|r| r.len()).max().unwrap_or(0);
165/// let schema = cells_schema::<Vec<u32>>(move |f| {
166///     for i in 0..max_colunm_count {
167///         f.column(i, |x| x.get(i));
168///     }
169/// });
170/// let g = to_grid_with_schema(rows, schema);
171/// assert_eq!(format!("\n{g}"), OUTPUT);
172///
173/// const OUTPUT: &str = r"
174///  0 | 1 | 2 | 3 |
175/// ---|---|---|---|
176///  1 | 2 | 3 |   |
177///  1 | 2 |   |   |
178///  1 | 2 | 3 | 4 |
179/// ";
180/// ```
181pub fn cells_schema<T: ?Sized>(
182    fmt: impl Fn(&mut CellsFormatter<T>),
183) -> impl CellsSchema<Source = T> {
184    struct FnCellsSchema<T: ?Sized, F> {
185        fmt: F,
186        _phantom: PhantomData<fn(&mut CellsFormatter<T>)>,
187    }
188
189    impl<T: ?Sized, F: Fn(&mut CellsFormatter<T>)> CellsSchema for FnCellsSchema<T, F> {
190        type Source = T;
191        fn fmt(&self, f: &mut CellsFormatter<T>) {
192            (self.fmt)(f)
193        }
194    }
195    FnCellsSchema {
196        fmt,
197        _phantom: PhantomData,
198    }
199}
200
201macro_rules! impl_for_tuple {
202    ($($idx:tt : $ty:ident,)*) => {
203        impl<$($ty),*> Cells for ($($ty,)*) where $($ty: Cells),* {
204            fn fmt(f: &mut CellsFormatter<Self>) {
205                $(
206                    f.map_with(|x| &x.$idx, Cells::fmt);
207                )*
208            }
209        }
210
211        impl<$($ty),*> CellsSchema for ($($ty,)*)
212        where
213            $($ty: CellsSchema, $ty::Source: Sized,)*
214        {
215            type Source = ($($ty::Source,)*);
216            fn fmt(&self, f: &mut CellsFormatter<Self::Source>) {
217                $(self.$idx.fmt(&mut f.map(|x| &x.$idx));)*
218            }
219        }
220    };
221}
222
223impl_for_tuple!(0: T0,);
224impl_for_tuple!(0: T0, 1: T1,);
225impl_for_tuple!(0: T0, 1: T1, 2: T2,);
226impl_for_tuple!(0: T0, 1: T1, 2: T2, 3: T3,);
227impl_for_tuple!(0: T0, 1: T1, 2: T2, 3: T3, 4: T4,);
228impl_for_tuple!(0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5,);
229impl_for_tuple!(0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6,);
230impl_for_tuple!(0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7,);
231impl_for_tuple!(
232    0: T0,
233    1: T1,
234    2: T2,
235    3: T3,
236    4: T4,
237    5: T5,
238    6: T6,
239    7: T7,
240    8: T8,
241);
242impl_for_tuple!(
243    0: T0,
244    1: T1,
245    2: T2,
246    3: T3,
247    4: T4,
248    5: T5,
249    6: T6,
250    7: T7,
251    8: T8,
252    9: T9,
253);
254impl_for_tuple!(
255    0: T0,
256    1: T1,
257    2: T2,
258    3: T3,
259    4: T4,
260    5: T5,
261    6: T6,
262    7: T7,
263    8: T8,
264    9: T9,
265    10: T10,
266);
267impl_for_tuple!(
268    0: T0,
269    1: T1,
270    2: T2,
271    3: T3,
272    4: T4,
273    5: T5,
274    6: T6,
275    7: T7,
276    8: T8,
277    9: T9,
278    10: T10,
279    11: T11,
280);
281impl_for_tuple!(
282    0: T0,
283    1: T1,
284    2: T2,
285    3: T3,
286    4: T4,
287    5: T5,
288    6: T6,
289    7: T7,
290    8: T8,
291    9: T9,
292    10: T10,
293    11: T11,
294    12: T12,
295);
296impl_for_tuple!(
297    0: T0,
298    1: T1,
299    2: T2,
300    3: T3,
301    4: T4,
302    5: T5,
303    6: T6,
304    7: T7,
305    8: T8,
306    9: T9,
307    10: T10,
308    11: T11,
309    12: T12,
310    13: T13,
311);
312impl_for_tuple!(
313    0: T0,
314    1: T1,
315    2: T2,
316    3: T3,
317    4: T4,
318    5: T5,
319    6: T6,
320    7: T7,
321    8: T8,
322    9: T9,
323    10: T10,
324    11: T11,
325    12: T12,
326    13: T13,
327    14: T14,
328);
329impl_for_tuple!(
330    0: T0,
331    1: T1,
332    2: T2,
333    3: T3,
334    4: T4,
335    5: T5,
336    6: T6,
337    7: T7,
338    8: T8,
339    9: T9,
340    10: T10,
341    11: T11,
342    12: T12,
343    13: T13,
344    14: T14,
345    15: T15,
346);