skima/
list.rs

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	// TODO: implement key-based moves
80	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		// Sync same items at the beginning
91		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		// Sync same items at the end
112		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			// We only have new items, we need to add them
135			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			// We only have old items, we need to remove them
145			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				// TODO: remove from the end instead, this version is super inefficient
154				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					// TODO: remove from the end instead, this version is super inefficient
170					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			// INSERTS
198		}
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}