1use std::cell::RefCell;
6use std::rc::{Rc, Weak};
7
8pub use surpass::layout;
9use surpass::painter::{CachedTile, Color};
10
11use layout::{Flusher, Layout};
12
13use crate::small_bit_set::SmallBitSet;
14
15#[derive(Debug)]
31pub struct Buffer<'b, 'l, L: Layout> {
32 pub(crate) buffer: &'b mut [u8],
33 pub(crate) layout: &'l mut L,
34 pub(crate) layer_cache: Option<BufferLayerCache>,
35 pub(crate) flusher: Option<Box<dyn Flusher>>,
36}
37
38#[derive(Debug)]
51pub struct BufferBuilder<'b, 'l, L: Layout> {
52 buffer: Buffer<'b, 'l, L>,
53}
54
55impl<'b, 'l, L: Layout> BufferBuilder<'b, 'l, L> {
56 #[inline]
57 pub fn new(buffer: &'b mut [u8], layout: &'l mut L) -> Self {
58 Self { buffer: Buffer { buffer, layout, layer_cache: None, flusher: None } }
59 }
60
61 #[inline]
62 pub fn layer_cache(mut self, layer_cache: BufferLayerCache) -> Self {
63 self.buffer.layer_cache = Some(layer_cache);
64 self
65 }
66
67 #[inline]
68 pub fn flusher(mut self, flusher: Box<dyn Flusher>) -> Self {
69 self.buffer.flusher = Some(flusher);
70 self
71 }
72
73 #[inline]
74 pub fn build(self) -> Buffer<'b, 'l, L> {
75 self.buffer
76 }
77}
78
79#[derive(Debug)]
80struct IdDropper {
81 id: u8,
82 buffers_with_caches: Weak<RefCell<SmallBitSet>>,
83}
84
85impl Drop for IdDropper {
86 fn drop(&mut self) {
87 if let Some(buffers_with_caches) = Weak::upgrade(&self.buffers_with_caches) {
88 buffers_with_caches.borrow_mut().remove(self.id);
89 }
90 }
91}
92
93#[derive(Debug)]
94pub struct CacheInner {
95 pub clear_color: Option<Color>,
96 pub tiles: Vec<CachedTile>,
97 pub width: Option<usize>,
98 pub height: Option<usize>,
99 _id_dropper: IdDropper,
100}
101
102#[derive(Clone, Debug)]
148pub struct BufferLayerCache {
149 pub(crate) id: u8,
150 pub(crate) cache: Rc<RefCell<CacheInner>>,
151}
152
153impl BufferLayerCache {
154 pub(crate) fn new(id: u8, buffers_with_caches: Weak<RefCell<SmallBitSet>>) -> Self {
155 Self {
156 id,
157 cache: Rc::new(RefCell::new(CacheInner {
158 clear_color: None,
159 tiles: Vec::new(),
160 width: None,
161 height: None,
162 _id_dropper: IdDropper { id, buffers_with_caches },
163 })),
164 }
165 }
166
167 #[inline]
168 pub fn clear(&self) {
169 let mut cache = self.cache.borrow_mut();
170
171 cache.clear_color = None;
172 cache.tiles.fill(CachedTile::default());
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 use std::mem;
181
182 fn new_cache(bit_set: &Rc<RefCell<SmallBitSet>>) -> BufferLayerCache {
183 bit_set
184 .borrow_mut()
185 .first_empty_slot()
186 .map(|id| BufferLayerCache::new(id, Rc::downgrade(bit_set)))
187 .unwrap()
188 }
189
190 #[test]
191 fn clone_and_drop() {
192 let bit_set = Rc::new(RefCell::new(SmallBitSet::default()));
193
194 let cache0 = new_cache(&bit_set);
195 let cache1 = new_cache(&bit_set);
196 let cache2 = new_cache(&bit_set);
197
198 assert!(bit_set.borrow().contains(&0));
199 assert!(bit_set.borrow().contains(&1));
200 assert!(bit_set.borrow().contains(&2));
201
202 mem::drop(cache0.clone());
203 mem::drop(cache1.clone());
204 mem::drop(cache2.clone());
205
206 assert!(bit_set.borrow().contains(&0));
207 assert!(bit_set.borrow().contains(&1));
208 assert!(bit_set.borrow().contains(&2));
209
210 mem::drop(cache1);
211
212 assert!(bit_set.borrow().contains(&0));
213 assert!(!bit_set.borrow().contains(&1));
214 assert!(bit_set.borrow().contains(&2));
215
216 let cache1 = new_cache(&bit_set);
217
218 assert!(bit_set.borrow().contains(&0));
219 assert!(bit_set.borrow().contains(&1));
220 assert!(bit_set.borrow().contains(&2));
221
222 mem::drop(cache0);
223 mem::drop(cache1);
224 mem::drop(cache2);
225
226 assert!(!bit_set.borrow().contains(&0));
227 assert!(!bit_set.borrow().contains(&1));
228 assert!(!bit_set.borrow().contains(&2));
229 }
230}