sigmut/collections/
slab_map.rs

1use std::{
2    any::Any,
3    cell::{Ref, RefCell, RefMut},
4    ops::Index,
5    rc::Rc,
6};
7
8use derive_ex::derive_ex;
9use slabmap::SlabMap;
10
11use crate::{
12    core::{
13        BindKey, BindSink, BindSource, DirtyOrMaybeDirty, NotifyContext, SinkBindings, Slot,
14        SourceBinder, UpdateContext,
15    },
16    utils::{Changes, RefCountOps},
17    ActionContext, SignalContext,
18};
19
20const SLOT_ITEMS: Slot = Slot(usize::MAX);
21
22fn key_to_slot(key: usize) -> Slot {
23    assert!(key != usize::MAX);
24    Slot(key)
25}
26fn slot_to_key(slot: Slot) -> Option<usize> {
27    if slot == SLOT_ITEMS {
28        None
29    } else {
30        Some(slot.0)
31    }
32}
33
34pub struct SignalSlabMap<T>(Rc<dyn DynSignalSlabMap<T>>);
35
36impl<T: 'static> SignalSlabMap<T> {
37    pub fn from_scan(f: impl FnMut(&mut ItemsMut<T>, &mut SignalContext) + 'static) -> Self {
38        Self(Scan::new(f))
39    }
40
41    pub fn item<'a, 's: 'a>(&'a self, key: usize, sc: &mut SignalContext<'s>) -> Ref<'a, T> {
42        self.0.item(self.0.clone().to_any(), key, sc)
43    }
44    pub fn items<'a, 's: 'a>(&'a self, sc: &mut SignalContext<'s>) -> Items<'a, T> {
45        self.0.items(self.0.clone().to_any(), None, sc)
46    }
47    pub fn reader(&self) -> SignalSlabMapReader<T> {
48        SignalSlabMapReader::new(self.0.clone())
49    }
50}
51
52trait DynSignalSlabMap<T> {
53    fn to_any(self: Rc<Self>) -> Rc<dyn Any>;
54    fn item(&self, this: Rc<dyn Any>, key: usize, sc: &mut SignalContext) -> Ref<T>;
55    fn items(&self, this: Rc<dyn Any>, age: Option<usize>, sc: &mut SignalContext) -> Items<T>;
56    fn ref_counts(&self) -> RefMut<RefCountOps>;
57}
58
59pub struct SignalSlabMapReader<T> {
60    owner: Rc<dyn DynSignalSlabMap<T>>,
61    age: Option<usize>,
62}
63impl<T: 'static> SignalSlabMapReader<T> {
64    fn new(owner: Rc<dyn DynSignalSlabMap<T>>) -> Self {
65        Self { owner, age: None }
66    }
67    pub fn read<'a, 's: 'a>(&'a mut self, sc: &mut SignalContext<'s>) -> Items<'a, T> {
68        let age = self.age;
69
70        let mut ref_counts = self.owner.ref_counts();
71        ref_counts.increment();
72        ref_counts.decrement(age);
73
74        let items = self.owner.items(self.owner.clone().to_any(), age, sc);
75        self.age = Some(items.items.changes.end_age());
76        items
77    }
78}
79impl<T> Drop for SignalSlabMapReader<T> {
80    fn drop(&mut self) {
81        self.owner.ref_counts().decrement(self.age);
82    }
83}
84
85pub struct Items<'a, T> {
86    items: Ref<'a, ItemsMut<T>>,
87    age: Option<usize>,
88}
89
90impl<'a, T> Items<'a, T> {
91    pub fn is_empty(&self) -> bool {
92        self.len() == 0
93    }
94    pub fn len(&self) -> usize {
95        self.items.len
96    }
97    pub fn get(&self, key: usize) -> Option<&T> {
98        self.items.get(key)
99    }
100    pub fn iter(&self) -> Iter<T> {
101        Iter(self.items.items.iter())
102    }
103    pub fn changes(&self) -> impl Iterator<Item = SlabMapChange<T>> {
104        use iter_n::iter2::*;
105        if let Some(age) = self.age {
106            self.items
107                .changes
108                .items(age)
109                .map(|change| {
110                    let key = change.key;
111                    let value = &self.items.items[key].value;
112                    match change.action {
113                        ChangeAction::Insert => SlabMapChange::Insert {
114                            key,
115                            new_value: value,
116                        },
117                        ChangeAction::Remove => SlabMapChange::Remove {
118                            key,
119                            old_value: value,
120                        },
121                    }
122                })
123                .into_iter0()
124        } else {
125            self.iter()
126                .map(|(key, value)| SlabMapChange::Insert {
127                    key,
128                    new_value: value,
129                })
130                .into_iter1()
131        }
132    }
133}
134impl<'a, T> Index<usize> for Items<'a, T> {
135    type Output = T;
136    fn index(&self, index: usize) -> &Self::Output {
137        self.get(index).expect("index out of bounds")
138    }
139}
140
141impl<'a, T> IntoIterator for &'a Items<'a, T> {
142    type Item = (usize, &'a T);
143    type IntoIter = Iter<'a, T>;
144
145    fn into_iter(self) -> Self::IntoIter {
146        self.iter()
147    }
148}
149
150pub struct ItemsMut<T> {
151    items: SlabMap<Item<T>>,
152    len: usize,
153    changes: Changes<ChangeData>,
154}
155impl<T> ItemsMut<T> {
156    fn new() -> Self {
157        Self {
158            items: SlabMap::new(),
159            len: 0,
160            changes: Changes::new(),
161        }
162    }
163    fn edit_start(&mut self, ref_counts: &RefCell<RefCountOps>) -> usize {
164        ref_counts.borrow_mut().apply(&mut self.changes);
165        self.clean_changes();
166        self.changes.end_age()
167    }
168    fn edit_end(
169        &mut self,
170        age: usize,
171        sinks: &mut SinkBindingsSet,
172        mut f: impl FnMut(&mut SinkBindings),
173    ) {
174        let mut is_dirty = false;
175        for c in self.changes.items(age) {
176            is_dirty = true;
177            if let Some(sink) = sinks.get_mut(key_to_slot(c.key)) {
178                f(sink);
179            }
180        }
181        if is_dirty {
182            f(&mut sinks.any);
183        }
184        self.clean_changes();
185    }
186    fn edit_end_and_update(
187        &mut self,
188        age: usize,
189        sinks: &mut SinkBindingsSet,
190        uc: &mut UpdateContext,
191    ) {
192        self.edit_end(age, sinks, |sink| sink.update(true, uc))
193    }
194    fn edit_end_and_notify(
195        &mut self,
196        sinks: &mut SinkBindingsSet,
197        age: usize,
198        nc: &mut NotifyContext,
199    ) {
200        self.edit_end(age, sinks, |sink| sink.notify(DirtyOrMaybeDirty::Dirty, nc))
201    }
202
203    pub fn get(&self, key: usize) -> Option<&T> {
204        let item = self.items.get(key)?;
205        if item.is_exists {
206            Some(&item.value)
207        } else {
208            None
209        }
210    }
211    pub fn insert(&mut self, value: T) -> usize {
212        let key = self.items.insert(Item::new(value));
213        self.len += 1;
214        self.changes.push(ChangeData {
215            action: ChangeAction::Insert,
216            key,
217        });
218        key
219    }
220    pub fn remove(&mut self, key: usize) {
221        let item = &mut self.items[key];
222        assert!(item.is_exists);
223        item.is_exists = false;
224        self.len -= 1;
225        self.changes.push(ChangeData {
226            action: ChangeAction::Remove,
227            key,
228        });
229    }
230
231    fn clean_changes(&mut self) {
232        self.changes.clean(|d| match d.action {
233            ChangeAction::Insert => {}
234            ChangeAction::Remove => {
235                self.items.remove(d.key);
236            }
237        });
238    }
239}
240impl<T> Index<usize> for ItemsMut<T> {
241    type Output = T;
242    fn index(&self, index: usize) -> &Self::Output {
243        self.get(index).expect("index out of bounds")
244    }
245}
246
247pub struct Iter<'a, T>(slabmap::Iter<'a, Item<T>>);
248
249impl<'a, T> Iterator for Iter<'a, T> {
250    type Item = (usize, &'a T);
251
252    fn next(&mut self) -> Option<Self::Item> {
253        for (key, value) in self.0.by_ref() {
254            if value.is_exists {
255                return Some((key, &value.value));
256            }
257        }
258        None
259    }
260}
261
262struct Item<T> {
263    value: T,
264    is_exists: bool,
265}
266impl<T> Item<T> {
267    fn new(value: T) -> Self {
268        Self {
269            value,
270            is_exists: true,
271        }
272    }
273}
274
275#[derive(Clone, Copy, Debug)]
276pub enum SlabMapChange<'a, T> {
277    Insert { key: usize, new_value: &'a T },
278    Remove { key: usize, old_value: &'a T },
279}
280
281enum ChangeAction {
282    Insert,
283    Remove,
284}
285
286struct ChangeData {
287    action: ChangeAction,
288    key: usize,
289}
290
291#[derive_ex(Default, Clone(bound()))]
292#[default(Self::new())]
293pub struct StateSlabMap<T>(Rc<RawStateSlabMap<T>>);
294
295impl<T> StateSlabMap<T> {
296    pub fn new() -> Self {
297        Self(Rc::new(RawStateSlabMap {
298            items: RefCell::new(ItemsMut::new()),
299            sinks: RefCell::new(SinkBindingsSet::new()),
300            ref_counts: RefCell::new(RefCountOps::new()),
301        }))
302    }
303}
304
305impl<T: 'static> StateSlabMap<T> {
306    pub fn to_signal_slab_map(&self) -> SignalSlabMap<T> {
307        SignalSlabMap(self.0.clone())
308    }
309    pub fn insert(&self, value: T, ac: &mut ActionContext) -> usize {
310        let mut data = self.0.items.borrow_mut();
311        let age = data.edit_start(&self.0.ref_counts);
312        let key = data.insert(value);
313        data.edit_end_and_notify(&mut self.0.sinks.borrow_mut(), age, ac.nc());
314        key
315    }
316    pub fn remove(&self, key: usize, ac: &mut ActionContext) {
317        let mut data = self.0.items.borrow_mut();
318        let age = data.edit_start(&self.0.ref_counts);
319        data.remove(key);
320        data.edit_end_and_notify(&mut self.0.sinks.borrow_mut(), age, ac.nc());
321    }
322    pub fn item<'a, 's: 'a>(&'a self, key: usize, sc: &mut SignalContext<'s>) -> Ref<'a, T> {
323        self.0.bind(key_to_slot(key), sc);
324        self.0.item(key)
325    }
326    pub fn items<'a, 's: 'a>(&'a self, sc: &mut SignalContext<'s>) -> Items<'a, T> {
327        self.0.bind(SLOT_ITEMS, sc);
328        self.0.items(None)
329    }
330    pub fn reader(&self) -> SignalSlabMapReader<T> {
331        SignalSlabMapReader::new(self.0.clone())
332    }
333}
334
335struct RawStateSlabMap<T> {
336    items: RefCell<ItemsMut<T>>,
337    sinks: RefCell<SinkBindingsSet>,
338    ref_counts: RefCell<RefCountOps>,
339}
340impl<T: 'static> RawStateSlabMap<T> {
341    fn rc_this(this: Rc<dyn Any>) -> Rc<Self> {
342        Rc::downcast(this).unwrap()
343    }
344    fn bind(self: &Rc<Self>, slot: Slot, sc: &mut SignalContext) {
345        self.sinks.borrow_mut().bind(self.clone(), slot, sc);
346    }
347    fn item(&self, key: usize) -> Ref<T> {
348        Ref::map(self.items.borrow(), |r| r.get(key).expect("key not found"))
349    }
350    fn items(&self, age: Option<usize>) -> Items<T> {
351        let items = self.items.borrow();
352        Items { items, age }
353    }
354}
355
356impl<T: 'static> DynSignalSlabMap<T> for RawStateSlabMap<T> {
357    fn to_any(self: Rc<Self>) -> Rc<dyn Any> {
358        self
359    }
360
361    fn item(&self, this: Rc<dyn Any>, key: usize, sc: &mut SignalContext) -> Ref<T> {
362        Self::rc_this(this).bind(key_to_slot(key), sc);
363        self.item(key)
364    }
365
366    fn items(&self, this: Rc<dyn Any>, age: Option<usize>, sc: &mut SignalContext) -> Items<T> {
367        Self::rc_this(this).bind(SLOT_ITEMS, sc);
368        self.items(age)
369    }
370
371    fn ref_counts(&self) -> RefMut<RefCountOps> {
372        self.ref_counts.borrow_mut()
373    }
374}
375
376impl<T: 'static> BindSource for RawStateSlabMap<T> {
377    fn check(self: Rc<Self>, slot: Slot, key: BindKey, uc: &mut UpdateContext) -> bool {
378        self.sinks.borrow_mut().is_dirty(slot, key, uc)
379    }
380    fn unbind(self: Rc<Self>, slot: Slot, key: BindKey, uc: &mut UpdateContext) {
381        self.sinks.borrow_mut().unbind(slot, key, uc);
382    }
383    fn rebind(self: Rc<Self>, slot: Slot, key: BindKey, sc: &mut SignalContext) {
384        self.sinks.borrow_mut().rebind(self.clone(), slot, key, sc);
385    }
386}
387
388struct SinkBindingsSet {
389    items: Vec<SinkBindings>,
390    any: SinkBindings,
391}
392impl SinkBindingsSet {
393    fn new() -> Self {
394        Self {
395            items: Vec::new(),
396            any: SinkBindings::new(),
397        }
398    }
399    fn update_all(&mut self, is_dirty: bool, uc: &mut UpdateContext) {
400        for s in &mut self.items {
401            s.update(is_dirty, uc);
402        }
403        self.any.update(is_dirty, uc);
404    }
405    fn notify_all(&mut self, dirty: DirtyOrMaybeDirty, nc: &mut NotifyContext) {
406        for s in &mut self.items {
407            s.notify(dirty, nc);
408        }
409        self.any.notify(dirty, nc);
410    }
411
412    fn bind(&mut self, this: Rc<dyn BindSource>, slot: Slot, sc: &mut SignalContext) {
413        if let Some(key) = slot_to_key(slot) {
414            if self.items.len() < key {
415                self.items.resize_with(key + 1, SinkBindings::new);
416            }
417        }
418        if let Some(s) = self.get_mut(slot) {
419            s.bind(this, slot, sc);
420        }
421    }
422    fn unbind(&mut self, slot: Slot, key: BindKey, uc: &mut UpdateContext) {
423        if let Some(s) = self.get_mut(slot) {
424            s.unbind(key, uc);
425        }
426    }
427    fn rebind(
428        &mut self,
429        this: Rc<dyn BindSource>,
430        slot: Slot,
431        key: BindKey,
432        sc: &mut SignalContext,
433    ) {
434        if let Some(s) = self.get_mut(slot) {
435            s.rebind(this, slot, key, sc);
436        }
437    }
438
439    fn is_dirty(&self, slot: Slot, key: BindKey, uc: &mut UpdateContext) -> bool {
440        if let Some(s) = self.get(slot) {
441            s.is_dirty(key, uc)
442        } else {
443            true
444        }
445    }
446
447    fn get(&self, slot: Slot) -> Option<&SinkBindings> {
448        if let Some(key) = slot_to_key(slot) {
449            self.items.get(key)
450        } else {
451            Some(&self.any)
452        }
453    }
454    fn get_mut(&mut self, slot: Slot) -> Option<&mut SinkBindings> {
455        if let Some(key) = slot_to_key(slot) {
456            self.items.get_mut(key)
457        } else {
458            Some(&mut self.any)
459        }
460    }
461}
462
463struct Scan<T, F> {
464    data: RefCell<ScanData<T, F>>,
465    ref_counts: RefCell<RefCountOps>,
466    sinks: RefCell<SinkBindingsSet>,
467}
468impl<T, F> Scan<T, F>
469where
470    T: 'static,
471    F: FnMut(&mut ItemsMut<T>, &mut SignalContext) + 'static,
472{
473    fn new(f: F) -> Rc<Self> {
474        Rc::new_cyclic(|this| Self {
475            data: RefCell::new(ScanData {
476                sb: SourceBinder::new(this, Slot(0)),
477                items: ItemsMut::new(),
478                f,
479            }),
480            ref_counts: RefCell::new(RefCountOps::new()),
481            sinks: RefCell::new(SinkBindingsSet::new()),
482        })
483    }
484
485    fn update(self: &Rc<Self>, uc: &mut UpdateContext) {
486        if uc.borrow(&self.data).sb.is_clean() {
487            return;
488        }
489        let d = &mut *self.data.borrow_mut();
490        if d.sb.check(uc) {
491            let age = d.items.edit_start(&self.ref_counts);
492            d.sb.update(|sc| (d.f)(&mut d.items, sc), uc);
493            d.items
494                .edit_end_and_update(age, &mut self.sinks.borrow_mut(), uc);
495        }
496        self.sinks.borrow_mut().update_all(false, uc);
497    }
498    fn rc_this(this: Rc<dyn Any>) -> Rc<Self> {
499        Rc::downcast(this).unwrap()
500    }
501}
502
503impl<T, F> DynSignalSlabMap<T> for Scan<T, F>
504where
505    T: 'static,
506    F: FnMut(&mut ItemsMut<T>, &mut SignalContext) + 'static,
507{
508    fn to_any(self: Rc<Self>) -> Rc<dyn Any> {
509        self
510    }
511
512    fn item(&self, this: Rc<dyn Any>, key: usize, sc: &mut SignalContext) -> Ref<T> {
513        let this = Self::rc_this(this);
514        this.update(sc.uc());
515        self.sinks.borrow_mut().bind(this, key_to_slot(key), sc);
516        Ref::map(self.data.borrow(), |data| &data.items[key])
517    }
518
519    fn items(&self, this: Rc<dyn Any>, age: Option<usize>, sc: &mut SignalContext) -> Items<T> {
520        let this = Self::rc_this(this);
521        this.update(sc.uc());
522        self.sinks.borrow_mut().bind(this, SLOT_ITEMS, sc);
523        let data = Ref::map(self.data.borrow(), |data| &data.items);
524        Items { items: data, age }
525    }
526    fn ref_counts(&self) -> RefMut<RefCountOps> {
527        self.ref_counts.borrow_mut()
528    }
529}
530impl<T, F> BindSource for Scan<T, F>
531where
532    T: 'static,
533    F: FnMut(&mut ItemsMut<T>, &mut SignalContext) + 'static,
534{
535    fn check(self: Rc<Self>, slot: Slot, key: BindKey, uc: &mut UpdateContext) -> bool {
536        self.update(uc);
537        self.sinks.borrow().is_dirty(slot, key, uc)
538    }
539
540    fn unbind(self: Rc<Self>, slot: Slot, key: BindKey, uc: &mut UpdateContext) {
541        self.sinks.borrow_mut().unbind(slot, key, uc)
542    }
543
544    fn rebind(self: Rc<Self>, slot: Slot, key: BindKey, sc: &mut SignalContext) {
545        self.sinks.borrow_mut().rebind(self.clone(), slot, key, sc)
546    }
547}
548impl<T, F> BindSink for Scan<T, F>
549where
550    T: 'static,
551    F: FnMut(&mut ItemsMut<T>, &mut SignalContext) + 'static,
552{
553    fn notify(self: Rc<Self>, slot: Slot, dirty: DirtyOrMaybeDirty, nc: &mut NotifyContext) {
554        if self.data.borrow_mut().sb.on_notify(slot, dirty) {
555            self.sinks
556                .borrow_mut()
557                .notify_all(DirtyOrMaybeDirty::MaybeDirty, nc);
558        }
559    }
560}
561
562struct ScanData<T, F> {
563    sb: SourceBinder,
564    items: ItemsMut<T>,
565    f: F,
566}