1#[cfg(feature = "export")]
2use crate::Exporter;
3use crate::{Row, TableColumn, TableContext};
4use dioxus::prelude::*;
5
6#[allow(clippy::type_complexity, reason = "to provide internal API")]
41pub trait Columns<R: Row>: Clone + PartialEq + 'static {
42 fn column_names(&self) -> Vec<String>;
44 fn headers(&self) -> Vec<Box<dyn Fn(&TableContext<Self>, Vec<Attribute>) -> Element + '_>>;
46 fn columns(&self) -> Vec<Box<dyn Fn(&TableContext<Self>, &R, Vec<Attribute>) -> Element + '_>>;
48 fn filter(&self, row: &R) -> bool;
50 fn compare(&self) -> Vec<Box<dyn Fn(&R, &R) -> std::cmp::Ordering + '_>>;
52}
53
54#[cfg(feature = "export")]
56pub struct SerializableHeader<'a> {
57 pub header_fn: Box<dyn Fn() -> String + 'a>,
58 pub include_in_export: bool,
59}
60
61#[cfg(feature = "export")]
63#[allow(clippy::type_complexity)]
64pub struct SerializableCell<'a, R, E: Exporter> {
65 pub cell_fn: Box<dyn Fn(usize, usize, &R, &mut E) -> Result<(), E::Error> + 'a>,
66 pub include_in_export: bool,
67}
68
69#[cfg(feature = "export")]
73pub trait SerializableColumns<R: Row>: Columns<R> {
74 fn serialize_headers(&self) -> Vec<SerializableHeader<'_>>;
76 fn serialize_cell<E: Exporter>(&self) -> Vec<SerializableCell<'_, R, E>>;
78}
79
80macro_rules! columns {
81 ($($number:tt => $column:ident),*) => {
82 impl<$($column: TableColumn<R>),*, R: Row> Columns<R> for ($($column),*,) {
83 fn column_names(&self) -> Vec<String> {
84 vec![$(self.$number.column_name()),*]
85 }
86 fn headers(&self) -> Vec<Box<dyn Fn(&TableContext<Self>, Vec<Attribute>) -> Element + '_>> {
87 vec![$(Box::new(move |context, attributes| {
88 self.$number.render_header(context.data.column_context($number), attributes)
89 })),*]
90 }
91 fn columns(&self) -> Vec<Box<dyn Fn(&TableContext<Self>, &R, Vec<Attribute>) -> Element + '_>> {
92 vec![$(Box::new(move |context, row, attributes| {
93 self.$number.render_cell(context.data.column_context($number), row, attributes)
94 })),*]
95 }
96 fn filter(&self, row: &R) -> bool {
97 $(self.$number.filter(row) &&)* true
98 }
99 fn compare(&self) -> Vec<Box<dyn Fn(&R, &R) -> std::cmp::Ordering + '_>> {
100 vec![$(Box::new(move |a, b| self.$number.compare(a, b))),*]
101 }
102 }
103 #[cfg(feature = "export")]
104 serialize_columns!($($number => $column),*);
105 }
106}
107
108#[cfg(feature = "export")]
109macro_rules! serialize_columns {
110 ($($number:tt => $column:ident),*) => {
111 impl<$($column: crate::SerializableColumn<R>),*, R: Row> SerializableColumns<R> for ($($column),*,) {
112 fn serialize_headers(&self) -> Vec<SerializableHeader<'_>> {
113 vec![$(SerializableHeader {
114 header_fn: Box::new(move || self.$number.header()),
115 include_in_export: self.$number.include_in_export(),
116 }),*]
117 }
118 fn serialize_cell<Ex: Exporter>(&self) -> Vec<SerializableCell<'_, R, Ex>> {
119 vec![$(SerializableCell {
120 cell_fn: Box::new(move |row_index, col_index, row, exporter| -> Result<(), Ex::Error> {
121 exporter.serialize_cell(row_index, col_index, self.$number.serialize_cell(row))
122 }),
123 include_in_export: self.$number.include_in_export(),
124 }),*]
125 }
126 }
127 }
128}
129
130columns!(0 => A);
131columns!(0 => A, 1 => B);
132columns!(0 => A, 1 => B, 2 => C);
133columns!(0 => A, 1 => B, 2 => C, 3 => D);
134columns!(0 => A, 1 => B, 2 => C, 3 => D, 4 => E);
135columns!(0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F);
136columns!(0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => G);
137columns!(0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => G, 7 => H);
138columns!(0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => G, 7 => H, 8 => I);
139columns!(0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => G, 7 => H, 8 => I, 9 => J);
140columns!(0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => G, 7 => H, 8 => I, 9 => J, 10 => K);
141columns!(0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => G, 7 => H, 8 => I, 9 => J, 10 => K, 11 => L);