1use std::borrow::Borrow;
2use std::cell::OnceCell;
3use std::collections::{HashMap, HashSet};
4use std::sync::Arc;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
14pub struct RowKey(pub u64);
15
16impl RowKey {
17 pub fn from_index(index: usize) -> Self {
18 Self(index as u64)
19 }
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24pub struct RowId(pub Arc<str>);
25
26impl RowId {
27 pub fn new(id: impl Into<Arc<str>>) -> Self {
28 Self(id.into())
29 }
30
31 pub fn as_str(&self) -> &str {
32 self.0.as_ref()
33 }
34}
35
36impl From<String> for RowId {
37 fn from(value: String) -> Self {
38 Self::new(value)
39 }
40}
41
42impl From<&str> for RowId {
43 fn from(value: &str) -> Self {
44 Self::new(Arc::<str>::from(value))
45 }
46}
47
48impl AsRef<str> for RowId {
49 fn as_ref(&self) -> &str {
50 self.0.as_ref()
51 }
52}
53
54impl Borrow<str> for RowId {
55 fn borrow(&self) -> &str {
56 self.0.as_ref()
57 }
58}
59
60pub type RowIndex = usize;
62
63#[derive(Debug)]
64pub struct Row<'a, TData> {
65 pub id: RowId,
66 pub key: RowKey,
67 pub original: &'a TData,
68 pub index: usize,
69 pub depth: u16,
70 pub parent: Option<RowIndex>,
71 pub parent_key: Option<RowKey>,
72 pub sub_rows: Vec<RowIndex>,
73}
74
75impl<'a, TData> Clone for Row<'a, TData> {
76 fn clone(&self) -> Self {
77 Self {
78 id: self.id.clone(),
79 key: self.key,
80 original: self.original,
81 index: self.index,
82 depth: self.depth,
83 parent: self.parent,
84 parent_key: self.parent_key,
85 sub_rows: self.sub_rows.clone(),
86 }
87 }
88}
89
90#[derive(Debug)]
91pub struct RowModel<'a, TData> {
92 pub(super) root_rows: Vec<RowIndex>,
93 pub(super) flat_rows: Vec<RowIndex>,
94 pub(super) rows_by_key: HashMap<RowKey, RowIndex>,
95 pub(super) rows_by_id: HashMap<RowId, RowIndex>,
96 pub(super) arena: Vec<Row<'a, TData>>,
97}
98
99impl<'a, TData> Clone for RowModel<'a, TData> {
100 fn clone(&self) -> Self {
101 Self {
102 root_rows: self.root_rows.clone(),
103 flat_rows: self.flat_rows.clone(),
104 rows_by_key: self.rows_by_key.clone(),
105 rows_by_id: self.rows_by_id.clone(),
106 arena: self.arena.clone(),
107 }
108 }
109}
110
111impl<'a, TData> RowModel<'a, TData> {
112 pub fn root_rows(&self) -> &[RowIndex] {
113 &self.root_rows
114 }
115
116 pub fn flat_rows(&self) -> &[RowIndex] {
117 &self.flat_rows
118 }
119
120 pub fn parent_rows(&self, row: RowIndex) -> Vec<RowIndex> {
122 let Some(mut current) = self.row(row).and_then(|r| r.parent) else {
123 return Vec::new();
124 };
125
126 let mut out = Vec::new();
127 while let Some(r) = self.row(current) {
128 out.push(current);
129 let Some(parent) = r.parent else {
130 break;
131 };
132 current = parent;
133 }
134
135 out.reverse();
136 out
137 }
138
139 pub fn parent_row_ids(&self, row: RowIndex) -> Vec<RowId> {
141 self.parent_rows(row)
142 .into_iter()
143 .filter_map(|idx| self.row(idx).map(|r| r.id.clone()))
144 .collect()
145 }
146
147 pub fn leaf_rows(&self, row: RowIndex) -> Vec<RowIndex> {
152 fn push_descendants<TData>(
153 arena: &[Row<'_, TData>],
154 out: &mut Vec<RowIndex>,
155 row: RowIndex,
156 ) {
157 let Some(r) = arena.get(row) else {
158 return;
159 };
160 for &child in &r.sub_rows {
161 out.push(child);
162 push_descendants(arena, out, child);
163 }
164 }
165
166 let mut out = Vec::new();
167 push_descendants(&self.arena, &mut out, row);
168 out
169 }
170
171 pub fn leaf_row_ids(&self, row: RowIndex) -> Vec<RowId> {
173 self.leaf_rows(row)
174 .into_iter()
175 .filter_map(|idx| self.row(idx).map(|r| r.id.clone()))
176 .collect()
177 }
178
179 pub fn row(&self, index: RowIndex) -> Option<&Row<'a, TData>> {
180 self.arena.get(index)
181 }
182
183 pub fn row_by_key(&self, key: RowKey) -> Option<RowIndex> {
184 self.rows_by_key.get(&key).copied()
185 }
186
187 pub fn row_by_id(&self, id: &str) -> Option<RowIndex> {
188 self.rows_by_id.get(id).copied()
189 }
190
191 pub fn rows_by_key(&self) -> &HashMap<RowKey, RowIndex> {
192 &self.rows_by_key
193 }
194
195 pub fn rows_by_id(&self) -> &HashMap<RowId, RowIndex> {
196 &self.rows_by_id
197 }
198
199 pub fn arena(&self) -> &[Row<'a, TData>] {
200 &self.arena
201 }
202}
203
204type GetRowKeyFn<'a, TData> = Box<dyn Fn(&TData, usize, Option<&RowKey>) -> RowKey + 'a>;
205type GetRowIdFn<'a, TData> = Box<dyn Fn(&TData, usize, Option<&RowId>) -> RowId + 'a>;
206type GetSubRowsFn<'a, TData> = Box<dyn for<'r> Fn(&'r TData, usize) -> Option<&'r [TData]> + 'a>;
207type GetGroupedRowModelFn<'a, TData> = Arc<
208 dyn Fn(
209 &RowModel<'a, TData>,
210 &[super::ColumnDef<TData>],
211 &super::GroupingState,
212 ) -> super::GroupedRowModel
213 + 'a,
214>;
215type GetGlobalFacetedRowModelFn<'a, TData> =
216 Arc<dyn Fn(&Table<'a, TData>) -> RowModel<'a, TData> + 'a>;
217type GetGlobalFacetedUniqueValuesFn<'a, TData> =
218 Arc<dyn Fn(&Table<'a, TData>) -> super::FacetCounts + 'a>;
219type GetGlobalFacetedMinMaxU64Fn<'a, TData> =
220 Arc<dyn Fn(&Table<'a, TData>) -> Option<(u64, u64)> + 'a>;
221
222pub struct TableBuilder<'a, TData> {
223 data: &'a [TData],
224 columns: Vec<super::ColumnDef<TData>>,
225 sorting_fns: HashMap<Arc<str>, super::SortingFnDef<TData>>,
226 filter_fns: HashMap<Arc<str>, super::FilterFnDef>,
227 aggregation_fns: HashMap<Arc<str>, super::AggregationFn>,
228 global_filter_fn: super::FilteringFnSpec,
229 get_column_can_global_filter: Option<Arc<dyn Fn(&super::ColumnDef<TData>, &TData) -> bool>>,
230 enable_row_pinning: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
231 enable_row_selection: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
232 enable_multi_row_selection: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
233 enable_sub_row_selection: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
234 get_row_can_expand: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
235 get_is_row_expanded: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
236 get_row_key: Option<GetRowKeyFn<'a, TData>>,
237 get_row_id: Option<GetRowIdFn<'a, TData>>,
238 get_sub_rows: Option<GetSubRowsFn<'a, TData>>,
239 get_grouped_row_model: Option<GetGroupedRowModelFn<'a, TData>>,
240 get_global_faceted_row_model: Option<GetGlobalFacetedRowModelFn<'a, TData>>,
241 get_global_faceted_unique_values: Option<GetGlobalFacetedUniqueValuesFn<'a, TData>>,
242 get_global_faceted_min_max_u64: Option<GetGlobalFacetedMinMaxU64Fn<'a, TData>>,
243 filtered_row_model_override_pre_filtered: bool,
244 sorted_row_model_override_pre_sorted: bool,
245 expanded_row_model_override_pre_expanded: bool,
246 pagination_row_model_override_pre_pagination: bool,
247 initial_state: Option<super::TableState>,
248 state: super::TableState,
249 options: super::TableOptions,
250 render_fallback_value: super::TanStackValue,
251}
252
253impl<'a, TData> TableBuilder<'a, TData> {
254 pub fn new(data: &'a [TData]) -> Self {
255 Self {
256 data,
257 columns: Vec::new(),
258 sorting_fns: HashMap::new(),
259 filter_fns: HashMap::new(),
260 aggregation_fns: HashMap::new(),
261 global_filter_fn: super::FilteringFnSpec::Auto,
262 get_column_can_global_filter: None,
263 enable_row_pinning: None,
264 enable_row_selection: None,
265 enable_multi_row_selection: None,
266 enable_sub_row_selection: None,
267 get_row_can_expand: None,
268 get_is_row_expanded: None,
269 get_row_key: None,
270 get_row_id: None,
271 get_sub_rows: None,
272 get_grouped_row_model: None,
273 get_global_faceted_row_model: None,
274 get_global_faceted_unique_values: None,
275 get_global_faceted_min_max_u64: None,
276 filtered_row_model_override_pre_filtered: false,
277 sorted_row_model_override_pre_sorted: false,
278 expanded_row_model_override_pre_expanded: false,
279 pagination_row_model_override_pre_pagination: false,
280 initial_state: None,
281 state: super::TableState::default(),
282 options: super::TableOptions::default(),
283 render_fallback_value: super::TanStackValue::Null,
284 }
285 }
286
287 pub fn columns(mut self, columns: Vec<super::ColumnDef<TData>>) -> Self {
288 self.columns = columns;
289 self
290 }
291
292 pub fn sorting_fn_builtin(
294 mut self,
295 key: impl Into<Arc<str>>,
296 sorting_fn: super::BuiltInSortingFn,
297 ) -> Self {
298 self.sorting_fns
299 .insert(key.into(), super::SortingFnDef::BuiltIn(sorting_fn));
300 self
301 }
302
303 pub fn sorting_fn_cmp(
305 mut self,
306 key: impl Into<Arc<str>>,
307 cmp: impl Fn(&TData, &TData) -> std::cmp::Ordering + 'static,
308 ) -> Self {
309 self.sorting_fns
310 .insert(key.into(), super::SortingFnDef::Cmp(Arc::new(cmp)));
311 self
312 }
313
314 pub fn filter_fn_builtin(
316 mut self,
317 key: impl Into<Arc<str>>,
318 filter_fn: super::BuiltInFilterFn,
319 ) -> Self {
320 self.filter_fns
321 .insert(key.into(), super::FilterFnDef::BuiltIn(filter_fn));
322 self
323 }
324
325 pub fn filter_fn_value(
327 mut self,
328 key: impl Into<Arc<str>>,
329 f: impl Fn(&super::TanStackValue, &serde_json::Value) -> bool + 'static,
330 ) -> Self {
331 self.filter_fns
332 .insert(key.into(), super::FilterFnDef::Value(Arc::new(f)));
333 self
334 }
335
336 pub fn filter_fn_value_with_meta(
338 mut self,
339 key: impl Into<Arc<str>>,
340 f: impl Fn(&super::TanStackValue, &serde_json::Value, &mut dyn FnMut(serde_json::Value)) -> bool
341 + 'static,
342 ) -> Self {
343 self.filter_fns
344 .insert(key.into(), super::FilterFnDef::ValueWithMeta(Arc::new(f)));
345 self
346 }
347
348 pub fn global_filter_fn(mut self, spec: super::FilteringFnSpec) -> Self {
350 self.global_filter_fn = spec;
351 self
352 }
353
354 pub fn get_column_can_global_filter(
356 mut self,
357 f: impl Fn(&super::ColumnDef<TData>, &TData) -> bool + 'static,
358 ) -> Self {
359 self.get_column_can_global_filter = Some(Arc::new(f));
360 self
361 }
362
363 pub fn state(mut self, state: super::TableState) -> Self {
364 self.state = state;
365 self
366 }
367
368 pub fn initial_state(mut self, initial_state: super::TableState) -> Self {
372 self.initial_state = Some(initial_state);
373 self
374 }
375
376 pub fn options(mut self, options: super::TableOptions) -> Self {
377 self.options = options;
378 self
379 }
380
381 pub fn manual_filtering(mut self, manual: bool) -> Self {
382 self.options.manual_filtering = manual;
383 self
384 }
385
386 pub fn filter_from_leaf_rows(mut self, enabled: bool) -> Self {
387 self.options.filter_from_leaf_rows = enabled;
388 self
389 }
390
391 pub fn max_leaf_row_filter_depth(mut self, depth: usize) -> Self {
392 self.options.max_leaf_row_filter_depth = depth;
393 self
394 }
395
396 pub fn override_filtered_row_model_pre_filtered(mut self) -> Self {
398 self.filtered_row_model_override_pre_filtered = true;
399 self
400 }
401
402 pub fn manual_sorting(mut self, manual: bool) -> Self {
403 self.options.manual_sorting = manual;
404 self
405 }
406
407 pub fn override_sorted_row_model_pre_sorted(mut self) -> Self {
409 self.sorted_row_model_override_pre_sorted = true;
410 self
411 }
412
413 pub fn manual_pagination(mut self, manual: bool) -> Self {
414 self.options.manual_pagination = manual;
415 self
416 }
417
418 pub fn manual_expanding(mut self, manual: bool) -> Self {
419 self.options.manual_expanding = manual;
420 self
421 }
422
423 pub fn override_expanded_row_model_pre_expanded(mut self) -> Self {
425 self.expanded_row_model_override_pre_expanded = true;
426 self
427 }
428
429 pub fn override_pagination_row_model_pre_pagination(mut self) -> Self {
431 self.pagination_row_model_override_pre_pagination = true;
432 self
433 }
434
435 pub fn paginate_expanded_rows(mut self, enabled: bool) -> Self {
436 self.options.paginate_expanded_rows = enabled;
437 self
438 }
439
440 pub fn keep_pinned_rows(mut self, keep: bool) -> Self {
441 self.options.keep_pinned_rows = keep;
442 self
443 }
444
445 pub fn enable_hiding(mut self, enabled: bool) -> Self {
446 self.options.enable_hiding = enabled;
447 self
448 }
449
450 pub fn enable_column_ordering(mut self, enabled: bool) -> Self {
451 self.options.enable_column_ordering = enabled;
452 self
453 }
454
455 pub fn enable_pinning(mut self, enabled: bool) -> Self {
456 self.options.enable_pinning = enabled;
457 self
458 }
459
460 pub fn enable_column_pinning(mut self, enabled: bool) -> Self {
461 self.options.enable_column_pinning = enabled;
462 self
463 }
464
465 pub fn enable_row_pinning(mut self, enabled: bool) -> Self {
466 self.options.enable_row_pinning = enabled;
467 self
468 }
469
470 pub fn enable_row_pinning_by(mut self, f: impl Fn(RowKey, &TData) -> bool + 'static) -> Self {
472 self.enable_row_pinning = Some(Arc::new(f));
473 self
474 }
475
476 pub fn enable_row_selection_by(mut self, f: impl Fn(RowKey, &TData) -> bool + 'static) -> Self {
478 self.enable_row_selection = Some(Arc::new(f));
479 self
480 }
481
482 pub fn enable_multi_row_selection_by(
484 mut self,
485 f: impl Fn(RowKey, &TData) -> bool + 'static,
486 ) -> Self {
487 self.enable_multi_row_selection = Some(Arc::new(f));
488 self
489 }
490
491 pub fn enable_sub_row_selection_by(
493 mut self,
494 f: impl Fn(RowKey, &TData) -> bool + 'static,
495 ) -> Self {
496 self.enable_sub_row_selection = Some(Arc::new(f));
497 self
498 }
499
500 pub fn get_row_can_expand_by(mut self, f: impl Fn(RowKey, &TData) -> bool + 'static) -> Self {
502 self.get_row_can_expand = Some(Arc::new(f));
503 self
504 }
505
506 pub fn get_is_row_expanded_by(mut self, f: impl Fn(RowKey, &TData) -> bool + 'static) -> Self {
508 self.get_is_row_expanded = Some(Arc::new(f));
509 self
510 }
511
512 pub fn enable_column_resizing(mut self, enabled: bool) -> Self {
513 self.options.enable_column_resizing = enabled;
514 self
515 }
516
517 pub fn get_row_key(
518 mut self,
519 f: impl Fn(&TData, usize, Option<&RowKey>) -> RowKey + 'a,
520 ) -> Self {
521 self.get_row_key = Some(Box::new(f));
522 self
523 }
524
525 pub fn get_row_id(mut self, f: impl Fn(&TData, usize, Option<&RowId>) -> RowId + 'a) -> Self {
527 self.get_row_id = Some(Box::new(f));
528 self
529 }
530
531 pub fn get_sub_rows(
532 mut self,
533 f: impl for<'r> Fn(&'r TData, usize) -> Option<&'r [TData]> + 'a,
534 ) -> Self {
535 self.get_sub_rows = Some(Box::new(f));
536 self
537 }
538
539 pub fn get_grouped_row_model(
541 mut self,
542 f: impl Fn(
543 &RowModel<'a, TData>,
544 &[super::ColumnDef<TData>],
545 &super::GroupingState,
546 ) -> super::GroupedRowModel
547 + 'a,
548 ) -> Self {
549 self.get_grouped_row_model = Some(Arc::new(f));
550 self
551 }
552
553 pub fn get_global_faceted_row_model(
555 mut self,
556 f: impl Fn(&Table<'a, TData>) -> RowModel<'a, TData> + 'a,
557 ) -> Self {
558 self.get_global_faceted_row_model = Some(Arc::new(f));
559 self
560 }
561
562 pub fn get_global_faceted_unique_values(
564 mut self,
565 f: impl Fn(&Table<'a, TData>) -> super::FacetCounts + 'a,
566 ) -> Self {
567 self.get_global_faceted_unique_values = Some(Arc::new(f));
568 self
569 }
570
571 pub fn get_global_faceted_min_max_u64(
573 mut self,
574 f: impl Fn(&Table<'a, TData>) -> Option<(u64, u64)> + 'a,
575 ) -> Self {
576 self.get_global_faceted_min_max_u64 = Some(Arc::new(f));
577 self
578 }
579
580 pub fn aggregation_fn(
582 mut self,
583 key: impl Into<Arc<str>>,
584 aggregation_fn: super::AggregationFn,
585 ) -> Self {
586 self.aggregation_fns.insert(key.into(), aggregation_fn);
587 self
588 }
589
590 pub fn render_fallback_value(mut self, value: super::TanStackValue) -> Self {
592 self.render_fallback_value = value;
593 self
594 }
595
596 pub fn build(self) -> Table<'a, TData> {
597 Table::new(self)
598 }
599}
600
601pub struct Table<'a, TData> {
602 data: &'a [TData],
603 column_tree: Vec<super::ColumnDef<TData>>,
604 columns: Vec<super::ColumnDef<TData>>,
605 sorting_fns: HashMap<Arc<str>, super::SortingFnDef<TData>>,
606 filter_fns: HashMap<Arc<str>, super::FilterFnDef>,
607 aggregation_fns: HashMap<Arc<str>, super::AggregationFn>,
608 global_filter_fn: super::FilteringFnSpec,
609 get_column_can_global_filter: Option<Arc<dyn Fn(&super::ColumnDef<TData>, &TData) -> bool>>,
610 enable_row_pinning: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
611 enable_row_selection: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
612 enable_multi_row_selection: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
613 enable_sub_row_selection: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
614 get_row_can_expand: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
615 get_is_row_expanded: Option<Arc<dyn Fn(RowKey, &TData) -> bool>>,
616 get_row_key: GetRowKeyFn<'a, TData>,
617 get_row_id: Option<GetRowIdFn<'a, TData>>,
618 get_sub_rows: Option<GetSubRowsFn<'a, TData>>,
619 get_grouped_row_model: Option<GetGroupedRowModelFn<'a, TData>>,
620 get_global_faceted_row_model: Option<GetGlobalFacetedRowModelFn<'a, TData>>,
621 get_global_faceted_unique_values: Option<GetGlobalFacetedUniqueValuesFn<'a, TData>>,
622 get_global_faceted_min_max_u64: Option<GetGlobalFacetedMinMaxU64Fn<'a, TData>>,
623 filtered_row_model_override_pre_filtered: bool,
624 sorted_row_model_override_pre_sorted: bool,
625 expanded_row_model_override_pre_expanded: bool,
626 pagination_row_model_override_pre_pagination: bool,
627 initial_state: super::TableState,
629 state: super::TableState,
630 options: super::TableOptions,
631 render_fallback_value: super::TanStackValue,
632 core_row_model: OnceCell<RowModel<'a, TData>>,
633 filtered_row_model: OnceCell<RowModel<'a, TData>>,
634 grouped_row_model: OnceCell<super::GroupedRowModel>,
635 grouped_pre_sorted_row_model: OnceCell<RowModel<'a, TData>>,
636 grouped_sorted_row_model: OnceCell<RowModel<'a, TData>>,
637 grouped_u64_aggregations: OnceCell<HashMap<RowKey, Arc<[(super::ColumnId, u64)]>>>,
638 grouped_any_aggregations:
639 OnceCell<HashMap<RowKey, Arc<[(super::ColumnId, super::TanStackValue)]>>>,
640 sorted_row_model: OnceCell<RowModel<'a, TData>>,
641 expanded_row_model: OnceCell<RowModel<'a, TData>>,
642 paginated_row_model: OnceCell<RowModel<'a, TData>>,
643 expanded_paginated_row_model: OnceCell<RowModel<'a, TData>>,
644 selected_row_model: OnceCell<RowModel<'a, TData>>,
645 filtered_selected_row_model: OnceCell<RowModel<'a, TData>>,
646 grouped_selected_row_model: OnceCell<RowModel<'a, TData>>,
647 page_selected_row_model: OnceCell<RowModel<'a, TData>>,
648 faceted_row_model_by_column: OnceCell<Vec<OnceCell<RowModel<'a, TData>>>>,
649 faceted_unique_values_by_column: OnceCell<Vec<OnceCell<super::FacetCounts>>>,
650 faceted_unique_labels_by_column: OnceCell<Vec<OnceCell<super::FacetLabels<'a>>>>,
651 faceted_min_max_u64_by_column: OnceCell<Vec<OnceCell<Option<(u64, u64)>>>>,
652 global_faceted_row_model: OnceCell<RowModel<'a, TData>>,
653 global_faceted_unique_values: OnceCell<super::FacetCounts>,
654 global_faceted_min_max_u64: OnceCell<Option<(u64, u64)>>,
655}
656
657fn rebuild_flat_rows_from_roots_including_duplicates<TData>(row_model: &mut RowModel<'_, TData>) {
658 let roots = row_model.root_rows.clone();
663 let mut flat = Vec::new();
664
665 fn push_flat<TData>(arena: &[Row<'_, TData>], out: &mut Vec<RowIndex>, row: RowIndex) {
666 out.push(row);
667 let Some(r) = arena.get(row) else {
668 return;
669 };
670 for &child in &r.sub_rows {
671 push_flat(arena, out, child);
672 }
673 }
674
675 for root in roots {
676 push_flat(&row_model.arena, &mut flat, root);
677 }
678
679 row_model.flat_rows = flat;
680}
681
682impl<'a, TData> Table<'a, TData> {
683 pub fn builder(data: &'a [TData]) -> TableBuilder<'a, TData> {
684 TableBuilder::new(data)
685 }
686
687 fn new(builder: TableBuilder<'a, TData>) -> Self {
688 fn push_leaf_columns<TData>(
689 cols: &[super::ColumnDef<TData>],
690 out: &mut Vec<super::ColumnDef<TData>>,
691 ) {
692 for col in cols {
693 if col.columns.is_empty() {
694 out.push(col.clone());
695 } else {
696 push_leaf_columns(&col.columns, out);
697 }
698 }
699 }
700
701 let get_row_key = builder
702 .get_row_key
703 .unwrap_or_else(|| Box::new(default_row_key_for_index_path));
704
705 let column_tree = builder.columns;
706 let mut columns: Vec<super::ColumnDef<TData>> = Vec::new();
707 push_leaf_columns(&column_tree, &mut columns);
708
709 let initial_state = builder.initial_state.clone().unwrap_or_default();
712
713 Self {
714 data: builder.data,
715 column_tree,
716 columns,
717 sorting_fns: builder.sorting_fns,
718 filter_fns: builder.filter_fns,
719 aggregation_fns: builder.aggregation_fns,
720 global_filter_fn: builder.global_filter_fn,
721 get_column_can_global_filter: builder.get_column_can_global_filter,
722 enable_row_pinning: builder.enable_row_pinning,
723 enable_row_selection: builder.enable_row_selection,
724 enable_multi_row_selection: builder.enable_multi_row_selection,
725 enable_sub_row_selection: builder.enable_sub_row_selection,
726 get_row_can_expand: builder.get_row_can_expand,
727 get_is_row_expanded: builder.get_is_row_expanded,
728 get_row_key,
729 get_row_id: builder.get_row_id,
730 get_sub_rows: builder.get_sub_rows,
731 get_grouped_row_model: builder.get_grouped_row_model,
732 get_global_faceted_row_model: builder.get_global_faceted_row_model,
733 get_global_faceted_unique_values: builder.get_global_faceted_unique_values,
734 get_global_faceted_min_max_u64: builder.get_global_faceted_min_max_u64,
735 filtered_row_model_override_pre_filtered: builder
736 .filtered_row_model_override_pre_filtered,
737 sorted_row_model_override_pre_sorted: builder.sorted_row_model_override_pre_sorted,
738 expanded_row_model_override_pre_expanded: builder
739 .expanded_row_model_override_pre_expanded,
740 pagination_row_model_override_pre_pagination: builder
741 .pagination_row_model_override_pre_pagination,
742 initial_state,
743 state: builder.state,
744 options: builder.options,
745 render_fallback_value: builder.render_fallback_value,
746 core_row_model: OnceCell::new(),
747 filtered_row_model: OnceCell::new(),
748 grouped_row_model: OnceCell::new(),
749 grouped_pre_sorted_row_model: OnceCell::new(),
750 grouped_sorted_row_model: OnceCell::new(),
751 grouped_u64_aggregations: OnceCell::new(),
752 grouped_any_aggregations: OnceCell::new(),
753 sorted_row_model: OnceCell::new(),
754 expanded_row_model: OnceCell::new(),
755 paginated_row_model: OnceCell::new(),
756 expanded_paginated_row_model: OnceCell::new(),
757 selected_row_model: OnceCell::new(),
758 filtered_selected_row_model: OnceCell::new(),
759 grouped_selected_row_model: OnceCell::new(),
760 page_selected_row_model: OnceCell::new(),
761 faceted_row_model_by_column: OnceCell::new(),
762 faceted_unique_values_by_column: OnceCell::new(),
763 faceted_unique_labels_by_column: OnceCell::new(),
764 faceted_min_max_u64_by_column: OnceCell::new(),
765 global_faceted_row_model: OnceCell::new(),
766 global_faceted_unique_values: OnceCell::new(),
767 global_faceted_min_max_u64: OnceCell::new(),
768 }
769 }
770
771 pub fn data(&self) -> &'a [TData] {
772 self.data
773 }
774
775 pub fn columns(&self) -> &[super::ColumnDef<TData>] {
776 &self.columns
777 }
778
779 pub fn render_fallback_value(&self) -> &super::TanStackValue {
781 &self.render_fallback_value
782 }
783
784 pub fn column_tree(&self) -> &[super::ColumnDef<TData>] {
785 &self.column_tree
786 }
787
788 pub fn column(&self, id: &str) -> Option<&super::ColumnDef<TData>> {
789 self.columns.iter().find(|c| c.id.as_ref() == id)
790 }
791
792 fn tanstack_value_for_item(
793 &self,
794 col: &super::ColumnDef<TData>,
795 item: &TData,
796 ) -> super::TanStackValue {
797 if let Some(get) = col.sort_value.as_ref() {
798 return get(item);
799 }
800 if let Some(get) = col.value_u64_fn.as_ref() {
801 return super::TanStackValue::Number(get(item) as f64);
802 }
803 if let Some(get) = col.facet_key_fn.as_ref() {
804 return super::TanStackValue::Number(get(item) as f64);
805 }
806 if let Some(get) = col.facet_str_fn.as_ref() {
807 return super::TanStackValue::String(Arc::<str>::from(get(item)));
808 }
809 super::TanStackValue::Undefined
810 }
811
812 pub fn cell_value(&self, row_key: RowKey, column_id: &str) -> Option<super::TanStackValue> {
817 let col = self.column(column_id)?;
818 let core = self.core_row_model();
819 let index = core.row_by_key(row_key)?;
820 let row = core.row(index)?;
821 Some(self.tanstack_value_for_item(col, row.original))
822 }
823
824 pub fn cell_render_value(
826 &self,
827 row_key: RowKey,
828 column_id: &str,
829 ) -> Option<super::TanStackValue> {
830 let value = self.cell_value(row_key, column_id)?;
831 match value {
832 super::TanStackValue::Undefined | super::TanStackValue::Null => {
833 Some(self.render_fallback_value.clone())
834 }
835 other => Some(other),
836 }
837 }
838
839 pub fn row_unique_values(
848 &self,
849 row_key: RowKey,
850 column_id: &str,
851 ) -> Option<Vec<super::TanStackValue>> {
852 let col = self.column(column_id)?;
853 let core = self.core_row_model();
854 let index = core.row_by_key(row_key)?;
855 let row = core.row(index)?;
856
857 if let Some(get_unique_values) = col.unique_values_fn.as_ref() {
858 return Some(get_unique_values(row.original, row.index));
859 }
860
861 let has_value_source = col.sort_value.is_some()
862 || col.value_u64_fn.is_some()
863 || col.facet_key_fn.is_some()
864 || col.facet_str_fn.is_some();
865 if !has_value_source {
866 return None;
867 }
868
869 Some(vec![self.tanstack_value_for_item(col, row.original)])
870 }
871
872 fn column_index(&self, id: &str) -> Option<usize> {
873 self.columns.iter().position(|c| c.id.as_ref() == id)
874 }
875
876 pub fn row(&self, row_key: RowKey, search_all: bool) -> Option<&Row<'a, TData>> {
879 let first = if search_all {
880 self.pre_pagination_row_model()
881 } else {
882 self.row_model()
883 };
884
885 first
886 .row_by_key(row_key)
887 .and_then(|i| first.row(i))
888 .or_else(|| {
889 let core = self.core_row_model();
890 core.row_by_key(row_key).and_then(|i| core.row(i))
891 })
892 }
893
894 pub fn row_by_id(&self, row_id: &str, search_all: bool) -> Option<&Row<'a, TData>> {
897 let first = if search_all {
898 self.pre_pagination_row_model()
899 } else {
900 self.row_model()
901 };
902
903 first
904 .row_by_id(row_id)
905 .and_then(|i| first.row(i))
906 .or_else(|| {
907 let core = self.core_row_model();
908 core.row_by_id(row_id).and_then(|i| core.row(i))
909 })
910 }
911
912 pub fn row_key_for_id(&self, row_id: &str, search_all: bool) -> Option<RowKey> {
913 if let Some(row) = self.row_by_id(row_id, search_all) {
914 return Some(row.key);
915 }
916
917 if !self.state.grouping.is_empty() {
918 let grouped = self.grouped_row_model();
919 if let Some(i) = grouped.row_by_id(row_id) {
920 return grouped.row(i).map(|r| r.key);
921 }
922 }
923
924 None
925 }
926
927 pub fn row_id_for_key(&self, row_key: RowKey) -> Option<RowId> {
928 if !self.state.grouping.is_empty() && !self.options.manual_grouping {
929 let grouped = self.grouped_row_model();
930 if let Some(i) = grouped.row_by_key(row_key)
931 && let Some(row) = grouped.row(i)
932 {
933 return Some(row.id.clone());
934 }
935 }
936
937 let core = self.core_row_model();
938 let index = core.row_by_key(row_key)?;
939 let row = core.row(index)?;
940 Some(row.id.clone())
941 }
942
943 pub fn cell_context(
945 &self,
946 row_key: RowKey,
947 column_id: &str,
948 ) -> Option<super::CellContextSnapshot> {
949 let row_id = self.row_id_for_key(row_key)?;
950 let col = self.column(column_id)?;
951 let id = Arc::<str>::from(format!("{}_{}", row_id.as_str(), col.id.as_ref()));
952 Some(super::CellContextSnapshot {
953 id,
954 row_id,
955 row_key,
956 column_id: col.id.clone(),
957 })
958 }
959
960 pub fn state(&self) -> &super::TableState {
961 &self.state
962 }
963
964 pub fn options(&self) -> super::TableOptions {
965 self.options
966 }
967
968 pub fn column_visibility(&self) -> &super::ColumnVisibilityState {
969 &self.state.column_visibility
970 }
971
972 pub fn is_column_visible(&self, column_id: &str) -> Option<bool> {
973 let col = self.column(column_id)?;
974
975 fn is_visible<TData>(
976 col: &super::ColumnDef<TData>,
977 visibility: &super::ColumnVisibilityState,
978 ) -> bool {
979 if !col.columns.is_empty() {
980 return col.columns.iter().any(|c| is_visible(c, visibility));
981 }
982
983 super::is_column_visible(visibility, &col.id)
984 }
985
986 Some(is_visible(col, &self.state.column_visibility))
987 }
988
989 pub fn column_can_hide(&self, column_id: &str) -> Option<bool> {
990 let col = self.column(column_id)?;
991 Some(self.options.enable_hiding && col.enable_hiding)
992 }
993
994 pub fn all_flat_columns(&self) -> Vec<&super::ColumnDef<TData>> {
999 fn push<'a, TData>(
1000 cols: &'a [super::ColumnDef<TData>],
1001 out: &mut Vec<&'a super::ColumnDef<TData>>,
1002 ) {
1003 for col in cols {
1004 out.push(col);
1005 if !col.columns.is_empty() {
1006 push(col.columns.as_slice(), out);
1007 }
1008 }
1009 }
1010
1011 let mut out = Vec::new();
1012 push(self.column_tree.as_slice(), &mut out);
1013 out
1014 }
1015
1016 pub fn visible_flat_columns(&self) -> Vec<&super::ColumnDef<TData>> {
1022 fn is_visible<TData>(
1023 col: &super::ColumnDef<TData>,
1024 visibility: &super::ColumnVisibilityState,
1025 ) -> bool {
1026 if !col.columns.is_empty() {
1027 return col.columns.iter().any(|c| is_visible(c, visibility));
1028 }
1029
1030 super::is_column_visible(visibility, &col.id)
1031 }
1032
1033 fn push<'a, TData>(
1034 cols: &'a [super::ColumnDef<TData>],
1035 visibility: &super::ColumnVisibilityState,
1036 out: &mut Vec<&'a super::ColumnDef<TData>>,
1037 ) {
1038 for col in cols {
1039 if is_visible(col, visibility) {
1040 out.push(col);
1041 }
1042 if !col.columns.is_empty() {
1043 push(col.columns.as_slice(), visibility, out);
1044 }
1045 }
1046 }
1047
1048 let mut out = Vec::new();
1049 push(
1050 self.column_tree.as_slice(),
1051 &self.state.column_visibility,
1052 &mut out,
1053 );
1054 out
1055 }
1056
1057 pub fn hideable_columns(&self) -> Vec<&super::ColumnDef<TData>> {
1058 self.ordered_columns()
1059 .into_iter()
1060 .filter(|c| self.options.enable_hiding && c.enable_hiding)
1061 .collect()
1062 }
1063
1064 pub fn is_all_columns_visible(&self) -> bool {
1065 self.columns
1066 .iter()
1067 .all(|c| super::is_column_visible(&self.state.column_visibility, &c.id))
1068 }
1069
1070 pub fn is_some_columns_visible(&self) -> bool {
1071 self.columns
1072 .iter()
1073 .any(|c| super::is_column_visible(&self.state.column_visibility, &c.id))
1074 }
1075
1076 pub fn toggled_column_visibility(
1077 &self,
1078 column_id: &str,
1079 visible: Option<bool>,
1080 ) -> Option<super::ColumnVisibilityState> {
1081 let col = self.column(column_id)?;
1082 if !(self.options.enable_hiding && col.enable_hiding) {
1083 return Some(self.state.column_visibility.clone());
1084 }
1085 Some(super::toggled_column_visible(
1086 &self.state.column_visibility,
1087 &col.id,
1088 visible,
1089 ))
1090 }
1091
1092 pub fn toggled_all_columns_visible(
1093 &self,
1094 visible: Option<bool>,
1095 ) -> super::ColumnVisibilityState {
1096 let visible = visible.unwrap_or_else(|| !self.is_all_columns_visible());
1097
1098 let mut next = self.state.column_visibility.clone();
1099 for col in &self.columns {
1100 let can_hide = self.options.enable_hiding && col.enable_hiding;
1101 if visible {
1102 super::set_column_visible(&mut next, &col.id, true);
1103 } else {
1104 super::set_column_visible(&mut next, &col.id, !can_hide);
1105 }
1106 }
1107 next
1108 }
1109
1110 pub fn is_some_rows_expanded(&self) -> bool {
1111 super::is_some_rows_expanded(&self.state.expanding)
1112 }
1113
1114 pub fn toggled_all_rows_expanded(&self, value: Option<bool>) -> super::ExpandingState {
1115 let value = value.unwrap_or_else(|| !self.is_all_rows_expanded());
1116 let mut next = self.state.expanding.clone();
1117 super::set_all_rows_expanded(&mut next, value);
1118 next
1119 }
1120
1121 pub fn toggled_row_expanded(
1122 &self,
1123 row_key: RowKey,
1124 value: Option<bool>,
1125 ) -> super::ExpandingState {
1126 self.row_expanding_updater(row_key, value)
1127 .apply(&self.state.expanding)
1128 }
1129
1130 pub fn row_expanding_updater(
1131 &self,
1132 row_key: RowKey,
1133 value: Option<bool>,
1134 ) -> super::Updater<super::ExpandingState> {
1135 let visible_row_keys: Vec<RowKey> = if self.state.grouping.is_empty() {
1136 self.row_model().rows_by_key().keys().copied().collect()
1137 } else {
1138 let grouped = self.grouped_row_model();
1139 grouped
1140 .flat_rows()
1141 .iter()
1142 .filter_map(|&index| grouped.row(index).map(|row| row.key))
1143 .collect()
1144 };
1145 super::Updater::Func(Arc::new(move |old| {
1146 let mut next = old.clone();
1147 let exists = super::is_row_expanded(row_key, &next);
1148 let expanded_value = value.unwrap_or(!exists);
1149
1150 match &mut next {
1151 super::ExpandingState::All => {
1152 if expanded_value {
1153 return next;
1154 }
1155
1156 let mut keys: HashSet<RowKey> = visible_row_keys.iter().copied().collect();
1157 keys.remove(&row_key);
1158 next = super::ExpandingState::Keys(keys);
1159 }
1160 super::ExpandingState::Keys(keys) => {
1161 if expanded_value {
1162 keys.insert(row_key);
1163 } else {
1164 keys.remove(&row_key);
1165 }
1166 }
1167 }
1168
1169 next
1170 }))
1171 }
1172
1173 pub fn row_expanding_updater_by_id(
1174 &self,
1175 row_id: &str,
1176 search_all: bool,
1177 value: Option<bool>,
1178 ) -> Option<super::Updater<super::ExpandingState>> {
1179 let row_key = self.row_key_for_id(row_id, search_all)?;
1180 Some(self.row_expanding_updater(row_key, value))
1181 }
1182
1183 pub fn toggled_row_expanded_by_id(
1184 &self,
1185 row_id: &str,
1186 search_all: bool,
1187 value: Option<bool>,
1188 ) -> Option<super::ExpandingState> {
1189 let updater = self.row_expanding_updater_by_id(row_id, search_all, value)?;
1190 Some(updater.apply(&self.state.expanding))
1191 }
1192
1193 pub fn should_auto_reset_expanded(&self) -> bool {
1195 self.options
1196 .auto_reset_all
1197 .or(self.options.auto_reset_expanded)
1198 .unwrap_or(!self.options.manual_expanding)
1199 }
1200
1201 pub fn reset_expanded(&self, default_state: bool) -> super::ExpandingState {
1203 if default_state {
1204 super::ExpandingState::default()
1205 } else {
1206 self.initial_state.expanding.clone()
1207 }
1208 }
1209
1210 pub fn should_auto_reset_page_index(&self) -> bool {
1212 self.options
1213 .auto_reset_all
1214 .or(self.options.auto_reset_page_index)
1215 .unwrap_or(!self.options.manual_pagination)
1216 }
1217
1218 pub fn reset_page_index(&self, default_state: bool) -> super::PaginationState {
1220 let value = if default_state {
1221 0
1222 } else {
1223 self.initial_state.pagination.page_index as i32
1224 };
1225 self.set_page_index(value)
1226 }
1227
1228 pub fn reset_page_size(&self, default_state: bool) -> super::PaginationState {
1230 let value = if default_state {
1231 10
1232 } else {
1233 self.initial_state.pagination.page_size as i32
1234 };
1235 self.set_page_size(value)
1236 }
1237
1238 pub fn reset_pagination(&self, default_state: bool) -> super::PaginationState {
1240 if default_state {
1241 super::PaginationState::default()
1242 } else {
1243 self.initial_state.pagination
1244 }
1245 }
1246
1247 pub fn set_page_index(&self, page_index: i32) -> super::PaginationState {
1249 super::PaginationState {
1250 page_index: Self::clamp_page_index(page_index, self.options.page_count),
1251 page_size: self.state.pagination.page_size,
1252 }
1253 }
1254
1255 pub fn pagination_updater_set_page_index(
1256 &self,
1257 page_index: i32,
1258 ) -> super::Updater<super::PaginationState> {
1259 let page_count_hint = self.options.page_count;
1260 super::Updater::Func(Arc::new(move |old| super::PaginationState {
1261 page_index: Self::clamp_page_index(page_index, page_count_hint),
1262 page_size: old.page_size,
1263 }))
1264 }
1265
1266 pub fn set_page_size(&self, page_size: i32) -> super::PaginationState {
1268 let page_size = (page_size as i64).max(1) as usize;
1269 let top_row_index = self
1270 .state
1271 .pagination
1272 .page_size
1273 .saturating_mul(self.state.pagination.page_index);
1274 let page_index = top_row_index / page_size;
1275 super::PaginationState {
1276 page_index,
1277 page_size,
1278 }
1279 }
1280
1281 pub fn pagination_updater_set_page_size(
1282 &self,
1283 page_size: i32,
1284 ) -> super::Updater<super::PaginationState> {
1285 super::Updater::Func(Arc::new(move |old| {
1286 let page_size = (page_size as i64).max(1) as usize;
1287 let top_row_index = old.page_size.saturating_mul(old.page_index);
1288 let page_index = top_row_index / page_size;
1289 super::PaginationState {
1290 page_index,
1291 page_size,
1292 }
1293 }))
1294 }
1295
1296 pub fn previous_page(&self) -> super::PaginationState {
1298 let current = self.state.pagination.page_index as i32;
1299 self.set_page_index(current.saturating_sub(1))
1300 }
1301
1302 pub fn next_page(&self) -> super::PaginationState {
1304 let current = self.state.pagination.page_index as i32;
1305 self.set_page_index(current.saturating_add(1))
1306 }
1307
1308 pub fn first_page(&self) -> super::PaginationState {
1310 self.set_page_index(0)
1311 }
1312
1313 pub fn last_page(&self) -> super::PaginationState {
1315 self.set_page_index(self.page_count().saturating_sub(1))
1316 }
1317
1318 pub fn row_count(&self) -> usize {
1320 self.options
1321 .row_count
1322 .unwrap_or_else(|| self.pre_pagination_row_model().root_rows().len())
1323 }
1324
1325 pub fn page_count(&self) -> i32 {
1327 if let Some(page_count) = self.options.page_count {
1328 return page_count;
1329 }
1330 let page_size = self.state.pagination.page_size;
1331 if page_size == 0 {
1332 return 0;
1333 }
1334 let count = self.row_count().div_ceil(page_size);
1335 i32::try_from(count).unwrap_or(i32::MAX)
1336 }
1337
1338 pub fn can_previous_page(&self) -> bool {
1340 self.state.pagination.page_index > 0
1341 }
1342
1343 pub fn can_next_page(&self) -> bool {
1345 let page_index = self.state.pagination.page_index;
1346 let page_count = self.page_count();
1347 if page_count == -1 {
1348 return true;
1349 }
1350 if page_count == 0 {
1351 return false;
1352 }
1353 let Ok(page_count) = usize::try_from(page_count) else {
1354 return false;
1355 };
1356 page_index + 1 < page_count
1357 }
1358
1359 pub fn page_options(&self) -> Vec<usize> {
1361 let page_count = self.page_count();
1362 if page_count <= 0 {
1363 return Vec::new();
1364 }
1365 let Ok(page_count) = usize::try_from(page_count) else {
1366 return Vec::new();
1367 };
1368 (0..page_count).collect()
1369 }
1370
1371 fn clamp_page_index(page_index: i32, page_count_hint: Option<i32>) -> usize {
1372 let max = match page_count_hint {
1373 None => i32::MAX,
1374 Some(-1) => i32::MAX,
1375 Some(n) => n.saturating_sub(1),
1376 };
1377 if max < 0 {
1378 return 0;
1379 }
1380 page_index.max(0).min(max) as usize
1381 }
1382
1383 pub fn grouping(&self) -> &super::GroupingState {
1384 &self.state.grouping
1385 }
1386
1387 pub fn column_can_group(&self, column_id: &str) -> Option<bool> {
1388 let col = self.column(column_id)?;
1389 Some(super::column_can_group(self.options, col))
1390 }
1391
1392 pub fn is_column_grouped(&self, column_id: &str) -> Option<bool> {
1393 let col = self.column(column_id)?;
1394 Some(super::is_column_grouped(&self.state.grouping, &col.id))
1395 }
1396
1397 pub fn column_grouped_index(&self, column_id: &str) -> Option<usize> {
1398 let col = self.column(column_id)?;
1399 super::grouped_index(&self.state.grouping, &col.id)
1400 }
1401
1402 pub fn toggled_column_grouping(
1403 &self,
1404 column_id: &str,
1405 grouped: Option<bool>,
1406 ) -> Option<super::GroupingState> {
1407 let col = self.column(column_id)?;
1408 Some(super::toggled_column_grouping_value(
1409 &self.state.grouping,
1410 &col.id,
1411 grouped,
1412 ))
1413 }
1414
1415 pub fn grouping_updater(
1418 &self,
1419 column_id: &str,
1420 grouped: Option<bool>,
1421 ) -> Option<super::Updater<super::GroupingState>> {
1422 let col = self.column(column_id)?;
1423 let id = col.id.clone();
1424 Some(super::Updater::Func(Arc::new(move |old| {
1425 super::toggled_column_grouping_value(old, &id, grouped)
1426 })))
1427 }
1428
1429 pub fn grouping_handler_updater(
1432 &self,
1433 column_id: &str,
1434 ) -> Option<super::Updater<super::GroupingState>> {
1435 let col = self.column(column_id)?;
1436 if !super::column_can_group(self.options, col) {
1437 return Some(super::Updater::Func(Arc::new(|old| old.clone())));
1438 }
1439 self.grouping_updater(column_id, None)
1440 }
1441
1442 pub fn pre_grouped_row_model(&self) -> &RowModel<'a, TData> {
1443 self.filtered_row_model()
1444 }
1445
1446 fn can_compute_grouped_row_model(&self) -> bool {
1447 if self.state.grouping.is_empty() {
1448 return false;
1449 }
1450
1451 self.state.grouping.iter().all(|column_id| {
1452 self.column(column_id.as_ref()).is_some_and(|column| {
1453 column.facet_key_fn.is_some() || column.facet_str_fn.is_some()
1454 })
1455 })
1456 }
1457
1458 pub fn grouped_row_model(&self) -> &super::GroupedRowModel {
1459 if self.options.manual_grouping
1460 || self.state.grouping.is_empty()
1461 || !self.can_compute_grouped_row_model()
1462 {
1463 return self
1464 .grouped_row_model
1465 .get_or_init(|| super::grouped_row_model_from_leaf(self.pre_grouped_row_model()));
1466 }
1467
1468 self.grouped_row_model.get_or_init(|| {
1469 if let Some(get_grouped_row_model) = self.get_grouped_row_model.as_ref() {
1470 return get_grouped_row_model(
1471 self.pre_grouped_row_model(),
1472 &self.columns,
1473 &self.state.grouping,
1474 );
1475 }
1476
1477 super::group_row_model(
1478 self.pre_grouped_row_model(),
1479 &self.columns,
1480 &self.state.grouping,
1481 )
1482 })
1483 }
1484
1485 fn grouped_row_original(&self, grouped_row: &super::GroupedRow) -> Option<&'a TData> {
1486 let row_key = match &grouped_row.kind {
1487 super::GroupedRowKind::Leaf { row_key } => *row_key,
1488 super::GroupedRowKind::Group {
1489 first_leaf_row_key, ..
1490 } => *first_leaf_row_key,
1491 };
1492 let core = self.core_row_model();
1493 core.row_by_key(row_key)
1494 .and_then(|index| core.row(index).map(|row| row.original))
1495 }
1496
1497 fn grouped_row_index_in_core(&self, grouped_row: &super::GroupedRow, fallback: usize) -> usize {
1498 let row_key = match &grouped_row.kind {
1499 super::GroupedRowKind::Leaf { row_key } => *row_key,
1500 super::GroupedRowKind::Group {
1501 first_leaf_row_key, ..
1502 } => *first_leaf_row_key,
1503 };
1504 let core = self.core_row_model();
1505 core.row_by_key(row_key)
1506 .and_then(|index| core.row(index).map(|row| row.index))
1507 .unwrap_or(fallback)
1508 }
1509
1510 fn build_grouped_row_model_as_row_model(
1511 &self,
1512 sorting: &[super::SortSpec],
1513 preserve_grouped_flat_rows: bool,
1514 ) -> RowModel<'a, TData> {
1515 let grouped = self.grouped_row_model();
1516
1517 let mut row_model = RowModel {
1518 root_rows: Vec::new(),
1519 flat_rows: Vec::new(),
1520 rows_by_key: HashMap::new(),
1521 rows_by_id: HashMap::new(),
1522 arena: Vec::new(),
1523 };
1524
1525 if grouped.root_rows().is_empty() {
1526 return row_model;
1527 }
1528
1529 let mut root_grouped_rows: Vec<super::GroupedRowIndex> = grouped.root_rows().to_vec();
1530 let mut sorted_children_by_grouped_index: HashMap<
1531 super::GroupedRowIndex,
1532 Vec<super::GroupedRowIndex>,
1533 > = HashMap::new();
1534
1535 let mut row_index_by_key: HashMap<RowKey, usize> = HashMap::new();
1536 let core = self.core_row_model();
1537 for &index in core.flat_rows() {
1538 let Some(row) = core.row(index) else {
1539 continue;
1540 };
1541 row_index_by_key.entry(row.key).or_insert(row.index);
1542 }
1543
1544 if !sorting.is_empty() {
1545 super::sort_grouped_row_indices_in_place(
1546 grouped,
1547 root_grouped_rows.as_mut_slice(),
1548 sorting,
1549 self.columns.as_slice(),
1550 self.data,
1551 &row_index_by_key,
1552 self.grouped_u64_aggregations(),
1553 self.grouped_aggregations_any(),
1554 );
1555
1556 fn sort_children_recursive<TData>(
1557 table: &Table<'_, TData>,
1558 grouped: &super::GroupedRowModel,
1559 node: super::GroupedRowIndex,
1560 sorting: &[super::SortSpec],
1561 columns: &[super::ColumnDef<TData>],
1562 data: &[TData],
1563 row_index_by_key: &HashMap<RowKey, usize>,
1564 sorted_children_by_grouped_index: &mut HashMap<
1565 super::GroupedRowIndex,
1566 Vec<super::GroupedRowIndex>,
1567 >,
1568 ) {
1569 let Some(row) = grouped.row(node) else {
1570 return;
1571 };
1572 if row.sub_rows.is_empty() {
1573 return;
1574 }
1575
1576 let mut children = row.sub_rows.clone();
1577 super::sort_grouped_row_indices_in_place(
1578 grouped,
1579 children.as_mut_slice(),
1580 sorting,
1581 columns,
1582 data,
1583 row_index_by_key,
1584 table.grouped_u64_aggregations(),
1585 table.grouped_aggregations_any(),
1586 );
1587
1588 for &child in &children {
1589 sort_children_recursive(
1590 table,
1591 grouped,
1592 child,
1593 sorting,
1594 columns,
1595 data,
1596 row_index_by_key,
1597 sorted_children_by_grouped_index,
1598 );
1599 }
1600
1601 sorted_children_by_grouped_index.insert(node, children);
1602 }
1603
1604 for &root in &root_grouped_rows {
1605 sort_children_recursive(
1606 self,
1607 grouped,
1608 root,
1609 sorting,
1610 self.columns.as_slice(),
1611 self.data,
1612 &row_index_by_key,
1613 &mut sorted_children_by_grouped_index,
1614 );
1615 }
1616 }
1617
1618 let mut grouped_to_row_index: HashMap<super::GroupedRowIndex, RowIndex> = HashMap::new();
1619
1620 fn materialize_grouped_row<'a, TData>(
1621 table: &Table<'a, TData>,
1622 grouped: &super::GroupedRowModel,
1623 grouped_index: super::GroupedRowIndex,
1624 parent: Option<RowIndex>,
1625 parent_key: Option<RowKey>,
1626 sorted_children_by_grouped_index: &HashMap<
1627 super::GroupedRowIndex,
1628 Vec<super::GroupedRowIndex>,
1629 >,
1630 row_model: &mut RowModel<'a, TData>,
1631 grouped_to_row_index: &mut HashMap<super::GroupedRowIndex, RowIndex>,
1632 ) -> Option<RowIndex> {
1633 let grouped_row = grouped.row(grouped_index)?;
1634 let original = table.grouped_row_original(grouped_row)?;
1635 let depth = u16::try_from(grouped_row.depth).unwrap_or(u16::MAX);
1636 let index = match &grouped_row.kind {
1637 super::GroupedRowKind::Leaf { .. } => {
1638 table.grouped_row_index_in_core(grouped_row, grouped_index)
1639 }
1640 super::GroupedRowKind::Group { .. } => grouped_index,
1641 };
1642
1643 let row_index = row_model.arena.len();
1644 row_model.arena.push(Row {
1645 id: grouped_row.id.clone(),
1646 key: grouped_row.key,
1647 original,
1648 index,
1649 depth,
1650 parent,
1651 parent_key,
1652 sub_rows: Vec::new(),
1653 });
1654
1655 row_model.rows_by_key.insert(grouped_row.key, row_index);
1656 row_model
1657 .rows_by_id
1658 .insert(grouped_row.id.clone(), row_index);
1659 grouped_to_row_index.insert(grouped_index, row_index);
1660
1661 if parent.is_none() {
1662 row_model.root_rows.push(row_index);
1663 }
1664
1665 row_model.flat_rows.push(row_index);
1666
1667 let grouped_children = sorted_children_by_grouped_index
1668 .get(&grouped_index)
1669 .map(|children| children.as_slice())
1670 .unwrap_or_else(|| grouped_row.sub_rows.as_slice());
1671
1672 let mut row_children: Vec<RowIndex> = Vec::with_capacity(grouped_children.len());
1673 for &child_grouped_index in grouped_children {
1674 let Some(child_row_index) = materialize_grouped_row(
1675 table,
1676 grouped,
1677 child_grouped_index,
1678 Some(row_index),
1679 Some(grouped_row.key),
1680 sorted_children_by_grouped_index,
1681 row_model,
1682 grouped_to_row_index,
1683 ) else {
1684 continue;
1685 };
1686 row_children.push(child_row_index);
1687 }
1688
1689 if let Some(row) = row_model.arena.get_mut(row_index) {
1690 row.sub_rows = row_children;
1691 }
1692
1693 Some(row_index)
1694 }
1695
1696 for &root_grouped_index in &root_grouped_rows {
1697 let _ = materialize_grouped_row(
1698 self,
1699 grouped,
1700 root_grouped_index,
1701 None,
1702 None,
1703 &sorted_children_by_grouped_index,
1704 &mut row_model,
1705 &mut grouped_to_row_index,
1706 );
1707 }
1708
1709 if preserve_grouped_flat_rows {
1710 row_model.flat_rows.clear();
1711 for &grouped_index in grouped.flat_rows() {
1712 let Some(row_index) = grouped_to_row_index.get(&grouped_index).copied() else {
1713 continue;
1714 };
1715 row_model.flat_rows.push(row_index);
1716 }
1717 }
1718
1719 row_model
1720 }
1721
1722 fn grouped_pre_sorted_row_model(&self) -> &RowModel<'a, TData> {
1723 self.grouped_pre_sorted_row_model
1724 .get_or_init(|| self.build_grouped_row_model_as_row_model(&[], true))
1725 }
1726
1727 fn grouped_sorted_row_model(&self) -> &RowModel<'a, TData> {
1728 if self.state.sorting.is_empty() {
1729 return self.grouped_pre_sorted_row_model();
1730 }
1731 self.grouped_sorted_row_model.get_or_init(|| {
1732 self.build_grouped_row_model_as_row_model(self.state.sorting.as_slice(), false)
1733 })
1734 }
1735
1736 pub fn grouped_u64_aggregations(&self) -> &HashMap<RowKey, Arc<[(super::ColumnId, u64)]>> {
1737 self.grouped_u64_aggregations.get_or_init(|| {
1738 if self.options.manual_grouping || self.state.grouping.is_empty() {
1739 return Default::default();
1740 }
1741
1742 let grouped = self.grouped_row_model();
1743
1744 let grouped_columns: std::collections::HashSet<&str> =
1745 self.state.grouping.iter().map(|c| c.as_ref()).collect();
1746
1747 let mut agg_columns: Vec<super::ColumnDef<TData>> = Vec::new();
1748 for col in &self.columns {
1749 if grouped_columns.contains(col.id.as_ref()) {
1750 continue;
1751 }
1752
1753 let aggregation = if col.aggregation != super::Aggregation::None {
1754 col.aggregation
1755 } else if col.value_u64_fn.is_some() || col.facet_key_fn.is_some() {
1756 super::Aggregation::SumU64
1759 } else {
1760 continue;
1761 };
1762
1763 let mut next = col.clone();
1764 next.aggregation = aggregation;
1765 agg_columns.push(next);
1766 }
1767
1768 let agg_refs: Vec<&super::ColumnDef<TData>> = agg_columns.iter().collect();
1769 super::compute_grouped_u64_aggregations_from_core(
1770 grouped,
1771 self.core_row_model(),
1772 agg_refs.as_slice(),
1773 )
1774 })
1775 }
1776
1777 pub fn grouped_aggregations_any(
1778 &self,
1779 ) -> &HashMap<RowKey, Arc<[(super::ColumnId, super::TanStackValue)]>> {
1780 self.grouped_any_aggregations.get_or_init(|| {
1781 if self.options.manual_grouping || self.state.grouping.is_empty() {
1782 return Default::default();
1783 }
1784
1785 let grouped = self.grouped_row_model();
1786 if grouped.flat_rows().is_empty() {
1787 return Default::default();
1788 }
1789
1790 let grouped_columns: HashSet<&str> =
1791 self.state.grouping.iter().map(|c| c.as_ref()).collect();
1792
1793 let agg_columns: Vec<&super::ColumnDef<TData>> = self
1794 .columns
1795 .iter()
1796 .filter(|c| !grouped_columns.contains(c.id.as_ref()))
1797 .collect();
1798
1799 if agg_columns.is_empty() {
1800 return Default::default();
1801 }
1802
1803 fn leaf_row_keys(model: &super::GroupedRowModel, node: usize, out: &mut Vec<RowKey>) {
1804 let Some(row) = model.row(node) else {
1805 return;
1806 };
1807 match &row.kind {
1808 super::GroupedRowKind::Leaf { row_key } => out.push(*row_key),
1809 super::GroupedRowKind::Group { .. } => {
1810 for &child in &row.sub_rows {
1811 leaf_row_keys(model, child, out);
1812 }
1813 }
1814 }
1815 }
1816
1817 let core = self.core_row_model();
1818 let mut visited: HashSet<RowKey> = Default::default();
1819 let mut out: HashMap<RowKey, Arc<[(super::ColumnId, super::TanStackValue)]>> =
1820 Default::default();
1821
1822 for &node in grouped.flat_rows() {
1823 let Some(row) = grouped.row(node) else {
1824 continue;
1825 };
1826 if !matches!(row.kind, super::GroupedRowKind::Group { .. }) {
1827 continue;
1828 }
1829 if !visited.insert(row.key) {
1830 continue;
1831 }
1832
1833 let mut leaf_keys: Vec<RowKey> = Vec::new();
1834 leaf_row_keys(grouped, node, &mut leaf_keys);
1835
1836 let mut values: Vec<(super::ColumnId, super::TanStackValue)> = Vec::new();
1837
1838 for col in &agg_columns {
1839 let mut leaf_values: Vec<super::TanStackValue> = Vec::new();
1840 for key in &leaf_keys {
1841 let Some(core_index) = core.row_by_key(*key) else {
1842 continue;
1843 };
1844 let Some(item) = core.row(core_index).map(|r| r.original) else {
1845 continue;
1846 };
1847 leaf_values.push(self.tanstack_value_for_item(col, item));
1848 }
1849
1850 let v = match &col.aggregation_fn {
1851 super::AggregationFnSpec::None => super::TanStackValue::Undefined,
1852 super::AggregationFnSpec::Auto => {
1853 if let Some(builtin) = super::resolve_auto_aggregation(&leaf_values) {
1854 super::apply_builtin_aggregation(builtin, &leaf_values)
1855 } else {
1856 super::TanStackValue::Undefined
1857 }
1858 }
1859 super::AggregationFnSpec::BuiltIn(builtin) => {
1860 super::apply_builtin_aggregation(*builtin, &leaf_values)
1861 }
1862 super::AggregationFnSpec::Named(key) => {
1863 if let Some(custom) = self.aggregation_fns.get(key) {
1864 custom(col.id.as_ref(), &leaf_values)
1865 } else if let Some(builtin) =
1866 super::BuiltInAggregationFn::from_tanstack_key(key.as_ref())
1867 {
1868 super::apply_builtin_aggregation(builtin, &leaf_values)
1869 } else {
1870 super::TanStackValue::Undefined
1871 }
1872 }
1873 };
1874
1875 values.push((col.id.clone(), v));
1876 }
1877
1878 out.insert(row.key, Arc::from(values.into_boxed_slice()));
1879 }
1880
1881 out
1882 })
1883 }
1884
1885 pub fn is_all_rows_expanded(&self) -> bool {
1886 match &self.state.expanding {
1887 super::ExpandingState::All => true,
1888 super::ExpandingState::Keys(keys) if keys.is_empty() => false,
1889 _ => {
1890 let model = self.row_model();
1891 model
1892 .flat_rows()
1893 .iter()
1894 .filter_map(|&i| model.row(i))
1895 .all(|r| self.row_is_expanded_for_row(r))
1896 }
1897 }
1898 }
1899
1900 fn row_is_expanded_for_row(&self, row: &Row<'a, TData>) -> bool {
1901 self.get_is_row_expanded
1902 .as_ref()
1903 .map(|f| f(row.key, row.original))
1904 .unwrap_or_else(|| super::is_row_expanded(row.key, &self.state.expanding))
1905 }
1906
1907 fn row_is_expanded_for_key_and_original(&self, row_key: RowKey, original: &TData) -> bool {
1908 self.get_is_row_expanded
1909 .as_ref()
1910 .map(|f| f(row_key, original))
1911 .unwrap_or_else(|| super::is_row_expanded(row_key, &self.state.expanding))
1912 }
1913
1914 fn row_can_expand_for_row(&self, row: &Row<'a, TData>) -> bool {
1915 self.get_row_can_expand
1916 .as_ref()
1917 .map(|f| f(row.key, row.original))
1918 .unwrap_or_else(|| self.options.enable_expanding && !row.sub_rows.is_empty())
1919 }
1920
1921 pub fn can_some_rows_expand(&self) -> bool {
1922 let model = self.pre_pagination_row_model();
1923 model
1924 .flat_rows()
1925 .iter()
1926 .filter_map(|&i| model.row(i))
1927 .any(|r| self.row_can_expand_for_row(r))
1928 }
1929
1930 pub fn expanded_depth(&self) -> u16 {
1931 super::expanded_depth(self.pre_expanded_row_model(), &self.state.expanding)
1932 }
1933
1934 pub fn row_can_expand(&self, row_key: RowKey) -> bool {
1935 let model = self.core_row_model();
1936 model
1937 .row_by_key(row_key)
1938 .and_then(|i| model.row(i))
1939 .is_some_and(|r| self.row_can_expand_for_row(r))
1940 }
1941
1942 pub fn row_is_all_parents_expanded(&self, row_key: RowKey) -> bool {
1943 let model = self.core_row_model();
1944 let Some(mut current) = model.row_by_key(row_key) else {
1945 return false;
1946 };
1947 loop {
1948 let Some(r) = model.row(current) else {
1949 return true;
1950 };
1951 let Some(parent) = r.parent else {
1952 return true;
1953 };
1954 let Some(parent_row) = model.row(parent) else {
1955 return true;
1956 };
1957 if !self.row_is_expanded_for_row(parent_row) {
1958 return false;
1959 }
1960 current = parent;
1961 }
1962 }
1963
1964 pub fn is_some_rows_pinned(&self, position: Option<super::RowPinPosition>) -> bool {
1965 super::is_some_rows_pinned(&self.state.row_pinning, position)
1966 }
1967
1968 pub fn reset_row_pinning(&self, default_state: bool) -> super::RowPinningState {
1970 if default_state {
1971 super::RowPinningState::default()
1972 } else {
1973 self.initial_state.row_pinning.clone()
1974 }
1975 }
1976
1977 pub fn is_some_columns_pinned(&self, position: Option<super::ColumnPinPosition>) -> bool {
1978 super::is_some_columns_pinned(&self.state.column_pinning, position)
1979 }
1980
1981 pub fn reset_column_pinning(&self, default_state: bool) -> super::ColumnPinningState {
1983 if default_state {
1984 super::ColumnPinningState::default()
1985 } else {
1986 self.initial_state.column_pinning.clone()
1987 }
1988 }
1989
1990 pub fn reset_row_selection(&self, default_state: bool) -> super::RowSelectionState {
1992 if default_state {
1993 super::RowSelectionState::default()
1994 } else {
1995 self.initial_state.row_selection.clone()
1996 }
1997 }
1998
1999 pub fn reset_sorting(&self, default_state: bool) -> super::SortingState {
2001 if default_state {
2002 super::SortingState::default()
2003 } else {
2004 self.initial_state.sorting.clone()
2005 }
2006 }
2007
2008 pub fn tanstack_sorted_flat_row_order_with_cache(
2018 &self,
2019 items_revision: u64,
2020 cache: &mut super::TanStackSortedFlatRowOrderCache,
2021 ) -> (Arc<[super::FlatRowOrderEntry]>, bool) {
2022 let deps = super::TanStackSortedFlatRowOrderDeps {
2023 items_revision,
2024 data_len: self.data.len(),
2025 sorting: self.state.sorting.clone(),
2026 column_filters: self.state.column_filters.clone(),
2027 global_filter: self.state.global_filter.clone(),
2028 options: self.options,
2029 global_filter_fn: self.global_filter_fn.clone(),
2030 has_get_column_can_global_filter: self.get_column_can_global_filter.is_some(),
2031 };
2032
2033 let (order, recomputed) = cache.sorted_order(
2034 self.data,
2035 &self.columns,
2036 self.get_row_key.as_ref(),
2037 &self.filter_fns,
2038 &self.sorting_fns,
2039 self.get_column_can_global_filter.as_deref(),
2040 deps,
2041 );
2042 (order.clone(), recomputed)
2043 }
2044
2045 pub fn tanstack_ungrouped_row_model_order_with_cache(
2055 &self,
2056 items_revision: u64,
2057 cache: &mut super::TanStackUngroupedRowModelOrderCache,
2058 ) -> Option<(Arc<super::TanStackRowModelOrderSnapshot>, bool)> {
2059 if !self.state.grouping.is_empty() && !self.options.manual_grouping {
2060 return None;
2061 }
2062
2063 let deps = super::TanStackUngroupedRowModelOrderDeps {
2064 items_revision,
2065 data_len: self.data.len(),
2066 sorting: self.state.sorting.clone(),
2067 column_filters: self.state.column_filters.clone(),
2068 global_filter: self.state.global_filter.clone(),
2069 expanding: self.state.expanding.clone(),
2070 pagination: self.state.pagination,
2071 options: self.options,
2072 global_filter_fn: self.global_filter_fn.clone(),
2073 has_get_column_can_global_filter: self.get_column_can_global_filter.is_some(),
2074 };
2075
2076 debug_assert_eq!(deps.data_len, self.data.len());
2077 debug_assert_eq!(
2078 deps.has_get_column_can_global_filter,
2079 self.get_column_can_global_filter.is_some()
2080 );
2081
2082 let signature = super::tanstack_memo::columns_signature(&self.columns);
2083 let (value, recomputed) = cache.ungrouped_order(signature, deps, || {
2084 let model = self.row_model();
2085 let rows: Vec<super::RowKey> = model
2086 .root_rows()
2087 .iter()
2088 .filter_map(|&i| model.row(i).map(|r| r.key))
2089 .collect();
2090 let flat_rows: Vec<super::RowKey> = model
2091 .flat_rows()
2092 .iter()
2093 .filter_map(|&i| model.row(i).map(|r| r.key))
2094 .collect();
2095 super::TanStackRowModelOrderSnapshot {
2096 rows: Arc::from(rows.into_boxed_slice()),
2097 flat_rows: Arc::from(flat_rows.into_boxed_slice()),
2098 }
2099 });
2100
2101 Some((value.clone(), recomputed))
2102 }
2103
2104 pub fn column_can_sort(&self, column_id: &str) -> Option<bool> {
2106 let col = self.column(column_id)?;
2107 let has_sort_value_source = col.sort_cmp.is_some() || col.sort_value.is_some();
2108 Some(self.options.enable_sorting && col.enable_sorting && has_sort_value_source)
2109 }
2110
2111 pub fn column_can_multi_sort(&self, column_id: &str) -> Option<bool> {
2113 let col = self.column(column_id)?;
2114 let has_sort_value_source = col.sort_cmp.is_some() || col.sort_value.is_some();
2115
2116 if has_sort_value_source {
2119 Some(self.options.enable_multi_sort && col.enable_multi_sort)
2120 } else {
2121 Some(false)
2122 }
2123 }
2124
2125 pub fn column_auto_sort_dir_desc_tanstack(&self, column_id: &str) -> Option<bool> {
2129 let col = self.column(column_id)?;
2130
2131 let Some(get_value) = col.sort_value.as_ref() else {
2137 return Some(true);
2138 };
2139
2140 let model = self.filtered_row_model();
2141 let first_value = model
2142 .flat_rows()
2143 .first()
2144 .and_then(|&i| model.row(i))
2145 .map(|r| (get_value)(r.original));
2146
2147 let desc = !matches!(first_value, Some(super::TanStackValue::String(_)));
2148 Some(desc)
2149 }
2150
2151 pub fn column_first_sort_dir_desc_tanstack(&self, column_id: &str) -> Option<bool> {
2157 let col = self.column(column_id)?;
2158
2159 if let Some(explicit) = col.sort_desc_first.or(self.options.sort_desc_first) {
2162 return Some(explicit);
2163 }
2164
2165 self.column_auto_sort_dir_desc_tanstack(column_id)
2166 }
2167
2168 pub fn column_next_sorting_order_desc_tanstack(
2176 &self,
2177 column_id: &str,
2178 multi: bool,
2179 ) -> Option<Option<bool>> {
2180 let first_desc = self.column_first_sort_dir_desc_tanstack(column_id)?;
2181 let is_sorted = super::sort_for_column(&self.state.sorting, column_id);
2182
2183 let enable_sorting_removal = self.options.enable_sorting_removal;
2184 let enable_multi_remove = self.options.enable_multi_remove;
2185
2186 match is_sorted {
2187 None => Some(Some(first_desc)),
2188 Some(current_desc) => {
2189 if current_desc != first_desc
2190 && enable_sorting_removal
2191 && (!multi || enable_multi_remove)
2192 {
2193 return Some(None);
2194 }
2195 Some(Some(!current_desc))
2196 }
2197 }
2198 }
2199
2200 pub fn cleared_column_sorting(&self, column_id: &str) -> Option<super::SortingState> {
2202 self.column(column_id)?;
2203
2204 let mut next = self.state.sorting.clone();
2205 next.retain(|spec| spec.column.as_ref() != column_id);
2206 Some(next)
2207 }
2208
2209 pub fn column_is_sorted(&self, column_id: &str) -> Option<bool> {
2211 self.column(column_id)?;
2212 Some(
2213 self.state
2214 .sorting
2215 .iter()
2216 .any(|s| s.column.as_ref() == column_id),
2217 )
2218 }
2219
2220 pub fn column_sort_index(&self, column_id: &str) -> Option<i32> {
2225 self.column(column_id)?;
2226 Some(
2227 self.state
2228 .sorting
2229 .iter()
2230 .position(|s| s.column.as_ref() == column_id)
2231 .map(|i| i as i32)
2232 .unwrap_or(-1),
2233 )
2234 }
2235
2236 pub fn sorting_updater_tanstack(
2240 &self,
2241 column_id: &str,
2242 multi: bool,
2243 auto_sort_dir_desc: bool,
2244 ) -> Option<super::Updater<super::SortingState>> {
2245 let col = self.column(column_id)?;
2246 let toggle_col = super::sorting::SortToggleColumn {
2247 id: col.id.clone(),
2248 enable_sorting: col.enable_sorting,
2249 enable_multi_sort: col.enable_multi_sort,
2250 sort_desc_first: col.sort_desc_first,
2251 has_sort_value_source: col.sort_cmp.is_some() || col.sort_value.is_some(),
2252 };
2253 let options = self.options;
2254 Some(super::Updater::Func(Arc::new(move |old| {
2255 let mut next = old.clone();
2256 super::sorting::toggle_sorting_state_tanstack(
2257 &mut next,
2258 &toggle_col,
2259 options,
2260 multi,
2261 auto_sort_dir_desc,
2262 );
2263 next
2264 })))
2265 }
2266
2267 pub fn sorting_handler_updater_tanstack(
2272 &self,
2273 column_id: &str,
2274 event_multi: bool,
2275 auto_sort_dir_desc: bool,
2276 ) -> Option<super::Updater<super::SortingState>> {
2277 let col = self.column(column_id)?;
2278 let toggle_col = super::sorting::SortToggleColumn {
2279 id: col.id.clone(),
2280 enable_sorting: col.enable_sorting,
2281 enable_multi_sort: col.enable_multi_sort,
2282 sort_desc_first: col.sort_desc_first,
2283 has_sort_value_source: col.sort_cmp.is_some() || col.sort_value.is_some(),
2284 };
2285 let options = self.options;
2286 Some(super::Updater::Func(Arc::new(move |old| {
2287 let mut next = old.clone();
2288 super::sorting::toggle_sorting_state_handler_tanstack(
2289 &mut next,
2290 &toggle_col,
2291 options,
2292 event_multi,
2293 auto_sort_dir_desc,
2294 );
2295 next
2296 })))
2297 }
2298
2299 pub fn toggled_column_sorting_tanstack(
2301 &self,
2302 column_id: &str,
2303 multi: bool,
2304 auto_sort_dir_desc: bool,
2305 ) -> Option<super::SortingState> {
2306 let updater = self.sorting_updater_tanstack(column_id, multi, auto_sort_dir_desc)?;
2307 Some(updater.apply(&self.state.sorting))
2308 }
2309
2310 pub fn toggled_column_sorting_handler_tanstack(
2312 &self,
2313 column_id: &str,
2314 event_multi: bool,
2315 auto_sort_dir_desc: bool,
2316 ) -> Option<super::SortingState> {
2317 let updater =
2318 self.sorting_handler_updater_tanstack(column_id, event_multi, auto_sort_dir_desc)?;
2319 Some(updater.apply(&self.state.sorting))
2320 }
2321
2322 pub fn reset_column_filters(&self, default_state: bool) -> super::ColumnFiltersState {
2324 if default_state {
2325 super::ColumnFiltersState::default()
2326 } else {
2327 self.initial_state.column_filters.clone()
2328 }
2329 }
2330
2331 pub fn reset_global_filter(&self, default_state: bool) -> super::GlobalFilterState {
2333 if default_state {
2334 super::GlobalFilterState::default()
2335 } else {
2336 self.initial_state.global_filter.clone()
2337 }
2338 }
2339
2340 pub fn column_can_filter(&self, column_id: &str) -> Option<bool> {
2341 fn column_has_filter_value_source<TData>(col: &super::ColumnDef<TData>) -> bool {
2342 if col.filter_fn.is_some() || col.filter_fn_with_meta.is_some() {
2343 return true;
2344 }
2345 col.filtering_fn.is_some() && col.sort_value.is_some()
2346 }
2347
2348 let col = self.column(column_id)?;
2349 Some(
2350 self.options.enable_filters
2351 && self.options.enable_column_filters
2352 && col.enable_column_filter
2353 && column_has_filter_value_source(col),
2354 )
2355 }
2356
2357 pub fn column_filter_value(&self, column_id: &str) -> Option<&serde_json::Value> {
2358 self.column(column_id)?;
2359 self.state
2360 .column_filters
2361 .iter()
2362 .find(|f| f.column.as_ref() == column_id)
2363 .map(|f| &f.value)
2364 }
2365
2366 pub fn column_is_filtered(&self, column_id: &str) -> Option<bool> {
2367 self.column(column_id)?;
2368 Some(
2369 self.state
2370 .column_filters
2371 .iter()
2372 .any(|f| f.column.as_ref() == column_id),
2373 )
2374 }
2375
2376 pub fn column_filter_index(&self, column_id: &str) -> Option<i32> {
2381 self.column(column_id)?;
2382 Some(
2383 self.state
2384 .column_filters
2385 .iter()
2386 .position(|f| f.column.as_ref() == column_id)
2387 .map(|i| i as i32)
2388 .unwrap_or(-1),
2389 )
2390 }
2391
2392 pub fn column_filters_updater_set_value(
2394 &self,
2395 column_id: &str,
2396 value: serde_json::Value,
2397 ) -> Option<super::Updater<super::ColumnFiltersState>> {
2398 let col = self.column(column_id)?;
2399 Some(super::filtering::column_filters_updater_set_value_tanstack(
2400 self.data,
2401 col,
2402 &self.filter_fns,
2403 value,
2404 ))
2405 }
2406
2407 pub fn global_filter_updater_set_value(
2409 &self,
2410 value: super::GlobalFilterState,
2411 ) -> super::Updater<super::GlobalFilterState> {
2412 super::filtering::global_filter_updater_set_value_tanstack(value)
2413 }
2414
2415 pub fn column_can_global_filter(&self, column_id: &str) -> Option<bool> {
2417 let col = self.column(column_id)?;
2418 if !(self.options.enable_filters
2419 && self.options.enable_global_filter
2420 && col.enable_global_filter)
2421 {
2422 return Some(false);
2423 }
2424
2425 let first_row_original = self
2426 .pre_filtered_row_model()
2427 .flat_rows()
2428 .first()
2429 .and_then(|&i| self.pre_filtered_row_model().row(i))
2430 .map(|r| r.original);
2431
2432 let can_global_filter = match self.get_column_can_global_filter.as_deref() {
2433 Some(f) => first_row_original.is_some_and(|first| f(col, first)),
2434 None => match first_row_original {
2435 Some(first) => match col.sort_value.as_ref() {
2436 Some(get_value) => matches!(
2437 (get_value)(first),
2438 super::TanStackValue::String(_) | super::TanStackValue::Number(_)
2439 ),
2440 None => col.filter_fn.is_some() || col.filter_fn_with_meta.is_some(),
2441 },
2442 None => false,
2443 },
2444 };
2445
2446 Some(can_global_filter)
2447 }
2448
2449 pub fn reset_grouping(&self, default_state: bool) -> super::GroupingState {
2451 if default_state {
2452 super::GroupingState::default()
2453 } else {
2454 self.initial_state.grouping.clone()
2455 }
2456 }
2457
2458 pub fn reset_column_visibility(&self, default_state: bool) -> super::ColumnVisibilityState {
2460 if default_state {
2461 super::ColumnVisibilityState::default()
2462 } else {
2463 self.initial_state.column_visibility.clone()
2464 }
2465 }
2466
2467 pub fn reset_column_order(&self, default_state: bool) -> super::ColumnOrderState {
2469 if default_state {
2470 super::ColumnOrderState::default()
2471 } else {
2472 self.initial_state.column_order.clone()
2473 }
2474 }
2475
2476 pub fn row_is_pinned(&self, row_key: RowKey) -> Option<super::RowPinPosition> {
2477 super::is_row_pinned(row_key, &self.state.row_pinning)
2478 }
2479
2480 pub fn row_pinned_index(&self, row_key: RowKey) -> Option<i32> {
2485 let exists = if !self.state.grouping.is_empty() && !self.options.manual_grouping {
2486 let grouped = self.grouped_row_model();
2487 grouped.row_by_key(row_key).is_some()
2488 || self.core_row_model().row_by_key(row_key).is_some()
2489 } else {
2490 self.core_row_model().row_by_key(row_key).is_some()
2491 };
2492 if !exists {
2493 return None;
2494 }
2495
2496 let Some(position) = self.row_is_pinned(row_key) else {
2497 return Some(-1);
2498 };
2499
2500 let keys = match position {
2501 super::RowPinPosition::Top => self.top_row_keys(),
2502 super::RowPinPosition::Bottom => self.bottom_row_keys(),
2503 };
2504 Some(
2505 keys.iter()
2506 .position(|k| *k == row_key)
2507 .map(|i| i as i32)
2508 .unwrap_or(-1),
2509 )
2510 }
2511
2512 pub fn row_can_pin(&self, row_key: RowKey) -> Option<bool> {
2513 let core = self.core_row_model();
2514
2515 if let Some(index) = core.row_by_key(row_key) {
2516 let row = core.row(index)?;
2517 if let Some(enable_row_pinning) = self.enable_row_pinning.as_ref() {
2518 return Some(enable_row_pinning(row_key, row.original));
2519 }
2520 return Some(self.options.enable_row_pinning);
2521 }
2522
2523 if !self.state.grouping.is_empty() && !self.options.manual_grouping {
2524 let grouped = self.grouped_row_model();
2525 let index = grouped.row_by_key(row_key)?;
2526 let row = grouped.row(index)?;
2527 if let Some(enable_row_pinning) = self.enable_row_pinning.as_ref() {
2528 let first_leaf_key = match row.kind {
2529 super::GroupedRowKind::Group {
2530 first_leaf_row_key, ..
2531 } => first_leaf_row_key,
2532 super::GroupedRowKind::Leaf { row_key } => row_key,
2533 };
2534 let leaf_index = core.row_by_key(first_leaf_key)?;
2535 let leaf_row = core.row(leaf_index)?;
2536 return Some(enable_row_pinning(row_key, leaf_row.original));
2537 }
2538 return Some(self.options.enable_row_pinning);
2539 }
2540
2541 None
2542 }
2543
2544 pub fn row_pinning_updater(
2545 &self,
2546 row_key: RowKey,
2547 position: Option<super::RowPinPosition>,
2548 include_leaf_rows: bool,
2549 include_parent_rows: bool,
2550 ) -> super::Updater<super::RowPinningState> {
2551 fn pin_grouped_row_keys(
2552 grouped: &super::GroupedRowModel,
2553 row_key: RowKey,
2554 include_leaf_rows: bool,
2555 include_parent_rows: bool,
2556 ) -> Vec<RowKey> {
2557 let Some(row_index) = grouped.row_by_key(row_key) else {
2558 return vec![row_key];
2559 };
2560
2561 let mut keys: Vec<RowKey> = Vec::new();
2562
2563 if include_parent_rows {
2564 let mut parents_rev: Vec<RowKey> = Vec::new();
2565 let mut current = grouped.row(row_index);
2566 while let Some(row) = current {
2567 let Some(parent) = row.parent else {
2568 break;
2569 };
2570 let Some(parent_row) = grouped.row(parent) else {
2571 break;
2572 };
2573 parents_rev.push(parent_row.key);
2574 current = Some(parent_row);
2575 }
2576 parents_rev.reverse();
2577 keys.extend(parents_rev);
2578 }
2579
2580 keys.push(row_key);
2581
2582 if include_leaf_rows {
2583 fn push_descendant_keys(
2584 grouped: &super::GroupedRowModel,
2585 row: usize,
2586 out: &mut Vec<RowKey>,
2587 ) {
2588 let Some(r) = grouped.row(row) else {
2589 return;
2590 };
2591 for &child in &r.sub_rows {
2592 let Some(child_row) = grouped.row(child) else {
2593 continue;
2594 };
2595 out.push(child_row.key);
2596 push_descendant_keys(grouped, child, out);
2597 }
2598 }
2599
2600 push_descendant_keys(grouped, row_index, &mut keys);
2601 }
2602
2603 let mut deduped: Vec<RowKey> = Vec::with_capacity(keys.len());
2604 let mut seen: HashSet<RowKey> = HashSet::new();
2605 for key in keys {
2606 if seen.insert(key) {
2607 deduped.push(key);
2608 }
2609 }
2610
2611 deduped
2612 }
2613
2614 let keys = if self.state.grouping.is_empty() {
2615 super::pin_row_keys(
2616 self.core_row_model(),
2617 row_key,
2618 include_leaf_rows,
2619 include_parent_rows,
2620 )
2621 } else {
2622 let grouped = self.grouped_row_model();
2623 if grouped.row_by_key(row_key).is_some() {
2624 pin_grouped_row_keys(grouped, row_key, include_leaf_rows, include_parent_rows)
2625 } else {
2626 super::pin_row_keys(
2627 self.core_row_model(),
2628 row_key,
2629 include_leaf_rows,
2630 include_parent_rows,
2631 )
2632 }
2633 };
2634
2635 super::Updater::Func(Arc::new(move |old| {
2636 let mut next = old.clone();
2637 super::pin_rows(&mut next, position, keys.clone());
2638 next
2639 }))
2640 }
2641
2642 pub fn row_pinning_updater_by_id(
2643 &self,
2644 row_id: &str,
2645 search_all: bool,
2646 position: Option<super::RowPinPosition>,
2647 include_leaf_rows: bool,
2648 include_parent_rows: bool,
2649 ) -> Option<super::Updater<super::RowPinningState>> {
2650 let row_key = self.row_key_for_id(row_id, search_all)?;
2651 Some(self.row_pinning_updater(row_key, position, include_leaf_rows, include_parent_rows))
2652 }
2653
2654 pub fn top_row_keys(&self) -> Vec<RowKey> {
2655 self.pinned_row_keys(super::RowPinPosition::Top)
2656 }
2657
2658 pub fn top_row_ids(&self) -> Vec<RowId> {
2659 self.top_row_keys()
2660 .into_iter()
2661 .filter_map(|k| self.row_id_for_key(k))
2662 .collect()
2663 }
2664
2665 pub fn bottom_row_keys(&self) -> Vec<RowKey> {
2666 self.pinned_row_keys(super::RowPinPosition::Bottom)
2667 }
2668
2669 pub fn bottom_row_ids(&self) -> Vec<RowId> {
2670 self.bottom_row_keys()
2671 .into_iter()
2672 .filter_map(|k| self.row_id_for_key(k))
2673 .collect()
2674 }
2675
2676 pub fn center_row_keys(&self) -> Vec<RowKey> {
2677 if self.state.grouping.is_empty() || self.options.manual_grouping {
2678 let model = self.row_model();
2679 return super::center_row_keys(model.root_rows(), model, &self.state.row_pinning);
2680 }
2681
2682 let grouped = self.grouped_row_model();
2683 let mut roots: Vec<super::GroupedRowIndex> = grouped.root_rows().to_vec();
2684
2685 let core = self.core_row_model();
2686 let mut row_index_by_key: HashMap<RowKey, usize> = HashMap::new();
2687 for &index in core.flat_rows() {
2688 let Some(row) = core.row(index) else {
2689 continue;
2690 };
2691 row_index_by_key.entry(row.key).or_insert(row.index);
2692 }
2693
2694 super::sort_grouped_row_indices_in_place(
2695 grouped,
2696 &mut roots,
2697 self.state.sorting.as_slice(),
2698 self.columns.as_slice(),
2699 self.data,
2700 &row_index_by_key,
2701 self.grouped_u64_aggregations(),
2702 self.grouped_aggregations_any(),
2703 );
2704
2705 let visible_roots: &[super::GroupedRowIndex] = if self.options.manual_pagination {
2706 roots.as_slice()
2707 } else if self.state.pagination.page_size == 0 {
2708 &[]
2709 } else {
2710 let page_start = self
2711 .state
2712 .pagination
2713 .page_index
2714 .saturating_mul(self.state.pagination.page_size);
2715 let page_end = page_start.saturating_add(self.state.pagination.page_size);
2716 let start = page_start.min(roots.len());
2717 let end = page_end.min(roots.len());
2718 roots.get(start..end).unwrap_or_default()
2719 };
2720
2721 let mut pinned: HashSet<RowKey> = HashSet::new();
2722 pinned.extend(self.state.row_pinning.top.iter().copied());
2723 pinned.extend(self.state.row_pinning.bottom.iter().copied());
2724
2725 visible_roots
2726 .iter()
2727 .filter_map(|&i| grouped.row(i))
2728 .map(|row| row.key)
2729 .filter(|key| !pinned.contains(key))
2730 .collect()
2731 }
2732
2733 pub fn center_row_ids(&self) -> Vec<RowId> {
2734 self.center_row_keys()
2735 .into_iter()
2736 .filter_map(|k| self.row_id_for_key(k))
2737 .collect()
2738 }
2739
2740 fn pinned_row_keys(&self, position: super::RowPinPosition) -> Vec<RowKey> {
2741 let keys = match position {
2742 super::RowPinPosition::Top => self.state.row_pinning.top.as_slice(),
2743 super::RowPinPosition::Bottom => self.state.row_pinning.bottom.as_slice(),
2744 };
2745 if keys.is_empty() {
2746 return Vec::new();
2747 }
2748
2749 if !self.options.keep_pinned_rows {
2750 let visible: std::collections::HashSet<RowKey> = if self.state.grouping.is_empty() {
2751 let model = self.row_model();
2752 model
2753 .root_rows()
2754 .iter()
2755 .filter_map(|&i| model.row(i).map(|r| r.key))
2756 .collect()
2757 } else {
2758 let model = self.grouped_row_model();
2759 model
2760 .root_rows()
2761 .iter()
2762 .filter_map(|&i| model.row(i).map(|r| r.key))
2763 .collect()
2764 };
2765 return keys
2766 .iter()
2767 .copied()
2768 .filter(|k| visible.contains(k))
2769 .collect();
2770 }
2771
2772 if self.state.grouping.is_empty() {
2773 let core = self.core_row_model();
2774 return keys
2775 .iter()
2776 .copied()
2777 .filter(|k| {
2778 core.row_by_key(*k).is_some_and(|i| {
2779 super::row_is_all_parents_expanded(core, &self.state.expanding, i)
2780 })
2781 })
2782 .collect();
2783 }
2784
2785 let grouped = self.grouped_row_model();
2786 keys.iter()
2787 .copied()
2788 .filter(|k| {
2789 grouped.row_by_key(*k).is_some_and(|mut i| {
2790 loop {
2791 let Some(r) = grouped.row(i) else {
2792 return true;
2793 };
2794 let Some(parent) = r.parent else {
2795 return true;
2796 };
2797 let Some(parent_row) = grouped.row(parent) else {
2798 return true;
2799 };
2800 if !super::is_row_expanded(parent_row.key, &self.state.expanding) {
2801 return false;
2802 }
2803 i = parent;
2804 }
2805 })
2806 })
2807 .collect()
2808 }
2809
2810 pub fn ordered_columns(&self) -> Vec<&super::ColumnDef<TData>> {
2811 let ordered = super::order_columns(&self.columns, &self.state.column_order);
2812 let mode = self.options.grouped_column_mode;
2813 let grouping = self.state.grouping.as_slice();
2814
2815 if grouping.is_empty() || mode == super::GroupedColumnMode::None {
2816 return ordered;
2817 }
2818
2819 let is_grouped =
2820 |c: &&super::ColumnDef<TData>| grouping.iter().any(|id| id.as_ref() == c.id.as_ref());
2821
2822 let non_grouped: Vec<&super::ColumnDef<TData>> =
2823 ordered.iter().copied().filter(|c| !is_grouped(c)).collect();
2824
2825 if mode == super::GroupedColumnMode::Remove {
2826 return non_grouped;
2827 }
2828
2829 let by_id: HashMap<&str, &super::ColumnDef<TData>> = ordered
2830 .iter()
2831 .copied()
2832 .map(|c| (c.id.as_ref(), c))
2833 .collect();
2834 let mut grouped_cols: Vec<&super::ColumnDef<TData>> = Vec::new();
2835 for id in grouping {
2836 if let Some(col) = by_id.get(id.as_ref()).copied() {
2837 grouped_cols.push(col);
2838 }
2839 }
2840 grouped_cols.extend(non_grouped);
2841 grouped_cols
2842 }
2843
2844 pub fn column_order(&self) -> &super::ColumnOrderState {
2845 &self.state.column_order
2846 }
2847
2848 pub fn column_pinning(&self) -> &super::ColumnPinningState {
2849 &self.state.column_pinning
2850 }
2851
2852 pub fn column_can_order(&self, column_id: &str) -> Option<bool> {
2853 let col = self.column(column_id)?;
2854 Some(self.options.enable_column_ordering && col.enable_ordering)
2855 }
2856
2857 pub fn column_can_pin(&self, column_id: &str) -> Option<bool> {
2858 fn any_leaf_can_pin<TData>(
2859 col: &super::ColumnDef<TData>,
2860 enable_column_pinning: bool,
2861 ) -> bool {
2862 if col.columns.is_empty() {
2863 return enable_column_pinning && col.enable_pinning;
2864 }
2865 col.columns
2866 .iter()
2867 .any(|c| any_leaf_can_pin(c, enable_column_pinning))
2868 }
2869
2870 let col = self.find_column_in_tree(column_id)?;
2871 Some(any_leaf_can_pin(col, self.options.enable_column_pinning))
2872 }
2873
2874 pub fn column_pin_position(&self, column_id: &str) -> Option<super::ColumnPinPosition> {
2875 let leaf_ids = self.column_leaf_ids_for(column_id)?;
2876
2877 if leaf_ids
2878 .iter()
2879 .any(|id| self.state.column_pinning.left.iter().any(|c| c == id))
2880 {
2881 return Some(super::ColumnPinPosition::Left);
2882 }
2883 if leaf_ids
2884 .iter()
2885 .any(|id| self.state.column_pinning.right.iter().any(|c| c == id))
2886 {
2887 return Some(super::ColumnPinPosition::Right);
2888 }
2889 None
2890 }
2891
2892 pub fn column_pinned_index(&self, column_id: &str) -> Option<i32> {
2897 self.find_column_in_tree(column_id)?;
2898
2899 let Some(position) = self.column_pin_position(column_id) else {
2900 return Some(0);
2901 };
2902
2903 let ids = match position {
2904 super::ColumnPinPosition::Left => self.state.column_pinning.left.as_slice(),
2905 super::ColumnPinPosition::Right => self.state.column_pinning.right.as_slice(),
2906 };
2907 Some(
2908 ids.iter()
2909 .position(|id| id.as_ref() == column_id)
2910 .map(|i| i as i32)
2911 .unwrap_or(-1),
2912 )
2913 }
2914
2915 pub fn column_pinning_updater(
2916 &self,
2917 column_id: &str,
2918 position: Option<super::ColumnPinPosition>,
2919 ) -> Option<super::Updater<super::ColumnPinningState>> {
2920 let leaf_ids = self.column_leaf_ids_for(column_id)?;
2921
2922 Some(super::Updater::Func(Arc::new(move |old| {
2923 super::pinned_columns(old, position, leaf_ids.clone())
2924 })))
2925 }
2926
2927 pub fn toggled_column_order_move(
2928 &self,
2929 column_id: &str,
2930 to_index: usize,
2931 ) -> Option<super::ColumnOrderState> {
2932 let col = self.column(column_id)?;
2933 if !(self.options.enable_column_ordering && col.enable_ordering) {
2934 return Some(self.state.column_order.clone());
2935 }
2936 Some(super::moved_column(
2937 &self.state.column_order,
2938 &col.id,
2939 to_index,
2940 ))
2941 }
2942
2943 pub fn toggled_column_pinning(
2944 &self,
2945 column_id: &str,
2946 position: Option<super::ColumnPinPosition>,
2947 ) -> Option<super::ColumnPinningState> {
2948 let updater = self.column_pinning_updater(column_id, position)?;
2949 Some(updater.apply(&self.state.column_pinning))
2950 }
2951
2952 pub fn visible_columns(&self) -> Vec<&super::ColumnDef<TData>> {
2953 self.ordered_columns()
2954 .into_iter()
2955 .filter(|c| super::is_column_visible(&self.state.column_visibility, &c.id))
2956 .collect()
2957 }
2958
2959 pub fn header_groups(&self) -> Vec<super::HeaderGroupSnapshot> {
2960 let (left, center, right) = self.pinned_visible_columns();
2961 let mut columns_to_group: Vec<std::sync::Arc<str>> = Vec::new();
2962 columns_to_group.extend(left.into_iter().map(|c| c.id.clone()));
2963 columns_to_group.extend(center.into_iter().map(|c| c.id.clone()));
2964 columns_to_group.extend(right.into_iter().map(|c| c.id.clone()));
2965
2966 let leaf_visible = |id: &str| {
2967 self.column(id)
2968 .is_some_and(|c| super::is_column_visible(&self.state.column_visibility, &c.id))
2969 };
2970
2971 super::build_header_groups(&self.column_tree, &columns_to_group, &leaf_visible, None)
2972 }
2973
2974 pub fn left_header_groups(&self) -> Vec<super::HeaderGroupSnapshot> {
2975 let (left, _, _) = self.pinned_visible_columns();
2976 let columns_to_group: Vec<std::sync::Arc<str>> =
2977 left.into_iter().map(|c| c.id.clone()).collect();
2978 let leaf_visible = |id: &str| {
2979 self.column(id)
2980 .is_some_and(|c| super::is_column_visible(&self.state.column_visibility, &c.id))
2981 };
2982 super::build_header_groups(
2983 &self.column_tree,
2984 &columns_to_group,
2985 &leaf_visible,
2986 Some("left"),
2987 )
2988 }
2989
2990 pub fn center_header_groups(&self) -> Vec<super::HeaderGroupSnapshot> {
2991 let (_, center, _) = self.pinned_visible_columns();
2992 let columns_to_group: Vec<std::sync::Arc<str>> =
2993 center.into_iter().map(|c| c.id.clone()).collect();
2994 let leaf_visible = |id: &str| {
2995 self.column(id)
2996 .is_some_and(|c| super::is_column_visible(&self.state.column_visibility, &c.id))
2997 };
2998 super::build_header_groups(
2999 &self.column_tree,
3000 &columns_to_group,
3001 &leaf_visible,
3002 Some("center"),
3003 )
3004 }
3005
3006 pub fn right_header_groups(&self) -> Vec<super::HeaderGroupSnapshot> {
3007 let (_, _, right) = self.pinned_visible_columns();
3008 let columns_to_group: Vec<std::sync::Arc<str>> =
3009 right.into_iter().map(|c| c.id.clone()).collect();
3010 let leaf_visible = |id: &str| {
3011 self.column(id)
3012 .is_some_and(|c| super::is_column_visible(&self.state.column_visibility, &c.id))
3013 };
3014 super::build_header_groups(
3015 &self.column_tree,
3016 &columns_to_group,
3017 &leaf_visible,
3018 Some("right"),
3019 )
3020 }
3021
3022 pub fn footer_groups(&self) -> Vec<super::HeaderGroupSnapshot> {
3023 let mut groups = self.header_groups();
3024 groups.reverse();
3025 groups
3026 }
3027
3028 pub fn left_footer_groups(&self) -> Vec<super::HeaderGroupSnapshot> {
3029 let mut groups = self.left_header_groups();
3030 groups.reverse();
3031 groups
3032 }
3033
3034 pub fn center_footer_groups(&self) -> Vec<super::HeaderGroupSnapshot> {
3035 let mut groups = self.center_header_groups();
3036 groups.reverse();
3037 groups
3038 }
3039
3040 pub fn right_footer_groups(&self) -> Vec<super::HeaderGroupSnapshot> {
3041 let mut groups = self.right_header_groups();
3042 groups.reverse();
3043 groups
3044 }
3045
3046 pub fn flat_headers(&self) -> Vec<super::HeaderSnapshot> {
3047 self.header_groups()
3048 .into_iter()
3049 .flat_map(|g| g.headers)
3050 .collect()
3051 }
3052
3053 pub fn left_flat_headers(&self) -> Vec<super::HeaderSnapshot> {
3054 self.left_header_groups()
3055 .into_iter()
3056 .flat_map(|g| g.headers)
3057 .collect()
3058 }
3059
3060 pub fn center_flat_headers(&self) -> Vec<super::HeaderSnapshot> {
3061 self.center_header_groups()
3062 .into_iter()
3063 .flat_map(|g| g.headers)
3064 .collect()
3065 }
3066
3067 pub fn right_flat_headers(&self) -> Vec<super::HeaderSnapshot> {
3068 self.right_header_groups()
3069 .into_iter()
3070 .flat_map(|g| g.headers)
3071 .collect()
3072 }
3073
3074 pub fn left_leaf_headers(&self) -> Vec<super::HeaderSnapshot> {
3075 self.left_flat_headers()
3076 .into_iter()
3077 .filter(|h| h.sub_header_ids.is_empty())
3078 .collect()
3079 }
3080
3081 pub fn center_leaf_headers(&self) -> Vec<super::HeaderSnapshot> {
3082 self.center_flat_headers()
3083 .into_iter()
3084 .filter(|h| h.sub_header_ids.is_empty())
3085 .collect()
3086 }
3087
3088 pub fn right_leaf_headers(&self) -> Vec<super::HeaderSnapshot> {
3089 self.right_flat_headers()
3090 .into_iter()
3091 .filter(|h| h.sub_header_ids.is_empty())
3092 .collect()
3093 }
3094
3095 pub fn leaf_headers(&self) -> Vec<super::HeaderSnapshot> {
3097 fn recurse(
3098 id: &Arc<str>,
3099 headers_by_id: &HashMap<Arc<str>, super::HeaderSnapshot>,
3100 out: &mut Vec<super::HeaderSnapshot>,
3101 ) {
3102 let Some(h) = headers_by_id.get(id) else {
3103 return;
3104 };
3105 for child in &h.sub_header_ids {
3106 recurse(child, headers_by_id, out);
3107 }
3108 out.push(h.clone());
3109 }
3110
3111 let left = self.left_header_groups();
3112 let center = self.center_header_groups();
3113 let right = self.right_header_groups();
3114
3115 let mut roots: Vec<Arc<str>> = Vec::new();
3116 for groups in [&left, ¢er, &right] {
3117 if let Some(top) = groups.first() {
3118 roots.extend(top.headers.iter().map(|h| h.id.clone()));
3119 }
3120 }
3121
3122 let mut headers_by_id: HashMap<Arc<str>, super::HeaderSnapshot> = HashMap::new();
3123 for groups in [left, center, right] {
3124 for g in groups {
3125 for h in g.headers {
3126 headers_by_id.insert(h.id.clone(), h);
3127 }
3128 }
3129 }
3130
3131 let mut out = Vec::new();
3132 for root in roots {
3133 recurse(&root, &headers_by_id, &mut out);
3134 }
3135 out
3136 }
3137
3138 pub fn row_cells(&self, row_key: RowKey) -> Option<super::RowCellsSnapshot> {
3139 let row = self.row(row_key, true)?;
3140 let row_id = row.id.as_str();
3141
3142 let grouped_column_ids = self.state.grouping.as_slice();
3143 let mut row_grouping_column_id: Option<&str> = None;
3144 if !grouped_column_ids.is_empty() {
3145 let grouped = self.grouped_row_model();
3146 if let Some(grouped_row_index) = grouped.row_by_key(row.key)
3147 && let Some(grouped_row) = grouped.row(grouped_row_index)
3148 && let super::GroupedRowKind::Group {
3149 grouping_column, ..
3150 } = &grouped_row.kind
3151 {
3152 row_grouping_column_id = Some(grouping_column.as_ref());
3153 }
3154 }
3155
3156 let row_has_sub_rows = !row.sub_rows.is_empty();
3157
3158 let all_leaf_columns = self.ordered_columns();
3159 let (left, center, right) = self.pinned_visible_columns();
3160
3161 Some(super::snapshot_cells_for_row(
3162 row_id,
3163 all_leaf_columns.as_slice(),
3164 left.as_slice(),
3165 center.as_slice(),
3166 right.as_slice(),
3167 grouped_column_ids,
3168 row_grouping_column_id,
3169 row_has_sub_rows,
3170 ))
3171 }
3172
3173 pub fn core_model_snapshot(&self) -> super::CoreModelSnapshot {
3174 fn snapshot_row_model_ids<'a, TData>(
3175 model: &RowModel<'a, TData>,
3176 ) -> super::RowModelIdSnapshot {
3177 let root: Vec<Arc<str>> = model
3178 .root_rows()
3179 .iter()
3180 .filter_map(|&i| model.row(i).map(|r| r.id.0.clone()))
3181 .collect();
3182 let flat: Vec<Arc<str>> = model
3183 .flat_rows()
3184 .iter()
3185 .filter_map(|&i| model.row(i).map(|r| r.id.0.clone()))
3186 .collect();
3187 super::RowModelIdSnapshot { root, flat }
3188 }
3189
3190 let column_tree = self.column_tree_snapshot();
3191
3192 let mut column_capabilities: std::collections::BTreeMap<
3193 Arc<str>,
3194 super::ColumnCapabilitySnapshot,
3195 > = std::collections::BTreeMap::new();
3196 for col in self.ordered_columns() {
3197 let id = col.id.clone();
3198 column_capabilities.insert(
3199 id.clone(),
3200 super::ColumnCapabilitySnapshot {
3201 can_hide: self.column_can_hide(id.as_ref()).unwrap_or(false),
3202 can_pin: self.column_can_pin(id.as_ref()).unwrap_or(false),
3203 pin_position: self.column_pin_position(id.as_ref()),
3204 pinned_index: self.column_pinned_index(id.as_ref()).unwrap_or(0),
3205 can_resize: self.column_can_resize(id.as_ref()).unwrap_or(false),
3206 is_visible: self.is_column_visible(id.as_ref()).unwrap_or(false),
3207 },
3208 );
3209 }
3210
3211 let all_leaf = self
3212 .ordered_columns()
3213 .into_iter()
3214 .map(|c| c.id.clone())
3215 .collect::<Vec<_>>();
3216 let visible = self
3217 .visible_columns()
3218 .into_iter()
3219 .map(|c| c.id.clone())
3220 .collect::<Vec<_>>();
3221 let (left, center, right) = self.pinned_visible_columns();
3222 let left_visible = left.into_iter().map(|c| c.id.clone()).collect::<Vec<_>>();
3223 let center_visible = center.into_iter().map(|c| c.id.clone()).collect::<Vec<_>>();
3224 let right_visible = right.into_iter().map(|c| c.id.clone()).collect::<Vec<_>>();
3225
3226 let all_flat = self
3227 .all_flat_columns()
3228 .into_iter()
3229 .map(|c| c.id.clone())
3230 .collect::<Vec<_>>();
3231 let visible_flat = self
3232 .visible_flat_columns()
3233 .into_iter()
3234 .map(|c| c.id.clone())
3235 .collect::<Vec<_>>();
3236
3237 let header_groups = self.header_groups();
3238 let left_header_groups = self.left_header_groups();
3239 let center_header_groups = self.center_header_groups();
3240 let right_header_groups = self.right_header_groups();
3241
3242 let mut header_size: std::collections::BTreeMap<Arc<str>, f32> =
3243 std::collections::BTreeMap::new();
3244 let mut header_start: std::collections::BTreeMap<Arc<str>, f32> =
3245 std::collections::BTreeMap::new();
3246
3247 for groups in [
3248 &header_groups,
3249 &left_header_groups,
3250 ¢er_header_groups,
3251 &right_header_groups,
3252 ] {
3253 for g in groups {
3254 for h in &g.headers {
3255 let id = h.id.clone();
3256 if let Some(size) = self.header_size(id.as_ref()) {
3257 header_size.insert(id.clone(), size);
3258 }
3259 if let Some(start) = self.header_start(id.as_ref()) {
3260 header_start.insert(id.clone(), start);
3261 }
3262 }
3263 }
3264 }
3265
3266 let (left_total_size, center_total_size, right_total_size) = self.pinned_total_sizes();
3267
3268 let mut column_size: std::collections::BTreeMap<Arc<str>, f32> =
3269 std::collections::BTreeMap::new();
3270 let mut column_start_all: std::collections::BTreeMap<Arc<str>, f32> =
3271 std::collections::BTreeMap::new();
3272 let mut column_start_left: std::collections::BTreeMap<Arc<str>, Option<f32>> =
3273 std::collections::BTreeMap::new();
3274 let mut column_start_center: std::collections::BTreeMap<Arc<str>, Option<f32>> =
3275 std::collections::BTreeMap::new();
3276 let mut column_start_right: std::collections::BTreeMap<Arc<str>, Option<f32>> =
3277 std::collections::BTreeMap::new();
3278 let mut column_after_all: std::collections::BTreeMap<Arc<str>, f32> =
3279 std::collections::BTreeMap::new();
3280 let mut column_after_left: std::collections::BTreeMap<Arc<str>, Option<f32>> =
3281 std::collections::BTreeMap::new();
3282 let mut column_after_center: std::collections::BTreeMap<Arc<str>, Option<f32>> =
3283 std::collections::BTreeMap::new();
3284 let mut column_after_right: std::collections::BTreeMap<Arc<str>, Option<f32>> =
3285 std::collections::BTreeMap::new();
3286
3287 for col in self.ordered_columns() {
3288 let id = col.id.clone();
3289 column_size.insert(
3290 id.clone(),
3291 super::resolved_column_size(&self.state.column_sizing, col),
3292 );
3293 column_start_all.insert(
3294 id.clone(),
3295 self.column_start(id.as_ref(), super::ColumnSizingRegion::All)
3296 .unwrap_or(0.0),
3297 );
3298 column_start_left.insert(
3299 id.clone(),
3300 self.column_start(id.as_ref(), super::ColumnSizingRegion::Left),
3301 );
3302 column_start_center.insert(
3303 id.clone(),
3304 self.column_start(id.as_ref(), super::ColumnSizingRegion::Center),
3305 );
3306 column_start_right.insert(
3307 id.clone(),
3308 self.column_start(id.as_ref(), super::ColumnSizingRegion::Right),
3309 );
3310
3311 column_after_all.insert(
3312 id.clone(),
3313 self.column_after(id.as_ref(), super::ColumnSizingRegion::All)
3314 .unwrap_or(0.0),
3315 );
3316 column_after_left.insert(
3317 id.clone(),
3318 self.column_after(id.as_ref(), super::ColumnSizingRegion::Left),
3319 );
3320 column_after_center.insert(
3321 id.clone(),
3322 self.column_after(id.as_ref(), super::ColumnSizingRegion::Center),
3323 );
3324 column_after_right.insert(
3325 id.clone(),
3326 self.column_after(id.as_ref(), super::ColumnSizingRegion::Right),
3327 );
3328 }
3329
3330 let core = snapshot_row_model_ids(self.core_row_model());
3331 let row_model = snapshot_row_model_ids(self.row_model());
3332
3333 let mut cells: std::collections::BTreeMap<Arc<str>, super::RowCellsSnapshot> =
3334 std::collections::BTreeMap::new();
3335 for &row_i in self.row_model().root_rows() {
3336 let Some(row) = self.row_model().row(row_i) else {
3337 continue;
3338 };
3339 let row_id = row.id.0.clone();
3340 if let Some(snapshot) = self.row_cells(row.key) {
3341 cells.insert(row_id, snapshot);
3342 }
3343 }
3344
3345 super::CoreModelSnapshot {
3346 schema_version: 4,
3347 column_tree,
3348 column_capabilities,
3349 flat_columns: super::FlatColumnsSnapshot {
3350 all: all_flat,
3351 visible: visible_flat,
3352 },
3353 leaf_columns: super::LeafColumnsSnapshot {
3354 all: all_leaf,
3355 visible,
3356 left_visible,
3357 center_visible,
3358 right_visible,
3359 },
3360 header_groups,
3361 left_header_groups,
3362 center_header_groups,
3363 right_header_groups,
3364 header_sizing: super::HeaderSizingSnapshot {
3365 size: header_size,
3366 start: header_start,
3367 },
3368 leaf_column_sizing: super::LeafColumnSizingSnapshot {
3369 sizing: super::ColumnSizingSnapshot {
3370 total_size: self.total_size(),
3371 left_total_size,
3372 center_total_size,
3373 right_total_size,
3374 },
3375 size: column_size,
3376 start: super::ColumnStartSnapshot {
3377 all: column_start_all,
3378 left: column_start_left,
3379 center: column_start_center,
3380 right: column_start_right,
3381 },
3382 after: super::ColumnAfterSnapshot {
3383 all: column_after_all,
3384 left: column_after_left,
3385 center: column_after_center,
3386 right: column_after_right,
3387 },
3388 },
3389 rows: super::CoreRowsSnapshot { core, row_model },
3390 cells,
3391 }
3392 }
3393
3394 pub fn pinned_visible_columns(
3395 &self,
3396 ) -> (
3397 Vec<&super::ColumnDef<TData>>,
3398 Vec<&super::ColumnDef<TData>>,
3399 Vec<&super::ColumnDef<TData>>,
3400 ) {
3401 let visible = self.visible_columns();
3402 super::split_pinned_columns(visible.as_slice(), &self.state.column_pinning)
3403 }
3404
3405 pub fn pinned_leaf_columns(
3410 &self,
3411 ) -> (
3412 Vec<&super::ColumnDef<TData>>,
3413 Vec<&super::ColumnDef<TData>>,
3414 Vec<&super::ColumnDef<TData>>,
3415 ) {
3416 let leaf = self.ordered_columns();
3417 super::split_pinned_columns(leaf.as_slice(), &self.state.column_pinning)
3418 }
3419
3420 pub fn left_leaf_columns(&self) -> Vec<&super::ColumnDef<TData>> {
3421 let (left, _, _) = self.pinned_leaf_columns();
3422 left
3423 }
3424
3425 pub fn center_leaf_columns(&self) -> Vec<&super::ColumnDef<TData>> {
3426 let (_, center, _) = self.pinned_leaf_columns();
3427 center
3428 }
3429
3430 pub fn right_leaf_columns(&self) -> Vec<&super::ColumnDef<TData>> {
3431 let (_, _, right) = self.pinned_leaf_columns();
3432 right
3433 }
3434
3435 pub fn column_size(&self, id: &str) -> Option<f32> {
3436 let col = self.column(id)?;
3437 Some(super::resolved_column_size(&self.state.column_sizing, col))
3438 }
3439
3440 pub fn column_sizing(&self) -> &super::ColumnSizingState {
3441 &self.state.column_sizing
3442 }
3443
3444 pub fn column_sizing_info(&self) -> &super::ColumnSizingInfoState {
3445 &self.state.column_sizing_info
3446 }
3447
3448 pub fn column_can_resize(&self, id: &str) -> Option<bool> {
3449 let col = self.column(id)?;
3450 Some(super::column_can_resize(self.options, col))
3451 }
3452
3453 pub fn is_column_resizing(&self, id: &str) -> Option<bool> {
3454 let col = self.column(id)?;
3455 Some(
3456 self.state
3457 .column_sizing_info
3458 .is_resizing_column
3459 .as_ref()
3460 .is_some_and(|active| active.as_ref() == col.id.as_ref()),
3461 )
3462 }
3463
3464 pub fn reset_column_size(&self, id: &str) -> Option<super::ColumnSizingState> {
3466 let col = self.column(id)?;
3467 let mut next = self.state.column_sizing.clone();
3468 next.remove(&col.id);
3469 Some(next)
3470 }
3471
3472 pub fn reset_column_sizing(&self, default_state: bool) -> super::ColumnSizingState {
3474 if default_state {
3475 super::ColumnSizingState::default()
3476 } else {
3477 self.initial_state.column_sizing.clone()
3478 }
3479 }
3480
3481 pub fn reset_header_size_info(&self, default_state: bool) -> super::ColumnSizingInfoState {
3483 if default_state {
3484 super::ColumnSizingInfoState::default()
3485 } else {
3486 self.initial_state.column_sizing_info.clone()
3487 }
3488 }
3489
3490 pub fn started_column_resize(
3491 &self,
3492 id: &str,
3493 pointer_x: f32,
3494 ) -> Option<super::ColumnSizingInfoState> {
3495 let col = self.column(id)?;
3496 if !super::column_can_resize(self.options, col) {
3497 return Some(self.state.column_sizing_info.clone());
3498 }
3499
3500 let start = super::resolved_column_size(&self.state.column_sizing, col);
3501 let mut next = self.state.column_sizing_info.clone();
3502 super::begin_column_resize(
3503 &mut next,
3504 col.id.clone(),
3505 pointer_x,
3506 start,
3507 vec![(col.id.clone(), start)],
3508 );
3509 Some(next)
3510 }
3511
3512 pub fn dragged_column_resize(
3513 &self,
3514 pointer_x: f32,
3515 ) -> (super::ColumnSizingState, super::ColumnSizingInfoState) {
3516 let mut sizing = self.state.column_sizing.clone();
3517 let mut info = self.state.column_sizing_info.clone();
3518 super::drag_column_resize(
3519 self.options.column_resize_mode,
3520 self.options.column_resize_direction,
3521 &mut sizing,
3522 &mut info,
3523 pointer_x,
3524 );
3525 (sizing, info)
3526 }
3527
3528 pub fn ended_column_resize(
3529 &self,
3530 pointer_x: Option<f32>,
3531 ) -> (super::ColumnSizingState, super::ColumnSizingInfoState) {
3532 let mut sizing = self.state.column_sizing.clone();
3533 let mut info = self.state.column_sizing_info.clone();
3534 super::end_column_resize(
3535 self.options.column_resize_mode,
3536 self.options.column_resize_direction,
3537 &mut sizing,
3538 &mut info,
3539 pointer_x,
3540 );
3541 (sizing, info)
3542 }
3543
3544 pub fn total_size(&self) -> f32 {
3545 self.visible_columns()
3546 .into_iter()
3547 .map(|c| super::resolved_column_size(&self.state.column_sizing, c))
3548 .sum()
3549 }
3550
3551 pub fn pinned_total_sizes(&self) -> (f32, f32, f32) {
3552 let (left, center, right) = self.pinned_visible_columns();
3553 let sizing = &self.state.column_sizing;
3554
3555 let left = left
3556 .into_iter()
3557 .map(|c| super::resolved_column_size(sizing, c))
3558 .sum();
3559 let center = center
3560 .into_iter()
3561 .map(|c| super::resolved_column_size(sizing, c))
3562 .sum();
3563 let right = right
3564 .into_iter()
3565 .map(|c| super::resolved_column_size(sizing, c))
3566 .sum();
3567
3568 (left, center, right)
3569 }
3570
3571 pub fn left_total_size(&self) -> f32 {
3572 self.pinned_total_sizes().0
3573 }
3574
3575 pub fn center_total_size(&self) -> f32 {
3576 self.pinned_total_sizes().1
3577 }
3578
3579 pub fn right_total_size(&self) -> f32 {
3580 self.pinned_total_sizes().2
3581 }
3582
3583 pub fn column_start(&self, column_id: &str, region: super::ColumnSizingRegion) -> Option<f32> {
3595 let col = self.column(column_id)?;
3596 let sizing = &self.state.column_sizing;
3597
3598 let pin_pos = self.column_pin_position(column_id);
3599 let (left, center, right) = self.pinned_visible_columns();
3600
3601 fn tanstack_start_for<'a, TData: 'a>(
3602 cols: impl IntoIterator<Item = &'a super::ColumnDef<TData>>,
3603 target: &super::ColumnDef<TData>,
3604 sizing: &super::ColumnSizingState,
3605 ) -> f32 {
3606 let cols: Vec<&super::ColumnDef<TData>> = cols.into_iter().collect();
3607 let idx = cols
3608 .iter()
3609 .position(|c| c.id.as_ref() == target.id.as_ref())
3610 .map(|i| i as isize)
3611 .unwrap_or(-1);
3612
3613 let end = if idx == -1 {
3614 cols.len().saturating_sub(1)
3615 } else {
3616 idx as usize
3617 };
3618
3619 let mut sum = 0.0;
3620 for c in cols.into_iter().take(end) {
3621 sum += super::resolved_column_size(sizing, c);
3622 }
3623 sum
3624 }
3625
3626 match region {
3627 super::ColumnSizingRegion::All => {
3628 let visible = self.visible_columns();
3629 Some(tanstack_start_for(visible, col, sizing))
3630 }
3631 super::ColumnSizingRegion::Left => {
3632 if pin_pos != Some(super::ColumnPinPosition::Left) {
3633 return None;
3634 }
3635 Some(tanstack_start_for(left, col, sizing))
3636 }
3637 super::ColumnSizingRegion::Center => {
3638 if pin_pos.is_some() {
3639 return None;
3640 }
3641 Some(tanstack_start_for(center, col, sizing))
3642 }
3643 super::ColumnSizingRegion::Right => {
3644 if pin_pos != Some(super::ColumnPinPosition::Right) {
3645 return None;
3646 }
3647 Some(tanstack_start_for(right, col, sizing))
3648 }
3649 }
3650 }
3651
3652 pub fn column_after(&self, column_id: &str, region: super::ColumnSizingRegion) -> Option<f32> {
3654 let col = self.column(column_id)?;
3655 let sizing = &self.state.column_sizing;
3656
3657 let pin_pos = self.column_pin_position(column_id);
3658 let (left, center, right) = self.pinned_visible_columns();
3659
3660 fn tanstack_after_for<'a, TData: 'a>(
3661 cols: impl IntoIterator<Item = &'a super::ColumnDef<TData>>,
3662 target: &super::ColumnDef<TData>,
3663 sizing: &super::ColumnSizingState,
3664 ) -> f32 {
3665 let cols: Vec<&super::ColumnDef<TData>> = cols.into_iter().collect();
3666 let idx = cols
3667 .iter()
3668 .position(|c| c.id.as_ref() == target.id.as_ref())
3669 .map(|i| i as isize)
3670 .unwrap_or(-1);
3671
3672 let start = (idx + 1).max(0) as usize;
3673 let mut sum = 0.0;
3674 for c in cols.into_iter().skip(start) {
3675 sum += super::resolved_column_size(sizing, c);
3676 }
3677 sum
3678 }
3679
3680 match region {
3681 super::ColumnSizingRegion::All => {
3682 let visible = self.visible_columns();
3683 Some(tanstack_after_for(visible, col, sizing))
3684 }
3685 super::ColumnSizingRegion::Left => {
3686 if pin_pos != Some(super::ColumnPinPosition::Left) {
3687 return None;
3688 }
3689 Some(tanstack_after_for(left, col, sizing))
3690 }
3691 super::ColumnSizingRegion::Center => {
3692 if pin_pos.is_some() {
3693 return None;
3694 }
3695 Some(tanstack_after_for(center, col, sizing))
3696 }
3697 super::ColumnSizingRegion::Right => {
3698 if pin_pos != Some(super::ColumnPinPosition::Right) {
3699 return None;
3700 }
3701 Some(tanstack_after_for(right, col, sizing))
3702 }
3703 }
3704 }
3705
3706 fn header_groups_for_sizing(&self, header_id: &str) -> Vec<super::HeaderGroupSnapshot> {
3707 if header_id.starts_with("left_") {
3708 return self.left_header_groups();
3709 }
3710 if header_id.starts_with("center_") {
3711 return self.center_header_groups();
3712 }
3713 if header_id.starts_with("right_") {
3714 return self.right_header_groups();
3715 }
3716 if self.column(header_id).is_some() {
3720 return match self.column_pin_position(header_id) {
3721 Some(super::ColumnPinPosition::Left) => self.left_header_groups(),
3722 Some(super::ColumnPinPosition::Right) => self.right_header_groups(),
3723 None => self.center_header_groups(),
3724 };
3725 }
3726 self.header_groups()
3727 }
3728
3729 pub fn header_size(&self, header_id: &str) -> Option<f32> {
3731 let groups = self.header_groups_for_sizing(header_id);
3732 let mut by_id: HashMap<Arc<str>, super::HeaderSnapshot> = HashMap::new();
3733 for g in &groups {
3734 for h in &g.headers {
3735 by_id.insert(h.id.clone(), h.clone());
3736 }
3737 }
3738
3739 fn size_for<'a, TData>(
3740 table: &Table<'a, TData>,
3741 by_id: &HashMap<Arc<str>, super::HeaderSnapshot>,
3742 cache: &mut HashMap<Arc<str>, f32>,
3743 id: &Arc<str>,
3744 ) -> f32 {
3745 if let Some(v) = cache.get(id) {
3746 return *v;
3747 }
3748
3749 let Some(h) = by_id.get(id) else {
3750 cache.insert(id.clone(), 0.0);
3751 return 0.0;
3752 };
3753
3754 let size = if h.sub_header_ids.is_empty() {
3755 table
3756 .column(h.column_id.as_ref())
3757 .map(|c| super::resolved_column_size(&table.state.column_sizing, c))
3758 .unwrap_or(0.0)
3759 } else {
3760 let mut sum = 0.0;
3761 for child in &h.sub_header_ids {
3762 sum += size_for(table, by_id, cache, child);
3763 }
3764 sum
3765 };
3766
3767 cache.insert(id.clone(), size);
3768 size
3769 }
3770
3771 let id = Arc::<str>::from(header_id);
3772 if !by_id.contains_key(&id) {
3773 return None;
3774 }
3775 let mut cache: HashMap<Arc<str>, f32> = HashMap::new();
3776 Some(size_for(self, &by_id, &mut cache, &id))
3777 }
3778
3779 pub fn header_start(&self, header_id: &str) -> Option<f32> {
3781 let groups = self.header_groups_for_sizing(header_id);
3782 if groups.is_empty() {
3783 return None;
3784 }
3785
3786 let mut by_id: HashMap<Arc<str>, super::HeaderSnapshot> = HashMap::new();
3787 for g in &groups {
3788 for h in &g.headers {
3789 by_id.insert(h.id.clone(), h.clone());
3790 }
3791 }
3792
3793 fn size_for<'a, TData>(
3794 table: &Table<'a, TData>,
3795 by_id: &HashMap<Arc<str>, super::HeaderSnapshot>,
3796 cache: &mut HashMap<Arc<str>, f32>,
3797 id: &Arc<str>,
3798 ) -> f32 {
3799 if let Some(v) = cache.get(id) {
3800 return *v;
3801 }
3802
3803 let Some(h) = by_id.get(id) else {
3804 cache.insert(id.clone(), 0.0);
3805 return 0.0;
3806 };
3807
3808 let size = if h.sub_header_ids.is_empty() {
3809 table
3810 .column(h.column_id.as_ref())
3811 .map(|c| super::resolved_column_size(&table.state.column_sizing, c))
3812 .unwrap_or(0.0)
3813 } else {
3814 let mut sum = 0.0;
3815 for child in &h.sub_header_ids {
3816 sum += size_for(table, by_id, cache, child);
3817 }
3818 sum
3819 };
3820
3821 cache.insert(id.clone(), size);
3822 size
3823 }
3824
3825 let mut cache: HashMap<Arc<str>, f32> = HashMap::new();
3826
3827 for g in &groups {
3828 let mut index: Option<usize> = None;
3829 for (i, h) in g.headers.iter().enumerate() {
3830 if h.id.as_ref() == header_id {
3831 index = Some(i);
3832 break;
3833 }
3834 }
3835
3836 let Some(index) = index else {
3837 continue;
3838 };
3839
3840 let mut start = 0.0;
3841 for h in g.headers.iter().take(index) {
3842 start += size_for(self, &by_id, &mut cache, &h.id);
3843 }
3844 return Some(start);
3845 }
3846
3847 None
3848 }
3849
3850 pub fn core_row_model(&self) -> &RowModel<'a, TData> {
3851 self.core_row_model.get_or_init(|| {
3852 build_core_row_model(
3853 self.data,
3854 &*self.get_row_key,
3855 self.get_row_id.as_deref(),
3856 self.get_sub_rows.as_deref(),
3857 )
3858 })
3859 }
3860
3861 pub fn pre_filtered_row_model(&self) -> &RowModel<'a, TData> {
3862 self.core_row_model()
3863 }
3864
3865 pub fn filtered_row_model(&self) -> &RowModel<'a, TData> {
3866 if self.options.manual_filtering || self.filtered_row_model_override_pre_filtered {
3867 return self.pre_filtered_row_model();
3868 }
3869 self.filtered_row_model.get_or_init(|| {
3870 super::filter_row_model(
3871 self.pre_filtered_row_model(),
3872 &self.columns,
3873 &self.state.column_filters,
3874 self.state.global_filter.clone(),
3875 self.options,
3876 &self.filter_fns,
3877 &self.global_filter_fn,
3878 self.get_column_can_global_filter.as_deref(),
3879 )
3880 })
3881 }
3882
3883 pub fn row_filter_state_snapshot(&self) -> super::RowFilterStateSnapshot {
3884 if self.options.manual_filtering || self.filtered_row_model_override_pre_filtered {
3885 return super::RowFilterStateSnapshot::default();
3886 }
3887 super::evaluate_row_filter_state(
3888 self.pre_filtered_row_model(),
3889 &self.columns,
3890 &self.state.column_filters,
3891 self.state.global_filter.clone(),
3892 self.options,
3893 &self.filter_fns,
3894 &self.global_filter_fn,
3895 self.get_column_can_global_filter.as_deref(),
3896 )
3897 }
3898
3899 pub fn pre_sorted_row_model(&self) -> &RowModel<'a, TData> {
3900 if !self.options.manual_grouping && !self.state.grouping.is_empty() {
3901 return self.grouped_pre_sorted_row_model();
3902 }
3903 self.filtered_row_model()
3904 }
3905
3906 pub fn sorted_row_model(&self) -> &RowModel<'a, TData> {
3907 if self.options.manual_sorting || self.sorted_row_model_override_pre_sorted {
3908 return self.pre_sorted_row_model();
3909 }
3910 if !self.options.manual_grouping && !self.state.grouping.is_empty() {
3911 return self.grouped_sorted_row_model();
3912 }
3913 self.sorted_row_model.get_or_init(|| {
3914 super::sort_row_model(
3915 self.pre_sorted_row_model(),
3916 &self.columns,
3917 &self.state.sorting,
3918 &self.sorting_fns,
3919 )
3920 })
3921 }
3922
3923 pub fn pre_pagination_row_model(&self) -> &RowModel<'a, TData> {
3924 if self.options.paginate_expanded_rows {
3925 self.expanded_row_model()
3926 } else {
3927 self.sorted_row_model()
3928 }
3929 }
3930
3931 pub fn pre_expanded_row_model(&self) -> &RowModel<'a, TData> {
3932 self.sorted_row_model()
3933 }
3934
3935 pub fn expanded_row_model(&self) -> &RowModel<'a, TData> {
3936 if !self.options.paginate_expanded_rows {
3937 return self.pre_expanded_row_model();
3938 }
3939 if !self.options.manual_grouping && !self.state.grouping.is_empty() {
3940 return self.pre_expanded_row_model();
3941 }
3942 if self.options.manual_expanding {
3943 return self.pre_expanded_row_model();
3944 }
3945 if self.expanded_row_model_override_pre_expanded {
3946 return self.pre_expanded_row_model();
3947 }
3948 if !super::is_some_rows_expanded(&self.state.expanding) {
3949 return self.pre_expanded_row_model();
3950 }
3951 self.expanded_row_model.get_or_init(|| {
3952 super::expand_row_model(
3953 self.pre_expanded_row_model(),
3954 &self.state.expanding,
3955 |row_key, original| self.row_is_expanded_for_key_and_original(row_key, original),
3956 )
3957 })
3958 }
3959
3960 pub fn row_model(&self) -> &RowModel<'a, TData> {
3961 if self.options.manual_pagination {
3962 return self.pre_pagination_row_model();
3963 }
3964 if self.pagination_row_model_override_pre_pagination {
3965 return self.pre_pagination_row_model();
3966 }
3967 if self.options.paginate_expanded_rows {
3968 return self.paginated_row_model.get_or_init(|| {
3969 super::paginate_row_model(self.pre_pagination_row_model(), self.state.pagination)
3970 });
3971 }
3972
3973 let paginated = self.paginated_row_model.get_or_init(|| {
3974 super::paginate_row_model(self.pre_pagination_row_model(), self.state.pagination)
3975 });
3976 self.expanded_paginated_row_model.get_or_init(|| {
3977 let mut out =
3978 super::expand_row_model(paginated, &self.state.expanding, |row_key, original| {
3979 self.row_is_expanded_for_key_and_original(row_key, original)
3980 });
3981 rebuild_flat_rows_from_roots_including_duplicates(&mut out);
3982 out
3983 })
3984 }
3985
3986 pub fn pre_selected_row_model(&self) -> &RowModel<'a, TData> {
3987 self.core_row_model()
3988 }
3989
3990 pub fn selected_row_model(&self) -> &RowModel<'a, TData> {
3991 self.selected_row_model.get_or_init(|| {
3992 super::select_rows_fn(self.pre_selected_row_model(), &self.state.row_selection)
3993 })
3994 }
3995
3996 pub fn filtered_selected_row_model(&self) -> &RowModel<'a, TData> {
3997 self.filtered_selected_row_model.get_or_init(|| {
3998 if self.state.row_selection.is_empty() {
3999 return RowModel {
4000 root_rows: Vec::new(),
4001 flat_rows: Vec::new(),
4002 rows_by_key: HashMap::new(),
4003 rows_by_id: HashMap::new(),
4004 arena: Vec::new(),
4005 };
4006 }
4007 super::select_rows_fn(self.filtered_row_model(), &self.state.row_selection)
4008 })
4009 }
4010
4011 pub fn grouped_selected_row_model(&self) -> &RowModel<'a, TData> {
4012 self.grouped_selected_row_model.get_or_init(|| {
4013 if self.state.row_selection.is_empty() {
4014 return RowModel {
4015 root_rows: Vec::new(),
4016 flat_rows: Vec::new(),
4017 rows_by_key: HashMap::new(),
4018 rows_by_id: HashMap::new(),
4019 arena: Vec::new(),
4020 };
4021 }
4022 super::select_rows_fn(self.sorted_row_model(), &self.state.row_selection)
4023 })
4024 }
4025
4026 pub fn page_selected_row_model(&self) -> &RowModel<'a, TData> {
4027 self.page_selected_row_model.get_or_init(|| {
4028 if self.state.row_selection.is_empty() {
4029 return RowModel {
4030 root_rows: Vec::new(),
4031 flat_rows: Vec::new(),
4032 rows_by_key: HashMap::new(),
4033 rows_by_id: HashMap::new(),
4034 arena: Vec::new(),
4035 };
4036 }
4037 super::select_rows_fn(self.row_model(), &self.state.row_selection)
4038 })
4039 }
4040
4041 pub fn row_is_selected(&self, row_key: RowKey) -> bool {
4042 super::is_row_selected(row_key, &self.state.row_selection)
4043 }
4044
4045 fn row_can_select_for_row(&self, row_key: RowKey, row: &Row<'a, TData>) -> bool {
4046 if let Some(enable_row_selection) = self.enable_row_selection.as_ref() {
4047 return enable_row_selection(row_key, row.original);
4048 }
4049 self.options.enable_row_selection
4050 }
4051
4052 fn row_can_multi_select_for_row(&self, row_key: RowKey, row: &Row<'a, TData>) -> bool {
4053 if let Some(enable_multi_row_selection) = self.enable_multi_row_selection.as_ref() {
4054 return enable_multi_row_selection(row_key, row.original);
4055 }
4056 self.options.enable_multi_row_selection
4057 }
4058
4059 fn row_can_select_sub_rows_for_row(&self, row_key: RowKey, row: &Row<'a, TData>) -> bool {
4060 if let Some(enable_sub_row_selection) = self.enable_sub_row_selection.as_ref() {
4061 return enable_sub_row_selection(row_key, row.original);
4062 }
4063 self.options.enable_sub_row_selection
4064 }
4065
4066 pub fn row_is_some_selected(&self, row_key: RowKey) -> bool {
4067 let can_select =
4068 |row_key: RowKey, row: &Row<'a, TData>| self.row_can_select_for_row(row_key, row);
4069 self.core_row_model().row_by_key(row_key).is_some_and(|i| {
4070 super::row_is_some_selected(
4071 self.core_row_model(),
4072 &self.state.row_selection,
4073 i,
4074 &can_select,
4075 )
4076 })
4077 }
4078
4079 pub fn row_is_all_sub_rows_selected(&self, row_key: RowKey) -> bool {
4080 let can_select =
4081 |row_key: RowKey, row: &Row<'a, TData>| self.row_can_select_for_row(row_key, row);
4082 self.core_row_model().row_by_key(row_key).is_some_and(|i| {
4083 super::row_is_all_sub_rows_selected(
4084 self.core_row_model(),
4085 &self.state.row_selection,
4086 i,
4087 &can_select,
4088 )
4089 })
4090 }
4091
4092 pub fn row_selection_updater(
4093 &self,
4094 row_key: RowKey,
4095 value: Option<bool>,
4096 select_children: bool,
4097 ) -> super::Updater<super::RowSelectionState> {
4098 #[derive(Clone)]
4099 struct SelectionRowMeta {
4100 sub_rows: Vec<RowKey>,
4101 can_select: bool,
4102 can_multi_select: bool,
4103 can_select_sub_rows: bool,
4104 }
4105
4106 fn mutate_row_selection(
4107 row_meta_by_key: &HashMap<RowKey, SelectionRowMeta>,
4108 selection: &mut super::RowSelectionState,
4109 row_key: RowKey,
4110 value: bool,
4111 include_children: bool,
4112 ) {
4113 let Some(row_meta) = row_meta_by_key.get(&row_key) else {
4114 return;
4115 };
4116
4117 if value {
4118 if !row_meta.can_multi_select {
4119 selection.clear();
4120 }
4121 if row_meta.can_select {
4122 selection.insert(row_key);
4123 }
4124 } else {
4125 selection.remove(&row_key);
4126 }
4127
4128 if include_children && row_meta.can_select_sub_rows {
4129 for child_key in &row_meta.sub_rows {
4130 mutate_row_selection(
4131 row_meta_by_key,
4132 selection,
4133 *child_key,
4134 value,
4135 include_children,
4136 );
4137 }
4138 }
4139 }
4140
4141 let mut row_meta_by_key: HashMap<RowKey, SelectionRowMeta> = HashMap::new();
4142 let core = self.core_row_model();
4143 for row in core.arena() {
4144 let sub_rows = row
4145 .sub_rows
4146 .iter()
4147 .filter_map(|&index| core.row(index).map(|child| child.key))
4148 .collect::<Vec<_>>();
4149 row_meta_by_key.insert(
4150 row.key,
4151 SelectionRowMeta {
4152 sub_rows,
4153 can_select: self.row_can_select_for_row(row.key, row),
4154 can_multi_select: self.row_can_multi_select_for_row(row.key, row),
4155 can_select_sub_rows: self.row_can_select_sub_rows_for_row(row.key, row),
4156 },
4157 );
4158 }
4159
4160 if !self.state.grouping.is_empty() {
4161 let grouped = self.grouped_row_model();
4162 for &row_index in grouped.flat_rows() {
4163 let Some(row) = grouped.row(row_index) else {
4164 continue;
4165 };
4166 let sub_rows = row
4167 .sub_rows
4168 .iter()
4169 .filter_map(|&index| grouped.row(index).map(|child| child.key))
4170 .collect::<Vec<_>>();
4171
4172 let leaf_original = match &row.kind {
4173 super::GroupedRowKind::Leaf { row_key } => core
4174 .row_by_key(*row_key)
4175 .and_then(|index| core.row(index).map(|row| row.original)),
4176 super::GroupedRowKind::Group {
4177 first_leaf_row_key, ..
4178 } => core
4179 .row_by_key(*first_leaf_row_key)
4180 .and_then(|index| core.row(index).map(|row| row.original)),
4181 };
4182
4183 let can_select = match leaf_original {
4184 Some(original) => {
4185 if let Some(enable_row_selection) = self.enable_row_selection.as_ref() {
4186 enable_row_selection(row.key, original)
4187 } else {
4188 self.options.enable_row_selection
4189 }
4190 }
4191 None => self.options.enable_row_selection,
4192 };
4193 let can_multi_select = match leaf_original {
4194 Some(original) => {
4195 if let Some(enable_multi_row_selection) =
4196 self.enable_multi_row_selection.as_ref()
4197 {
4198 enable_multi_row_selection(row.key, original)
4199 } else {
4200 self.options.enable_multi_row_selection
4201 }
4202 }
4203 None => self.options.enable_multi_row_selection,
4204 };
4205 let can_select_sub_rows = match leaf_original {
4206 Some(original) => {
4207 if let Some(enable_sub_row_selection) =
4208 self.enable_sub_row_selection.as_ref()
4209 {
4210 enable_sub_row_selection(row.key, original)
4211 } else {
4212 self.options.enable_sub_row_selection
4213 }
4214 }
4215 None => self.options.enable_sub_row_selection,
4216 };
4217
4218 row_meta_by_key.insert(
4219 row.key,
4220 SelectionRowMeta {
4221 sub_rows,
4222 can_select,
4223 can_multi_select,
4224 can_select_sub_rows,
4225 },
4226 );
4227 }
4228 }
4229
4230 super::Updater::Func(Arc::new(move |old| {
4231 let current = old.contains(&row_key);
4232 let value = value.unwrap_or(!current);
4233
4234 let mut next = old.clone();
4235
4236 if let Some(row_meta) = row_meta_by_key.get(&row_key)
4237 && row_meta.can_select
4238 && current == value
4239 {
4240 return next;
4241 }
4242
4243 mutate_row_selection(&row_meta_by_key, &mut next, row_key, value, select_children);
4244 next
4245 }))
4246 }
4247
4248 pub fn row_selection_updater_by_id(
4249 &self,
4250 row_id: &str,
4251 search_all: bool,
4252 value: Option<bool>,
4253 select_children: bool,
4254 ) -> Option<super::Updater<super::RowSelectionState>> {
4255 let row_key = self.row_key_for_id(row_id, search_all)?;
4256 Some(self.row_selection_updater(row_key, value, select_children))
4257 }
4258
4259 pub fn toggled_row_selected_by_id(
4260 &self,
4261 row_id: &str,
4262 search_all: bool,
4263 value: Option<bool>,
4264 select_children: bool,
4265 ) -> Option<super::RowSelectionState> {
4266 let updater =
4267 self.row_selection_updater_by_id(row_id, search_all, value, select_children)?;
4268 Some(updater.apply(&self.state.row_selection))
4269 }
4270
4271 pub fn toggled_row_selected(
4272 &self,
4273 row_key: RowKey,
4274 value: Option<bool>,
4275 select_children: bool,
4276 ) -> super::RowSelectionState {
4277 self.row_selection_updater(row_key, value, select_children)
4278 .apply(&self.state.row_selection)
4279 }
4280
4281 pub fn is_all_rows_selected(&self) -> bool {
4282 let can_select =
4283 |row_key: RowKey, row: &Row<'a, TData>| self.row_can_select_for_row(row_key, row);
4284 super::is_all_rows_selected(
4285 self.filtered_row_model(),
4286 &self.state.row_selection,
4287 &can_select,
4288 )
4289 }
4290
4291 pub fn is_some_rows_selected(&self) -> bool {
4292 super::is_some_rows_selected(self.filtered_row_model(), &self.state.row_selection)
4293 }
4294
4295 pub fn is_all_page_rows_selected(&self) -> bool {
4296 let can_select =
4297 |row_key: RowKey, row: &Row<'a, TData>| self.row_can_select_for_row(row_key, row);
4298 super::is_all_page_rows_selected(self.row_model(), &self.state.row_selection, &can_select)
4299 }
4300
4301 pub fn is_some_page_rows_selected(&self) -> bool {
4302 let can_select =
4303 |row_key: RowKey, row: &Row<'a, TData>| self.row_can_select_for_row(row_key, row);
4304 super::is_some_page_rows_selected(
4305 self.row_model(),
4306 self.core_row_model(),
4307 &self.state.row_selection,
4308 &can_select,
4309 )
4310 }
4311
4312 pub fn filtered_row_count(&self) -> usize {
4313 self.filtered_row_model().root_rows().len()
4314 }
4315
4316 pub fn filtered_flat_row_count(&self) -> usize {
4317 self.filtered_row_model().flat_rows().len()
4318 }
4319
4320 pub fn filtered_selected_row_count(&self) -> usize {
4321 super::selected_root_row_count(self.filtered_row_model(), &self.state.row_selection)
4322 }
4323
4324 pub fn filtered_selected_flat_row_count(&self) -> usize {
4325 super::selected_flat_row_count(self.filtered_row_model(), &self.state.row_selection)
4326 }
4327
4328 pub fn row_can_select(&self, row_key: RowKey) -> bool {
4330 let model = self.core_row_model();
4331 model
4332 .row_by_key(row_key)
4333 .and_then(|i| model.row(i))
4334 .is_some_and(|r| self.row_can_select_for_row(row_key, r))
4335 }
4336
4337 pub fn row_can_multi_select(&self, row_key: RowKey) -> bool {
4339 let model = self.core_row_model();
4340 model
4341 .row_by_key(row_key)
4342 .and_then(|i| model.row(i))
4343 .is_some_and(|r| self.row_can_multi_select_for_row(row_key, r))
4344 }
4345
4346 pub fn row_can_select_sub_rows(&self, row_key: RowKey) -> bool {
4348 let model = self.core_row_model();
4349 model
4350 .row_by_key(row_key)
4351 .and_then(|i| model.row(i))
4352 .is_some_and(|r| self.row_can_select_sub_rows_for_row(row_key, r))
4353 }
4354
4355 pub fn row_can_select_by_id(&self, row_id: &str, search_all: bool) -> Option<bool> {
4356 let row = self.row_by_id(row_id, search_all)?;
4357 Some(self.row_can_select_for_row(row.key, row))
4358 }
4359
4360 pub fn row_can_multi_select_by_id(&self, row_id: &str, search_all: bool) -> Option<bool> {
4361 let row = self.row_by_id(row_id, search_all)?;
4362 Some(self.row_can_multi_select_for_row(row.key, row))
4363 }
4364
4365 pub fn row_can_select_sub_rows_by_id(&self, row_id: &str, search_all: bool) -> Option<bool> {
4366 let row = self.row_by_id(row_id, search_all)?;
4367 Some(self.row_can_select_sub_rows_for_row(row.key, row))
4368 }
4369
4370 pub fn toggled_all_rows_selected(&self, value: Option<bool>) -> super::RowSelectionState {
4371 let can_select =
4372 |row_key: RowKey, row: &Row<'a, TData>| self.row_can_select_for_row(row_key, row);
4373 super::toggle_all_rows_selected(
4374 self.filtered_row_model(),
4375 &self.state.row_selection,
4376 value,
4377 &can_select,
4378 )
4379 }
4380
4381 pub fn toggled_all_page_rows_selected(&self, value: Option<bool>) -> super::RowSelectionState {
4382 let can_select =
4383 |row_key: RowKey, row: &Row<'a, TData>| self.row_can_select_for_row(row_key, row);
4384 let can_multi =
4385 |row_key: RowKey, row: &Row<'a, TData>| self.row_can_multi_select_for_row(row_key, row);
4386 let can_sub = |row_key: RowKey, row: &Row<'a, TData>| {
4387 self.row_can_select_sub_rows_for_row(row_key, row)
4388 };
4389 super::toggle_all_page_rows_selected(
4390 self.row_model(),
4391 self.core_row_model(),
4392 &self.state.row_selection,
4393 value,
4394 &can_select,
4395 &can_multi,
4396 &can_sub,
4397 )
4398 }
4399
4400 pub fn faceted_row_model(&self, column_id: &str) -> Option<&RowModel<'a, TData>> {
4401 let column_index = self.column_index(column_id)?;
4402
4403 if self.options.manual_filtering || self.filtered_row_model_override_pre_filtered {
4404 return Some(self.pre_filtered_row_model());
4405 }
4406
4407 let caches = self.faceted_row_model_by_column.get_or_init(|| {
4408 let mut v = Vec::with_capacity(self.columns.len());
4409 for _ in 0..self.columns.len() {
4410 v.push(OnceCell::new());
4411 }
4412 v
4413 });
4414
4415 Some(caches[column_index].get_or_init(|| {
4416 super::faceted_row_model_excluding(
4417 self.pre_filtered_row_model(),
4418 &self.columns,
4419 &self.state.column_filters,
4420 self.state.global_filter.clone(),
4421 self.options,
4422 &self.filter_fns,
4423 &self.global_filter_fn,
4424 self.get_column_can_global_filter.as_deref(),
4425 Some(column_id),
4426 )
4427 }))
4428 }
4429
4430 pub fn faceted_unique_values(&self, column_id: &str) -> Option<&super::FacetCounts> {
4431 let column_index = self.column_index(column_id)?;
4432 let column = self.column(column_id)?;
4433
4434 let caches = self.faceted_unique_values_by_column.get_or_init(|| {
4435 let mut v = Vec::with_capacity(self.columns.len());
4436 for _ in 0..self.columns.len() {
4437 v.push(OnceCell::new());
4438 }
4439 v
4440 });
4441
4442 Some(caches[column_index].get_or_init(|| {
4443 let model = self
4444 .faceted_row_model(column_id)
4445 .unwrap_or_else(|| self.row_model());
4446 super::faceted_unique_values(model, column)
4447 }))
4448 }
4449
4450 pub fn faceted_unique_value_labels(&self, column_id: &str) -> Option<&super::FacetLabels<'a>> {
4451 let column_index = self.column_index(column_id)?;
4452 let column = self.column(column_id)?;
4453
4454 let caches = self.faceted_unique_labels_by_column.get_or_init(|| {
4455 let mut v = Vec::with_capacity(self.columns.len());
4456 for _ in 0..self.columns.len() {
4457 v.push(OnceCell::new());
4458 }
4459 v
4460 });
4461
4462 Some(caches[column_index].get_or_init(|| {
4463 let model = self
4464 .faceted_row_model(column_id)
4465 .unwrap_or_else(|| self.row_model());
4466 super::faceted_unique_value_labels(model, column)
4467 }))
4468 }
4469
4470 pub fn faceted_min_max_u64(&self, column_id: &str) -> Option<(u64, u64)> {
4471 let column_index = self.column_index(column_id)?;
4472 let column = self.column(column_id)?;
4473
4474 let caches = self.faceted_min_max_u64_by_column.get_or_init(|| {
4475 let mut v = Vec::with_capacity(self.columns.len());
4476 for _ in 0..self.columns.len() {
4477 v.push(OnceCell::new());
4478 }
4479 v
4480 });
4481
4482 *caches[column_index].get_or_init(|| {
4483 let model = self
4484 .faceted_row_model(column_id)
4485 .unwrap_or_else(|| self.row_model());
4486 super::faceted_min_max_u64(model, column)
4487 })
4488 }
4489
4490 pub fn global_faceted_row_model(&self) -> &RowModel<'a, TData> {
4497 if self.options.manual_filtering {
4498 return self.pre_filtered_row_model();
4499 }
4500
4501 let Some(get) = self.get_global_faceted_row_model.as_ref() else {
4502 return self.filtered_row_model();
4503 };
4504
4505 self.global_faceted_row_model.get_or_init(|| get(self))
4506 }
4507
4508 pub fn global_faceted_unique_values(&self) -> &super::FacetCounts {
4513 if let Some(get) = self.get_global_faceted_unique_values.as_ref() {
4514 return self.global_faceted_unique_values.get_or_init(|| get(self));
4515 }
4516
4517 self.global_faceted_unique_values
4518 .get_or_init(super::FacetCounts::new)
4519 }
4520
4521 pub fn global_faceted_min_max_u64(&self) -> Option<(u64, u64)> {
4526 if let Some(get) = self.get_global_faceted_min_max_u64.as_ref() {
4527 return *self.global_faceted_min_max_u64.get_or_init(|| get(self));
4528 }
4529
4530 *self.global_faceted_min_max_u64.get_or_init(|| None)
4531 }
4532}
4533
4534impl<'a, TData> Table<'a, TData> {
4535 fn find_column_in_tree(&self, column_id: &str) -> Option<&super::ColumnDef<TData>> {
4536 fn find<'c, TData>(
4537 cols: &'c [super::ColumnDef<TData>],
4538 id: &str,
4539 ) -> Option<&'c super::ColumnDef<TData>> {
4540 for col in cols {
4541 if col.id.as_ref() == id {
4542 return Some(col);
4543 }
4544 if let Some(found) = find(&col.columns, id) {
4545 return Some(found);
4546 }
4547 }
4548 None
4549 }
4550
4551 find(self.column_tree.as_slice(), column_id)
4552 }
4553
4554 pub fn column_any(&self, column_id: &str) -> Option<&super::ColumnDef<TData>> {
4559 self.find_column_in_tree(column_id)
4560 }
4561
4562 pub fn column_tree_snapshot(&self) -> Vec<super::ColumnNodeSnapshot> {
4564 fn push_column_nodes<TData>(
4565 cols: &[super::ColumnDef<TData>],
4566 depth: usize,
4567 parent_id: Option<Arc<str>>,
4568 out: &mut Vec<super::ColumnNodeSnapshot>,
4569 ) {
4570 for col in cols {
4571 let id = col.id.clone();
4572 let child_ids: Vec<Arc<str>> = col.columns.iter().map(|c| c.id.clone()).collect();
4573 out.push(super::ColumnNodeSnapshot {
4574 id: id.clone(),
4575 depth,
4576 parent_id: parent_id.clone(),
4577 child_ids,
4578 });
4579 if !col.columns.is_empty() {
4580 push_column_nodes(&col.columns, depth + 1, Some(id), out);
4581 }
4582 }
4583 }
4584
4585 let mut out = Vec::new();
4586 push_column_nodes(&self.column_tree, 0, None, &mut out);
4587 out
4588 }
4589
4590 pub fn column_node_snapshot(&self, column_id: &str) -> Option<super::ColumnNodeSnapshot> {
4592 fn find<TData>(
4593 cols: &[super::ColumnDef<TData>],
4594 depth: usize,
4595 parent_id: Option<Arc<str>>,
4596 id: &str,
4597 ) -> Option<super::ColumnNodeSnapshot> {
4598 for col in cols {
4599 let col_id = col.id.clone();
4600 let next_parent = Some(col_id.clone());
4601 if col_id.as_ref() == id {
4602 let child_ids: Vec<Arc<str>> =
4603 col.columns.iter().map(|c| c.id.clone()).collect();
4604 return Some(super::ColumnNodeSnapshot {
4605 id: col_id,
4606 depth,
4607 parent_id,
4608 child_ids,
4609 });
4610 }
4611
4612 if !col.columns.is_empty()
4613 && let Some(found) = find(&col.columns, depth + 1, next_parent, id)
4614 {
4615 return Some(found);
4616 }
4617 }
4618 None
4619 }
4620
4621 find(self.column_tree.as_slice(), 0, None, column_id)
4622 }
4623
4624 fn column_leaf_ids_for(&self, column_id: &str) -> Option<Vec<super::ColumnId>> {
4625 fn push_leaf_ids<TData>(col: &super::ColumnDef<TData>, out: &mut Vec<super::ColumnId>) {
4626 if col.columns.is_empty() {
4627 out.push(col.id.clone());
4628 return;
4629 }
4630 for c in &col.columns {
4631 push_leaf_ids(c, out);
4632 }
4633 }
4634
4635 let col = self.find_column_in_tree(column_id)?;
4636 let mut leaf_ids = Vec::new();
4637 push_leaf_ids(col, &mut leaf_ids);
4638 Some(leaf_ids)
4639 }
4640}
4641
4642fn splitmix64(mut z: u64) -> u64 {
4643 z = z.wrapping_add(0x9e37_79b9_7f4a_7c15);
4644 z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
4645 z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
4646 z ^ (z >> 31)
4647}
4648
4649fn default_row_key_for_index_path<TData>(
4650 _: &TData,
4651 index: usize,
4652 parent: Option<&RowKey>,
4653) -> RowKey {
4654 if let Some(parent) = parent {
4655 let z = parent
4658 .0
4659 .wrapping_mul(0x9e37_79b9_7f4a_7c15)
4660 .wrapping_add((index as u64).wrapping_add(0xbf58_476d_1ce4_e5b9));
4661 RowKey(splitmix64(z))
4662 } else {
4663 RowKey::from_index(index)
4664 }
4665}
4666
4667fn build_core_row_model<'a, TData>(
4668 data: &'a [TData],
4669 get_row_key: &dyn Fn(&TData, usize, Option<&RowKey>) -> RowKey,
4670 get_row_id: Option<&dyn Fn(&TData, usize, Option<&RowId>) -> RowId>,
4671 get_sub_rows: Option<&dyn for<'r> Fn(&'r TData, usize) -> Option<&'r [TData]>>,
4672) -> RowModel<'a, TData> {
4673 let mut root_rows: Vec<RowIndex> = Vec::new();
4674 let mut flat_rows: Vec<RowIndex> = Vec::new();
4675 let mut rows_by_key: HashMap<RowKey, RowIndex> = HashMap::new();
4676 let mut rows_by_id: HashMap<RowId, RowIndex> = HashMap::new();
4677 let mut arena: Vec<Row<'a, TData>> = Vec::new();
4678
4679 fn access_rows<'a, TData>(
4680 original_rows: &'a [TData],
4681 depth: u16,
4682 parent: Option<RowIndex>,
4683 parent_key: Option<&RowKey>,
4684 parent_id: Option<RowId>,
4685 get_row_key: &dyn Fn(&TData, usize, Option<&RowKey>) -> RowKey,
4686 get_row_id: Option<&dyn Fn(&TData, usize, Option<&RowId>) -> RowId>,
4687 get_sub_rows: Option<&dyn for<'r> Fn(&'r TData, usize) -> Option<&'r [TData]>>,
4688 root_out: &mut Vec<RowIndex>,
4689 flat_out: &mut Vec<RowIndex>,
4690 rows_by_key: &mut HashMap<RowKey, RowIndex>,
4691 rows_by_id: &mut HashMap<RowId, RowIndex>,
4692 arena: &mut Vec<Row<'a, TData>>,
4693 ) -> Vec<RowIndex> {
4694 let mut rows: Vec<RowIndex> = Vec::with_capacity(original_rows.len());
4695 for (index, original) in original_rows.iter().enumerate() {
4696 let key = get_row_key(original, index, parent_key);
4697 let id = match get_row_id {
4698 None => match parent_id.as_ref() {
4699 None => RowId::new(index.to_string()),
4700 Some(parent_id) => RowId::new(format!("{}.{}", parent_id.as_str(), index)),
4701 },
4702 Some(f) => f(original, index, parent_id.as_ref()),
4703 };
4704 let row_index = arena.len();
4705 arena.push(Row {
4706 id: id.clone(),
4707 key,
4708 original,
4709 index,
4710 depth,
4711 parent,
4712 parent_key: parent_key.copied(),
4713 sub_rows: Vec::new(),
4714 });
4715 flat_out.push(row_index);
4716 rows_by_key.insert(key, row_index);
4717 rows_by_id.insert(id, row_index);
4718 rows.push(row_index);
4719
4720 if let Some(get_sub_rows) = get_sub_rows
4721 && let Some(sub) = get_sub_rows(original, index)
4722 && !sub.is_empty()
4723 {
4724 let next_parent_id = arena[row_index].id.clone();
4725 let children = access_rows(
4726 sub,
4727 depth.saturating_add(1),
4728 Some(row_index),
4729 Some(&key),
4730 Some(next_parent_id),
4731 get_row_key,
4732 get_row_id,
4733 Some(get_sub_rows),
4734 root_out,
4735 flat_out,
4736 rows_by_key,
4737 rows_by_id,
4738 arena,
4739 );
4740 if let Some(row) = arena.get_mut(row_index) {
4741 row.sub_rows = children;
4742 }
4743 }
4744 }
4745
4746 if depth == 0 {
4747 root_out.extend_from_slice(&rows);
4748 }
4749
4750 rows
4751 }
4752
4753 let _ = access_rows(
4754 data,
4755 0,
4756 None,
4757 None,
4758 None,
4759 get_row_key,
4760 get_row_id,
4761 get_sub_rows,
4762 &mut root_rows,
4763 &mut flat_rows,
4764 &mut rows_by_key,
4765 &mut rows_by_id,
4766 &mut arena,
4767 );
4768
4769 RowModel {
4770 root_rows,
4771 flat_rows,
4772 rows_by_key,
4773 rows_by_id,
4774 arena,
4775 }
4776}
4777
4778#[cfg(test)]
4779mod tests {
4780 use super::*;
4781 use crate::table::is_column_visible;
4782 use crate::table::{
4783 ColumnDef, ColumnFilter, ColumnId, ColumnPinPosition, ColumnSizingRegion, PaginationState,
4784 SortSpec, TableOptions, TableState, TanStackValue, create_column_helper,
4785 };
4786 use std::sync::Arc;
4787
4788 #[derive(Debug, Clone)]
4789 struct Person {
4790 #[allow(dead_code)]
4791 name: String,
4792 sub_rows: Option<Vec<Person>>,
4793 }
4794
4795 fn make_people(rows: usize, sub_rows: usize) -> Vec<Person> {
4796 (0..rows)
4797 .map(|i| Person {
4798 name: format!("Person {i}"),
4799 sub_rows: (sub_rows > 0).then(|| {
4800 (0..sub_rows)
4801 .map(|j| Person {
4802 name: format!("Person {i}.{j}"),
4803 sub_rows: None,
4804 })
4805 .collect()
4806 }),
4807 })
4808 .collect()
4809 }
4810
4811 #[test]
4812 fn core_row_model_produces_flat_rows_and_key_map() {
4813 let data = make_people(3, 0);
4814 let table = Table::builder(&data).build();
4815 let model = table.core_row_model();
4816
4817 assert_eq!(model.root_rows().len(), 3);
4818 assert_eq!(model.flat_rows().len(), 3);
4819 assert!(model.row_by_key(RowKey::from_index(0)).is_some());
4820 assert!(model.row_by_key(RowKey::from_index(1)).is_some());
4821 assert!(model.row_by_key(RowKey::from_index(2)).is_some());
4822 }
4823
4824 #[test]
4825 fn core_row_model_recurses_into_sub_rows_and_assigns_unique_keys() {
4826 let data = make_people(3, 2);
4827 let table = Table::builder(&data)
4828 .get_sub_rows(|p, _| p.sub_rows.as_deref())
4829 .build();
4830 let model = table.core_row_model();
4831
4832 assert_eq!(model.root_rows().len(), 3);
4833 assert_eq!(model.flat_rows().len(), 3 + 3 * 2);
4834
4835 let root_0 = model.row(model.root_rows()[0]).expect("root row 0");
4836 assert_eq!(root_0.sub_rows.len(), 2);
4837
4838 let c0 = model.row(root_0.sub_rows[0]).expect("root 0 child 0").key;
4839 let c1 = model.row(root_0.sub_rows[1]).expect("root 0 child 1").key;
4840 assert_ne!(c0, c1);
4841 assert_ne!(c0, root_0.key);
4842 assert_ne!(c1, root_0.key);
4843 assert!(model.row_by_key(c0).is_some());
4844 assert!(model.row_by_key(c1).is_some());
4845 }
4846
4847 #[test]
4848 fn core_row_model_allows_custom_stable_row_keys() {
4849 let data = make_people(2, 0);
4850 let table = Table::builder(&data)
4851 .get_row_key(|_p, i, _parent| RowKey(10_000 + i as u64))
4852 .build();
4853 let model = table.core_row_model();
4854
4855 assert!(model.row_by_key(RowKey(10_000)).is_some());
4856 assert!(model.row_by_key(RowKey(10_001)).is_some());
4857 assert!(model.row_by_key(RowKey::from_index(0)).is_none());
4858 }
4859
4860 #[derive(Debug, Clone)]
4861 struct Item {
4862 value: i32,
4863 }
4864
4865 #[test]
4866 fn table_sorted_row_model_uses_state_sorting() {
4867 let data = vec![Item { value: 2 }, Item { value: 1 }, Item { value: 3 }];
4868
4869 let helper = create_column_helper::<Item>();
4870 let columns = vec![helper.accessor("value", |it| it.value)];
4871
4872 let table = Table::builder(&data)
4873 .columns(columns)
4874 .state(TableState {
4875 sorting: vec![SortSpec {
4876 column: "value".into(),
4877 desc: false,
4878 }],
4879 ..TableState::default()
4880 })
4881 .build();
4882
4883 let sorted = table.sorted_row_model();
4884 let keys = sorted
4885 .root_rows()
4886 .iter()
4887 .filter_map(|&i| sorted.row(i).map(|r| r.key.0))
4888 .collect::<Vec<_>>();
4889
4890 assert_eq!(keys, vec![1, 0, 2]);
4891 assert!(std::ptr::eq(sorted, table.sorted_row_model()));
4892 }
4893
4894 #[test]
4895 fn row_unique_values_uses_column_hook_or_falls_back_to_single_get_value() {
4896 #[derive(Debug, Clone)]
4897 struct UniqueItem {
4898 tags: Vec<&'static str>,
4899 }
4900
4901 let data = vec![UniqueItem {
4902 tags: vec!["a", "b"],
4903 }];
4904
4905 let col = ColumnDef::new("tags")
4906 .sort_value_by(|it: &UniqueItem| {
4907 TanStackValue::Array(
4908 it.tags
4909 .iter()
4910 .map(|s| TanStackValue::String(Arc::<str>::from(*s)))
4911 .collect(),
4912 )
4913 })
4914 .unique_values_by(|it: &UniqueItem, _index| {
4915 it.tags
4916 .iter()
4917 .map(|s| TanStackValue::String(Arc::<str>::from(*s)))
4918 .collect()
4919 });
4920
4921 let table = Table::builder(&data).columns(vec![col]).build();
4922 let row_key = RowKey::from_index(0);
4923 assert_eq!(
4924 table.row_unique_values(row_key, "tags").unwrap(),
4925 vec![
4926 TanStackValue::String(Arc::<str>::from("a")),
4927 TanStackValue::String(Arc::<str>::from("b")),
4928 ]
4929 );
4930
4931 let col = ColumnDef::new("tags").sort_value_by(|it: &UniqueItem| {
4932 TanStackValue::Array(
4933 it.tags
4934 .iter()
4935 .map(|s| TanStackValue::String(Arc::<str>::from(*s)))
4936 .collect(),
4937 )
4938 });
4939
4940 let table = Table::builder(&data).columns(vec![col]).build();
4941 assert_eq!(
4942 table.row_unique_values(row_key, "tags").unwrap(),
4943 vec![TanStackValue::Array(vec![
4944 TanStackValue::String(Arc::<str>::from("a")),
4945 TanStackValue::String(Arc::<str>::from("b")),
4946 ])]
4947 );
4948
4949 let col = ColumnDef::<UniqueItem>::new("missing_accessor");
4950 let table = Table::builder(&data).columns(vec![col]).build();
4951 assert_eq!(table.row_unique_values(row_key, "missing_accessor"), None);
4952 }
4953
4954 #[test]
4955 fn table_row_model_applies_pagination_after_sorting() {
4956 let data = vec![
4957 Item { value: 2 },
4958 Item { value: 1 },
4959 Item { value: 3 },
4960 Item { value: 0 },
4961 ];
4962
4963 let helper = create_column_helper::<Item>();
4964 let columns = vec![helper.accessor("value", |it| it.value)];
4965
4966 let table = Table::builder(&data)
4967 .columns(columns)
4968 .state(TableState {
4969 sorting: vec![SortSpec {
4970 column: "value".into(),
4971 desc: false,
4972 }],
4973 pagination: PaginationState {
4974 page_index: 0,
4975 page_size: 2,
4976 },
4977 ..TableState::default()
4978 })
4979 .build();
4980
4981 let paged = table.row_model();
4982 let keys = paged
4983 .root_rows()
4984 .iter()
4985 .filter_map(|&i| paged.row(i).map(|r| r.key.0))
4986 .collect::<Vec<_>>();
4987
4988 assert_eq!(keys, vec![3, 1]);
4989 assert!(std::ptr::eq(paged, table.row_model()));
4990 }
4991
4992 #[test]
4993 fn table_selected_row_model_uses_state_row_selection() {
4994 let data = make_people(3, 0);
4995 let table = Table::builder(&data)
4996 .state(TableState {
4997 row_selection: [RowKey(1)].into_iter().collect(),
4998 ..TableState::default()
4999 })
5000 .build();
5001
5002 let selected = table.selected_row_model();
5003 assert_eq!(selected.root_rows().len(), 1);
5004 assert!(selected.row_by_key(RowKey(1)).is_some());
5005 assert!(std::ptr::eq(selected, table.selected_row_model()));
5006 }
5007
5008 #[test]
5009 fn table_visible_columns_respects_order_then_visibility() {
5010 let data = vec![Item { value: 1 }];
5011
5012 let helper = create_column_helper::<Item>();
5013 let columns = vec![
5014 helper.clone().accessor("a", |it| it.value),
5015 helper.clone().accessor("b", |it| it.value),
5016 helper.accessor("c", |it| it.value),
5017 ];
5018
5019 let mut state = TableState::default();
5020 state.column_order = vec!["c".into(), "a".into()];
5021 state.column_visibility.insert("b".into(), false);
5022
5023 let table = Table::builder(&data).columns(columns).state(state).build();
5024 let visible = table.visible_columns();
5025 let ids = visible.iter().map(|c| c.id.as_ref()).collect::<Vec<_>>();
5026
5027 assert_eq!(ids, vec!["c", "a"]);
5028 }
5029
5030 #[test]
5031 fn table_column_size_reads_from_state() {
5032 let data = vec![Item { value: 1 }];
5033
5034 let helper = create_column_helper::<Item>();
5035 let columns = vec![helper.accessor("value", |it| it.value)];
5036
5037 let mut state = TableState::default();
5038 state.column_sizing.insert("value".into(), 120.0);
5039
5040 let table = Table::builder(&data).columns(columns).state(state).build();
5041 assert_eq!(table.column_size("value"), Some(120.0));
5042 assert_eq!(table.column_size("missing"), None);
5043 }
5044
5045 #[derive(Debug, Clone)]
5046 struct TreeNode {
5047 id: u64,
5048 children: Vec<TreeNode>,
5049 }
5050
5051 #[test]
5052 fn expanding_default_is_collapsed_and_does_not_allocate() {
5053 let data = vec![
5054 TreeNode {
5055 id: 1,
5056 children: vec![
5057 TreeNode {
5058 id: 10,
5059 children: Vec::new(),
5060 },
5061 TreeNode {
5062 id: 11,
5063 children: Vec::new(),
5064 },
5065 ],
5066 },
5067 TreeNode {
5068 id: 2,
5069 children: vec![TreeNode {
5070 id: 20,
5071 children: Vec::new(),
5072 }],
5073 },
5074 ];
5075
5076 let table = Table::builder(&data)
5077 .get_row_key(|n, _i, _parent| RowKey(n.id))
5078 .get_sub_rows(|n, _i| Some(n.children.as_slice()))
5079 .build();
5080
5081 let pre = table.pre_expanded_row_model();
5082 let expanded = table.expanded_row_model();
5083 assert!(
5084 std::ptr::eq(pre, expanded),
5085 "empty expanding should not allocate"
5086 );
5087 assert_eq!(expanded.root_rows().len(), 2, "collapsed shows only roots");
5088 }
5089
5090 #[test]
5091 fn expanding_flattens_visible_rows_under_expanded_parents() {
5092 let data = vec![
5093 TreeNode {
5094 id: 1,
5095 children: vec![
5096 TreeNode {
5097 id: 10,
5098 children: Vec::new(),
5099 },
5100 TreeNode {
5101 id: 11,
5102 children: Vec::new(),
5103 },
5104 ],
5105 },
5106 TreeNode {
5107 id: 2,
5108 children: vec![TreeNode {
5109 id: 20,
5110 children: Vec::new(),
5111 }],
5112 },
5113 ];
5114
5115 let mut state = TableState::default();
5116 state.expanding = [RowKey(1)].into_iter().collect();
5117
5118 let table = Table::builder(&data)
5119 .get_row_key(|n, _i, _parent| RowKey(n.id))
5120 .get_sub_rows(|n, _i| Some(n.children.as_slice()))
5121 .state(state)
5122 .build();
5123
5124 let expanded = table.expanded_row_model();
5125 let keys = expanded
5126 .root_rows()
5127 .iter()
5128 .filter_map(|&i| expanded.row(i).map(|r| r.key.0))
5129 .collect::<Vec<_>>();
5130
5131 assert_eq!(keys, vec![1, 10, 11, 2]);
5132 }
5133
5134 #[test]
5135 fn paginate_expanded_rows_true_counts_children_in_pages() {
5136 let data = vec![
5137 TreeNode {
5138 id: 1,
5139 children: vec![
5140 TreeNode {
5141 id: 10,
5142 children: Vec::new(),
5143 },
5144 TreeNode {
5145 id: 11,
5146 children: Vec::new(),
5147 },
5148 ],
5149 },
5150 TreeNode {
5151 id: 2,
5152 children: vec![TreeNode {
5153 id: 20,
5154 children: Vec::new(),
5155 }],
5156 },
5157 ];
5158
5159 let mut state = TableState::default();
5160 state.expanding = [RowKey(1)].into_iter().collect();
5161 state.pagination = PaginationState {
5162 page_index: 0,
5163 page_size: 2,
5164 };
5165
5166 let table = Table::builder(&data)
5167 .get_row_key(|n, _i, _parent| RowKey(n.id))
5168 .get_sub_rows(|n, _i| Some(n.children.as_slice()))
5169 .state(state)
5170 .build();
5171
5172 let model = table.row_model();
5173 let keys = model
5174 .root_rows()
5175 .iter()
5176 .filter_map(|&i| model.row(i).map(|r| r.key.0))
5177 .collect::<Vec<_>>();
5178 assert_eq!(keys, vec![1, 10]);
5179 }
5180
5181 #[test]
5182 fn paginate_expanded_rows_false_expands_within_parent_page() {
5183 let data = vec![
5184 TreeNode {
5185 id: 1,
5186 children: vec![
5187 TreeNode {
5188 id: 10,
5189 children: Vec::new(),
5190 },
5191 TreeNode {
5192 id: 11,
5193 children: Vec::new(),
5194 },
5195 ],
5196 },
5197 TreeNode {
5198 id: 2,
5199 children: vec![TreeNode {
5200 id: 20,
5201 children: Vec::new(),
5202 }],
5203 },
5204 ];
5205
5206 let mut state = TableState::default();
5207 state.expanding = [RowKey(1)].into_iter().collect();
5208 state.pagination = PaginationState {
5209 page_index: 0,
5210 page_size: 1,
5211 };
5212
5213 let table = Table::builder(&data)
5214 .get_row_key(|n, _i, _parent| RowKey(n.id))
5215 .get_sub_rows(|n, _i| Some(n.children.as_slice()))
5216 .state(state)
5217 .options(TableOptions {
5218 paginate_expanded_rows: false,
5219 ..Default::default()
5220 })
5221 .build();
5222
5223 let model = table.row_model();
5224 let keys = model
5225 .root_rows()
5226 .iter()
5227 .filter_map(|&i| model.row(i).map(|r| r.key.0))
5228 .collect::<Vec<_>>();
5229 assert_eq!(keys, vec![1, 10, 11]);
5230 }
5231
5232 #[test]
5233 fn manual_filtering_skips_filtered_row_model() {
5234 #[derive(Debug, Clone)]
5235 struct Item {
5236 label: Arc<str>,
5237 }
5238
5239 let data = vec![
5240 Item {
5241 label: Arc::from("a"),
5242 },
5243 Item {
5244 label: Arc::from("b"),
5245 },
5246 ];
5247
5248 let helper = create_column_helper::<Item>();
5249 let columns = vec![
5250 helper
5251 .accessor("label", |it| it.label.clone())
5252 .filter_by(|row, q| row.label.as_ref() == q),
5253 ];
5254
5255 let mut state = TableState::default();
5256 state.global_filter = Some(serde_json::Value::String("b".to_string()));
5257
5258 let table = Table::builder(&data)
5259 .columns(columns)
5260 .state(state)
5261 .options(TableOptions {
5262 manual_filtering: true,
5263 ..Default::default()
5264 })
5265 .build();
5266
5267 assert!(std::ptr::eq(
5268 table.filtered_row_model(),
5269 table.core_row_model()
5270 ));
5271 }
5272
5273 #[test]
5274 fn filtered_row_model_override_skips_filtered_and_faceted_row_models() {
5275 #[derive(Debug, Clone)]
5276 struct Item {
5277 label: Arc<str>,
5278 }
5279
5280 let data = vec![
5281 Item {
5282 label: Arc::from("a"),
5283 },
5284 Item {
5285 label: Arc::from("b"),
5286 },
5287 ];
5288
5289 let helper = create_column_helper::<Item>();
5290 let columns = vec![
5291 helper
5292 .accessor("label", |it| it.label.clone())
5293 .filter_by(|row, q| row.label.as_ref() == q),
5294 ];
5295
5296 let mut state = TableState::default();
5297 state.column_filters = vec![ColumnFilter {
5298 column: "label".into(),
5299 value: serde_json::Value::String("b".to_string()),
5300 }];
5301
5302 let table = Table::builder(&data)
5303 .columns(columns)
5304 .state(state)
5305 .override_filtered_row_model_pre_filtered()
5306 .build();
5307
5308 assert!(std::ptr::eq(
5309 table.filtered_row_model(),
5310 table.pre_filtered_row_model()
5311 ));
5312 let faceted = table.faceted_row_model("label").expect("faceted row model");
5313 assert!(std::ptr::eq(faceted, table.pre_filtered_row_model()));
5314
5315 let snapshot = table.row_filter_state_snapshot();
5316 assert!(snapshot.filterable_ids.is_empty());
5317 assert!(snapshot.row_column_filters.is_empty());
5318 assert!(snapshot.row_column_filters_meta.is_empty());
5319 }
5320
5321 #[test]
5322 fn manual_sorting_skips_sorted_row_model() {
5323 #[derive(Debug, Clone)]
5324 struct Item {
5325 value: i32,
5326 }
5327
5328 let data = vec![Item { value: 2 }, Item { value: 1 }];
5329 let helper = create_column_helper::<Item>();
5330 let columns = vec![helper.accessor("value", |it| it.value)];
5331
5332 let mut state = TableState::default();
5333 state.sorting = vec![SortSpec {
5334 column: "value".into(),
5335 desc: false,
5336 }];
5337
5338 let table = Table::builder(&data)
5339 .columns(columns)
5340 .state(state)
5341 .options(TableOptions {
5342 manual_sorting: true,
5343 ..Default::default()
5344 })
5345 .build();
5346
5347 assert!(std::ptr::eq(
5348 table.sorted_row_model(),
5349 table.pre_sorted_row_model()
5350 ));
5351 }
5352
5353 #[test]
5354 fn sorted_row_model_override_skips_sorted_row_model() {
5355 #[derive(Debug, Clone)]
5356 struct Item {
5357 value: i32,
5358 }
5359
5360 let data = vec![Item { value: 2 }, Item { value: 1 }];
5361 let helper = create_column_helper::<Item>();
5362 let columns = vec![helper.accessor("value", |it| it.value)];
5363
5364 let mut state = TableState::default();
5365 state.sorting = vec![SortSpec {
5366 column: "value".into(),
5367 desc: false,
5368 }];
5369
5370 let table = Table::builder(&data)
5371 .columns(columns)
5372 .state(state)
5373 .override_sorted_row_model_pre_sorted()
5374 .build();
5375
5376 assert!(std::ptr::eq(
5377 table.sorted_row_model(),
5378 table.pre_sorted_row_model()
5379 ));
5380 }
5381
5382 #[test]
5383 fn manual_pagination_skips_row_model() {
5384 #[derive(Debug, Clone)]
5385 struct Item {
5386 #[allow(dead_code)]
5387 value: i32,
5388 }
5389
5390 let data = (0..20).map(|i| Item { value: i }).collect::<Vec<_>>();
5391 let mut state = TableState::default();
5392 state.pagination = PaginationState {
5393 page_index: 1,
5394 page_size: 5,
5395 };
5396
5397 let table = Table::builder(&data)
5398 .state(state)
5399 .options(TableOptions {
5400 manual_pagination: true,
5401 ..Default::default()
5402 })
5403 .build();
5404
5405 assert!(std::ptr::eq(
5406 table.row_model(),
5407 table.pre_pagination_row_model()
5408 ));
5409 }
5410
5411 #[test]
5412 fn table_expanding_all_marks_all_rows_expanded() {
5413 let data = vec![TreeNode {
5414 id: 1,
5415 children: vec![TreeNode {
5416 id: 10,
5417 children: Vec::new(),
5418 }],
5419 }];
5420
5421 let mut state = TableState::default();
5422 state.expanding = crate::table::ExpandingState::All;
5423
5424 let table = Table::builder(&data)
5425 .get_row_key(|n, _i, _parent| RowKey(n.id))
5426 .get_sub_rows(|n, _i| Some(n.children.as_slice()))
5427 .state(state)
5428 .build();
5429
5430 assert!(table.is_some_rows_expanded());
5431 assert!(table.is_all_rows_expanded());
5432 assert!(table.row_can_expand(RowKey(1)));
5433 assert!(table.row_is_all_parents_expanded(RowKey(10)));
5434 }
5435
5436 #[test]
5437 fn keep_pinned_rows_true_keeps_pins_across_pagination() {
5438 #[derive(Debug, Clone)]
5439 struct Item {
5440 #[allow(dead_code)]
5441 value: usize,
5442 }
5443
5444 let data = (0..20).map(|i| Item { value: i }).collect::<Vec<_>>();
5445
5446 let mut state = TableState::default();
5447 state.pagination = PaginationState {
5448 page_index: 1,
5449 page_size: 5,
5450 };
5451 state.row_pinning.top = vec![RowKey(1)];
5452
5453 let table_keep = Table::builder(&data)
5454 .state(state.clone())
5455 .options(TableOptions {
5456 keep_pinned_rows: true,
5457 ..Default::default()
5458 })
5459 .build();
5460 assert_eq!(table_keep.top_row_keys(), vec![RowKey(1)]);
5461
5462 let table_no_keep = Table::builder(&data)
5463 .state(state)
5464 .options(TableOptions {
5465 keep_pinned_rows: false,
5466 ..Default::default()
5467 })
5468 .build();
5469 assert!(table_no_keep.top_row_keys().is_empty());
5470 }
5471
5472 #[test]
5473 fn keep_pinned_rows_true_respects_expanded_parents() {
5474 let data = vec![TreeNode {
5475 id: 1,
5476 children: vec![TreeNode {
5477 id: 10,
5478 children: Vec::new(),
5479 }],
5480 }];
5481
5482 let mut collapsed = TableState::default();
5483 collapsed.row_pinning.top = vec![RowKey(10)];
5484
5485 let table_collapsed = Table::builder(&data)
5486 .get_row_key(|n, _i, _p| RowKey(n.id))
5487 .get_sub_rows(|n, _i| Some(n.children.as_slice()))
5488 .state(collapsed)
5489 .options(TableOptions {
5490 keep_pinned_rows: true,
5491 ..Default::default()
5492 })
5493 .build();
5494 assert!(table_collapsed.top_row_keys().is_empty());
5495
5496 let mut expanded = TableState::default();
5497 expanded.expanding = [RowKey(1)].into_iter().collect();
5498 expanded.row_pinning.top = vec![RowKey(10)];
5499
5500 let table_expanded = Table::builder(&data)
5501 .get_row_key(|n, _i, _p| RowKey(n.id))
5502 .get_sub_rows(|n, _i| Some(n.children.as_slice()))
5503 .state(expanded)
5504 .options(TableOptions {
5505 keep_pinned_rows: true,
5506 ..Default::default()
5507 })
5508 .build();
5509 assert_eq!(table_expanded.top_row_keys(), vec![RowKey(10)]);
5510 }
5511
5512 #[test]
5513 fn center_row_keys_excludes_pinned_rows() {
5514 #[derive(Debug, Clone)]
5515 struct Item {
5516 #[allow(dead_code)]
5517 value: usize,
5518 }
5519
5520 let data = (0..5).map(|i| Item { value: i }).collect::<Vec<_>>();
5521 let mut state = TableState::default();
5522 state.row_pinning.top = vec![RowKey(0)];
5523 state.row_pinning.bottom = vec![RowKey(4)];
5524
5525 let table = Table::builder(&data).state(state).build();
5526 assert_eq!(
5527 table.center_row_keys(),
5528 vec![RowKey(1), RowKey(2), RowKey(3)]
5529 );
5530 }
5531
5532 #[test]
5533 fn table_faceting_excludes_own_filter_and_can_return_labels() {
5534 #[derive(Debug, Clone)]
5535 struct Item {
5536 status_key: u64,
5537 status_label: Arc<str>,
5538 role_key: u64,
5539 role_label: Arc<str>,
5540 }
5541
5542 let data = vec![
5543 Item {
5544 status_key: 1,
5545 status_label: "A".into(),
5546 role_key: 10,
5547 role_label: "X".into(),
5548 },
5549 Item {
5550 status_key: 2,
5551 status_label: "B".into(),
5552 role_key: 10,
5553 role_label: "X".into(),
5554 },
5555 Item {
5556 status_key: 1,
5557 status_label: "A".into(),
5558 role_key: 20,
5559 role_label: "Y".into(),
5560 },
5561 ];
5562
5563 let status = ColumnDef::new("status")
5564 .filter_by(|it: &Item, q| it.status_label.as_ref() == q)
5565 .facet_key_by(|it: &Item| it.status_key)
5566 .facet_str_by(|it: &Item| it.status_label.as_ref());
5567 let role = ColumnDef::new("role")
5568 .filter_by(|it: &Item, q| it.role_label.as_ref() == q)
5569 .facet_key_by(|it: &Item| it.role_key)
5570 .facet_str_by(|it: &Item| it.role_label.as_ref());
5571
5572 let mut state = TableState::default();
5573 state.column_filters = vec![
5574 ColumnFilter {
5575 column: "status".into(),
5576 value: serde_json::Value::from("A"),
5577 },
5578 ColumnFilter {
5579 column: "role".into(),
5580 value: serde_json::Value::from("X"),
5581 },
5582 ];
5583
5584 let table = Table::builder(&data)
5585 .columns(vec![status, role])
5586 .state(state)
5587 .build();
5588
5589 let counts = table.faceted_unique_values("status").unwrap();
5590 assert_eq!(counts.get(&1).copied(), Some(1));
5591 assert_eq!(counts.get(&2).copied(), Some(1));
5592
5593 let labels = table.faceted_unique_value_labels("status").unwrap();
5594 assert_eq!(labels.get(&1).copied(), Some("A"));
5595 assert_eq!(labels.get(&2).copied(), Some("B"));
5596
5597 assert_eq!(table.faceted_min_max_u64("status"), Some((1, 2)));
5598 }
5599
5600 #[test]
5601 fn table_row_selection_page_toggle_and_indeterminate_queries() {
5602 #[derive(Debug, Clone)]
5603 struct Item {
5604 #[allow(dead_code)]
5605 value: usize,
5606 }
5607
5608 let data = (0..10).map(|i| Item { value: i }).collect::<Vec<_>>();
5609 let mut state = TableState::default();
5610 state.pagination = PaginationState {
5611 page_index: 0,
5612 page_size: 3,
5613 };
5614
5615 let table = Table::builder(&data).state(state).build();
5616 assert!(!table.is_all_page_rows_selected());
5617 assert!(!table.is_some_page_rows_selected());
5618
5619 let selection = table.toggled_all_page_rows_selected(None);
5620 let table2 = Table::builder(&data)
5621 .state(TableState {
5622 pagination: table.state().pagination,
5623 row_selection: selection,
5624 ..TableState::default()
5625 })
5626 .build();
5627 assert!(table2.is_all_page_rows_selected());
5628 assert!(!table2.is_some_page_rows_selected());
5629
5630 let selection = table2.toggled_all_page_rows_selected(None);
5631 assert!(selection.is_empty());
5632 }
5633
5634 #[test]
5635 fn table_row_selection_filtered_selected_counts_match_filtered_rows() {
5636 #[derive(Debug, Clone)]
5637 struct Item {
5638 status: Arc<str>,
5639 }
5640
5641 let data = vec![
5642 Item { status: "A".into() },
5643 Item { status: "B".into() },
5644 Item { status: "A".into() },
5645 ];
5646
5647 let status = ColumnDef::new("status").filter_by(|it: &Item, q| it.status.as_ref() == q);
5648
5649 let mut state = TableState::default();
5650 state.column_filters = vec![ColumnFilter {
5651 column: "status".into(),
5652 value: serde_json::Value::from("A"),
5653 }];
5654 state.row_selection = [RowKey::from_index(0)].into_iter().collect();
5655
5656 let table = Table::builder(&data)
5657 .columns(vec![status])
5658 .state(state)
5659 .build();
5660
5661 assert_eq!(table.filtered_row_count(), 2);
5662 assert_eq!(table.filtered_selected_row_count(), 1);
5663 assert_eq!(table.filtered_selected_flat_row_count(), 1);
5664 assert!(table.is_some_rows_selected());
5665 assert!(!table.is_all_rows_selected());
5666
5667 let selection = table.toggled_all_rows_selected(Some(true));
5668 let table2 = Table::builder(&data)
5669 .columns(vec![
5670 ColumnDef::new("status").filter_by(|it: &Item, q| it.status.as_ref() == q),
5671 ])
5672 .state(TableState {
5673 column_filters: table.state().column_filters.clone(),
5674 row_selection: selection,
5675 ..TableState::default()
5676 })
5677 .build();
5678
5679 assert!(table2.is_all_rows_selected());
5680 assert!(!table2.is_some_rows_selected());
5681 }
5682
5683 #[test]
5684 fn table_filtered_selected_row_model_intersects_filtered_rows() {
5685 #[derive(Debug, Clone)]
5686 struct Item {
5687 status: Arc<str>,
5688 }
5689
5690 let data = vec![
5691 Item { status: "A".into() },
5692 Item { status: "B".into() },
5693 Item { status: "A".into() },
5694 ];
5695
5696 let status = ColumnDef::new("status").filter_by(|it: &Item, q| it.status.as_ref() == q);
5697
5698 let mut state = TableState::default();
5699 state.column_filters = vec![ColumnFilter {
5700 column: "status".into(),
5701 value: serde_json::Value::from("A"),
5702 }];
5703 state.row_selection = [RowKey::from_index(0), RowKey::from_index(1)]
5704 .into_iter()
5705 .collect();
5706
5707 let table = Table::builder(&data)
5708 .columns(vec![status])
5709 .state(state)
5710 .build();
5711
5712 let selected = table.filtered_selected_row_model();
5713 assert_eq!(selected.root_rows().len(), 1);
5714 assert!(selected.row_by_key(RowKey::from_index(0)).is_some());
5715 assert!(std::ptr::eq(selected, table.filtered_selected_row_model()));
5716 }
5717
5718 #[test]
5719 fn table_page_selected_row_model_only_includes_page_rows() {
5720 #[derive(Debug, Clone)]
5721 struct Item {
5722 #[allow(dead_code)]
5723 value: usize,
5724 }
5725
5726 let data = (0..10).map(|i| Item { value: i }).collect::<Vec<_>>();
5727 let mut state = TableState::default();
5728 state.pagination = PaginationState {
5729 page_index: 1,
5730 page_size: 3,
5731 };
5732 state.row_selection = [RowKey::from_index(0), RowKey::from_index(4)]
5733 .into_iter()
5734 .collect();
5735
5736 let table = Table::builder(&data).state(state).build();
5737
5738 let selected = table.page_selected_row_model();
5739 assert_eq!(selected.root_rows().len(), 1);
5740 assert!(selected.row_by_key(RowKey::from_index(4)).is_some());
5741 assert!(std::ptr::eq(selected, table.page_selected_row_model()));
5742 }
5743
5744 #[test]
5745 fn table_column_visibility_toggle_respects_enable_hiding() {
5746 #[derive(Debug, Clone)]
5747 struct Item {
5748 #[allow(dead_code)]
5749 value: usize,
5750 }
5751
5752 let data = vec![Item { value: 1 }];
5753 let columns = vec![
5754 ColumnDef::new("a").enable_hiding(true),
5755 ColumnDef::new("b").enable_hiding(false),
5756 ];
5757
5758 let table = Table::builder(&data).columns(columns).build();
5759 assert_eq!(table.column_can_hide("a"), Some(true));
5760 assert_eq!(table.column_can_hide("b"), Some(false));
5761 assert_eq!(table.is_column_visible("a"), Some(true));
5762
5763 let next = table.toggled_column_visibility("a", Some(false)).unwrap();
5764 assert!(!is_column_visible(&next, &ColumnId::from("a")));
5765
5766 let next_b = table.toggled_column_visibility("b", Some(false)).unwrap();
5767 assert!(is_column_visible(&next_b, &ColumnId::from("b")));
5768 }
5769
5770 #[test]
5771 fn table_toggle_all_columns_visible_keeps_non_hideable_visible_when_hiding_all() {
5772 #[derive(Debug, Clone)]
5773 struct Item {
5774 #[allow(dead_code)]
5775 value: usize,
5776 }
5777
5778 let data = vec![Item { value: 1 }];
5779 let columns = vec![
5780 ColumnDef::new("a").enable_hiding(true),
5781 ColumnDef::new("b").enable_hiding(false),
5782 ];
5783
5784 let table = Table::builder(&data).columns(columns).build();
5785 let next = table.toggled_all_columns_visible(Some(false));
5786
5787 assert!(!is_column_visible(&next, &ColumnId::from("a")));
5788 assert!(is_column_visible(&next, &ColumnId::from("b")));
5789 }
5790
5791 #[test]
5792 fn table_column_order_move_respects_enable_column_ordering() {
5793 #[derive(Debug, Clone)]
5794 struct Item {
5795 #[allow(dead_code)]
5796 value: usize,
5797 }
5798
5799 let data = vec![Item { value: 1 }];
5800 let columns = vec![
5801 ColumnDef::new("a").enable_ordering(true),
5802 ColumnDef::new("b").enable_ordering(false),
5803 ColumnDef::new("c").enable_ordering(true),
5804 ];
5805
5806 let mut state = TableState::default();
5807 state.column_order = vec!["a".into(), "b".into(), "c".into()];
5808 let table = Table::builder(&data).columns(columns).state(state).build();
5809
5810 let next = table.toggled_column_order_move("a", 2).unwrap();
5811 assert_eq!(
5812 next.iter().map(|c| c.as_ref()).collect::<Vec<_>>(),
5813 vec!["b", "c", "a"]
5814 );
5815
5816 let next_b = table.toggled_column_order_move("b", 0).unwrap();
5817 assert_eq!(
5818 next_b.iter().map(|c| c.as_ref()).collect::<Vec<_>>(),
5819 vec!["a", "b", "c"]
5820 );
5821 }
5822
5823 #[test]
5824 fn table_column_pinning_respects_enable_column_pinning() {
5825 #[derive(Debug, Clone)]
5826 struct Item {
5827 #[allow(dead_code)]
5828 value: usize,
5829 }
5830
5831 let data = vec![Item { value: 1 }];
5832 let columns = vec![
5833 ColumnDef::new("a").enable_pinning(true),
5834 ColumnDef::new("b").enable_pinning(false),
5835 ];
5836 let table = Table::builder(&data).columns(columns).build();
5837
5838 let next = table
5839 .toggled_column_pinning("a", Some(ColumnPinPosition::Left))
5840 .unwrap();
5841 assert_eq!(
5842 next.left.iter().map(|c| c.as_ref()).collect::<Vec<_>>(),
5843 vec!["a"]
5844 );
5845
5846 let next_b = table
5847 .toggled_column_pinning("b", Some(ColumnPinPosition::Right))
5848 .unwrap();
5849 assert!(next_b.left.is_empty());
5850 assert_eq!(
5851 next_b.right.iter().map(|c| c.as_ref()).collect::<Vec<_>>(),
5852 vec!["b"]
5853 );
5854 }
5855
5856 #[test]
5857 fn table_column_sizing_totals_and_start_offsets_respect_pinning_and_order() {
5858 #[derive(Debug, Clone)]
5859 struct Item {
5860 #[allow(dead_code)]
5861 value: usize,
5862 }
5863
5864 let data = vec![Item { value: 1 }];
5865 let columns = vec![
5866 ColumnDef::new("a").size(100.0),
5867 ColumnDef::new("b").size(50.0),
5868 ColumnDef::new("c").size(25.0),
5869 ];
5870
5871 let mut state = TableState::default();
5872 state.column_order = vec!["b".into(), "c".into(), "a".into()];
5873 state.column_pinning.left = vec!["b".into()];
5874 state.column_pinning.right = vec!["a".into()];
5875
5876 let table = Table::builder(&data).columns(columns).state(state).build();
5877
5878 assert_eq!(table.left_total_size(), 50.0);
5879 assert_eq!(table.center_total_size(), 25.0);
5880 assert_eq!(table.right_total_size(), 100.0);
5881 assert_eq!(table.total_size(), 175.0);
5882
5883 assert_eq!(table.column_start("b", ColumnSizingRegion::All), Some(0.0));
5884 assert_eq!(table.column_start("c", ColumnSizingRegion::All), Some(50.0));
5885 assert_eq!(table.column_start("a", ColumnSizingRegion::All), Some(75.0));
5886
5887 assert_eq!(
5888 table.column_after("b", ColumnSizingRegion::All),
5889 Some(125.0)
5890 );
5891 assert_eq!(
5892 table.column_after("c", ColumnSizingRegion::All),
5893 Some(100.0)
5894 );
5895 assert_eq!(table.column_after("a", ColumnSizingRegion::All), Some(0.0));
5896
5897 assert_eq!(table.column_start("b", ColumnSizingRegion::Left), Some(0.0));
5898 assert_eq!(table.column_start("c", ColumnSizingRegion::Left), None);
5899 assert_eq!(
5900 table.column_start("c", ColumnSizingRegion::Center),
5901 Some(0.0)
5902 );
5903 assert_eq!(
5904 table.column_start("a", ColumnSizingRegion::Right),
5905 Some(0.0)
5906 );
5907
5908 assert_eq!(table.column_after("b", ColumnSizingRegion::Left), Some(0.0));
5909 assert_eq!(table.column_after("c", ColumnSizingRegion::Left), None);
5910 assert_eq!(
5911 table.column_after("c", ColumnSizingRegion::Center),
5912 Some(0.0)
5913 );
5914 assert_eq!(
5915 table.column_after("a", ColumnSizingRegion::Right),
5916 Some(0.0)
5917 );
5918 }
5919}