leptos_struct_table/
loaded_rows.rs

1use std::ops::{Index, Range};
2
3#[derive(Clone)]
4pub enum RowState<T: Clone> {
5    /// The row is not yet loaded and a placeholder is displayed if the row is visible in the viewport.
6    Placeholder,
7    /// The row is loading and a placeholder is displayed if the row is visible in the viewport.
8    Loading,
9    /// The row has been loaded.
10    Loaded(T),
11    /// The row failed to load. This error is shown in the row if it's visible in the viewport.
12    Error(String),
13}
14
15impl<T: Clone> std::fmt::Debug for RowState<T> {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        match self {
18            RowState::Placeholder => write!(f, "Placeholder"),
19            RowState::Loading => write!(f, "Loading"),
20            RowState::Loaded(_) => write!(f, "Loaded"),
21            RowState::Error(e) => write!(f, "Error({})", e),
22        }
23    }
24}
25
26/// This is basically a cache for rows and used by [`TableContent`] internally to track
27/// which rows are already loaded, which are still loading and which are missing.
28pub struct LoadedRows<T: Clone> {
29    rows: Vec<RowState<T>>,
30}
31
32impl<T: Clone> LoadedRows<T> {
33    pub fn new() -> Self {
34        Self { rows: vec![] }
35    }
36
37    #[inline]
38    pub fn len(&self) -> usize {
39        self.rows.len()
40    }
41
42    #[inline]
43    pub fn resize(&mut self, len: usize) {
44        self.rows.resize(len, RowState::Placeholder);
45    }
46
47    pub fn write_loading(&mut self, range: Range<usize>) {
48        if range.end > self.rows.len() {
49            self.rows.resize(range.end, RowState::Placeholder);
50        }
51
52        for row in &mut self.rows[range] {
53            *row = RowState::Loading;
54        }
55    }
56
57    pub fn write_loaded(
58        &mut self,
59        loading_result: Result<(Vec<T>, Range<usize>), String>,
60        missing_range: Range<usize>,
61    ) {
62        match loading_result {
63            Ok((rows, range)) => {
64                if range.end > self.rows.len() {
65                    self.rows.resize(range.end, RowState::Placeholder);
66                }
67
68                for (self_row, loaded_row) in self.rows[range].iter_mut().zip(rows) {
69                    *self_row = RowState::Loaded(loaded_row);
70                }
71            }
72            Err(error) => {
73                let range = missing_range.start..missing_range.end.min(self.rows.len());
74                if range.start >= range.end {
75                    return;
76                }
77
78                for row in &mut self.rows[range] {
79                    *row = RowState::Error(error.clone());
80                }
81            }
82        }
83    }
84
85    #[inline]
86    pub fn missing_range(&self, range: Range<usize>) -> Option<Range<usize>> {
87        let do_load_predicate = |row| matches!(row, &RowState::Placeholder);
88
89        let slice = &self.rows[range.clone()];
90
91        let start = slice.iter().position(do_load_predicate)?;
92        let end = slice.iter().rposition(do_load_predicate)?;
93
94        let start = start + range.start;
95        let end = end + range.start + 1;
96
97        Some(start..end)
98    }
99
100    #[inline]
101    pub fn clear(&mut self) {
102        self.rows.fill(RowState::Placeholder);
103    }
104}
105
106impl<T: Clone> Index<Range<usize>> for LoadedRows<T> {
107    type Output = [RowState<T>];
108
109    #[inline]
110    fn index(&self, index: Range<usize>) -> &Self::Output {
111        &self.rows[index]
112    }
113}
114
115impl<T: Clone> Index<usize> for LoadedRows<T> {
116    type Output = RowState<T>;
117
118    #[inline]
119    fn index(&self, index: usize) -> &Self::Output {
120        &self.rows[index]
121    }
122}