1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::fmt::Debug;
4use std::marker::PhantomData;
5use std::rc::Rc;
6
7use indexmap::IndexMap;
8
9use crate::iter::IteratorExt;
10use crate::tree::Tree;
11use crate::{Backend, Markup};
12
13pub struct ListData<K, M> {
14 rendered: RefCell<HashMap<K, M>>,
15}
16
17pub struct List<K, T, F, M, B>
18where
19 K: std::hash::Hash + Eq,
20 F: Fn(&T, &K) -> M,
21 M: Markup<B>,
22 B: Backend,
23{
24 data: IndexMap<K, T>,
25 func: F,
26 _b: PhantomData<B>,
27}
28
29pub fn list<'a, K, T, F, M, B>(
30 iter: impl IntoIterator<Item = (K, T)>,
31 func: F,
32) -> List<K, T, F, M, B>
33where
34 K: Eq + std::hash::Hash,
35 F: Fn(&T, &K) -> M,
36 M: Markup<B>,
37 B: Backend,
38{
39 let mut set = IndexMap::new();
40 for a in iter.into_iter() {
41 set.insert(a.0, a.1);
42 }
43
44 List {
45 data: set,
46 func,
47 _b: PhantomData,
48 }
49}
50
51impl<K, T, F, M, B> Markup<B> for List<K, T, F, M, B>
52where
53 K: Eq + std::hash::Hash + Clone + Debug + 'static,
54 F: Fn(&T, &K) -> M,
55 M: Markup<B> + 'static,
56 B: Backend,
57{
58 fn has_own_node() -> bool {
59 true
60 }
61
62 fn render(&self, parent: &crate::tree::Tree<B>) {
63 let data = Rc::new(ListData {
64 rendered: Default::default(),
65 });
66
67 let mut rendered = data.rendered.borrow_mut();
68 for item in self.data.iter() {
69 let markup = (self.func)(&item.1, &item.0);
70 let tree = Tree::new(&parent);
71 markup.render(&tree);
72 rendered.insert(item.0.clone(), markup);
73 }
74
75 std::mem::drop(rendered);
76 parent.set_data(data);
77 }
78
79 fn diff(&self, prev: &Self, tree: &crate::tree::Tree<B>) {
81 let data = tree.data::<ListData<K, M>>();
82 let mut rendered = data.rendered.borrow_mut();
83
84 let mut next_iter = self.data.iter().de_peekable();
85 let mut prev_iter = prev.data.iter().de_peekable();
86
87 let mut prev_range = 0..prev.data.len();
88 let mut next_range = 0..self.data.len();
89
90 while prev_iter
92 .peek()
93 .and_then(|kprev| next_iter.peek().filter(|knext| kprev.0 == knext.0))
94 .is_some()
95 {
96 let prev_item = prev_iter.next().unwrap();
97 let next_item = next_iter.next().unwrap();
98 let tree = tree.child_at(prev_range.start);
99
100 let prev_m = rendered.get(&prev_item.0).unwrap();
101 let next_m = (self.func)(next_item.1, next_item.0);
102
103 next_m.diff(prev_m, &tree);
104
105 rendered.insert(next_item.0.clone(), next_m);
106
107 prev_range.start += 1;
108 next_range.start += 1;
109 }
110
111 while prev_iter
113 .peek_back()
114 .and_then(|kprev| next_iter.peek_back().filter(|knext| kprev.0 == knext.0))
115 .is_some()
116 {
117 let prev_item = prev_iter.next_back().unwrap();
118 let next_item = next_iter.next_back().unwrap();
119
120 let tree = tree.child_at(prev_range.start);
121
122 let prev_m = rendered.get(&prev_item.0).unwrap();
123 let next_m = (self.func)(next_item.1, next_item.0);
124
125 next_m.diff(prev_m, &tree);
126
127 rendered.insert(next_item.0.clone(), next_m);
128
129 prev_range.end -= 1;
130 next_range.end -= 1;
131 }
132
133 if prev_iter.peek().is_none() {
134 for node in next_iter {
136 let subtree = tree.insert_at(next_range.start);
137 let markup = (self.func)(node.1, node.0);
138 markup.render(&subtree);
139 rendered.insert(node.0.clone(), markup);
140 next_range.start += 1;
141 }
142 return;
143 } else if next_iter.peek().is_none() {
144 for prev_item in prev_iter {
146 let subtree = tree.child_at(prev_range.start);
147
148 let prev_m = rendered.remove(&prev_item.0).unwrap();
149
150 prev_m.drop(&subtree, true);
151 subtree.disconnect(true);
152
153 tree.remove_at(prev_range.start);
155 }
156
157 return;
158 }
159
160 for prev_item in prev_iter {
161 match next_iter.next() {
162 None => {
163 let subtree = tree.child_at(prev_range.start);
164 let prev_m = rendered.remove(&prev_item.0).unwrap();
165
166 prev_m.drop(&subtree, true);
167 subtree.disconnect(true);
168
169 tree.remove_at(prev_range.start);
171 }
172 Some(next_item) => {
173 let tree = tree.child_at(prev_range.start);
174
175 let prev_m = rendered.get(&prev_item.0).unwrap();
176 let next_m = (self.func)(next_item.1, next_item.0);
177
178 next_m.diff(prev_m, &tree);
179
180 rendered.insert(next_item.0.clone(), next_m);
181
182 prev_range.start += 1;
183 next_range.start += 1;
184 }
185 }
186 }
187
188 for next_item in next_iter {
189 let subtree = tree.insert_at(next_range.start);
190 let markup = (self.func)(next_item.1, next_item.0);
191 markup.render(&subtree);
192
193 rendered.insert(next_item.0.clone(), markup);
194
195 next_range.start += 1;
196 next_range.start += 1;
197 }
199 }
200
201 fn drop(&self, tree: &Tree<B>, should_unmount: bool) {
202 let data = tree.data::<ListData<K, M>>();
203 let rendered = data.rendered.borrow_mut();
204
205 let mut cursor = None;
206 for (i, key) in self.data.keys().enumerate() {
207 if i == 0 {
208 cursor = Some(tree.first_child());
209 } else {
210 cursor = Some(cursor.unwrap().next());
211 }
212
213 let markup = rendered.get(key).unwrap();
214 markup.drop(cursor.as_ref().unwrap(), should_unmount);
215 }
216
217 tree.clear()
218 }
219}