kas_view/data_traits.rs
1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4// https://www.apache.org/licenses/LICENSE-2.0
5
6//! Traits for shared data objects
7
8use kas::{autoimpl, Id};
9use std::borrow::Borrow;
10#[allow(unused)] // doc links
11use std::cell::RefCell;
12use std::fmt::Debug;
13
14/// Bounds on the key type
15pub trait DataKey: Clone + Debug + Default + PartialEq + Eq + 'static {
16 /// Make an [`Id`] for a key
17 ///
18 /// The result must be distinct from `parent`.
19 /// Use [`Id::make_child`].
20 fn make_id(&self, parent: &Id) -> Id;
21
22 /// Reconstruct a key from an [`Id`]
23 ///
24 /// Where `child` is the output of [`Self::make_id`] for the same `parent`
25 /// *or any [`Id`] descended from that*, this should return a copy of
26 /// the `key` passed to `make_id`.
27 ///
28 /// See: [`Id::next_key_after`], [`Id::iter_keys_after`]
29 fn reconstruct_key(parent: &Id, child: &Id) -> Option<Self>;
30}
31
32impl DataKey for () {
33 fn make_id(&self, parent: &Id) -> Id {
34 // We need a distinct child, so use index 0
35 parent.make_child(0)
36 }
37
38 fn reconstruct_key(parent: &Id, child: &Id) -> Option<Self> {
39 if child.next_key_after(parent) == Some(0) {
40 Some(())
41 } else {
42 None
43 }
44 }
45}
46
47// NOTE: we cannot use this blanket impl without specialisation / negative impls
48// impl<Key: Cast<usize> + Clone + Debug + PartialEq + Eq + 'static> DataKey for Key
49impl DataKey for usize {
50 fn make_id(&self, parent: &Id) -> Id {
51 parent.make_child(*self)
52 }
53
54 fn reconstruct_key(parent: &Id, child: &Id) -> Option<Self> {
55 child.next_key_after(parent)
56 }
57}
58
59impl DataKey for (usize, usize) {
60 fn make_id(&self, parent: &Id) -> Id {
61 parent.make_child(self.0).make_child(self.1)
62 }
63
64 fn reconstruct_key(parent: &Id, child: &Id) -> Option<Self> {
65 let mut iter = child.iter_keys_after(parent);
66 let col = iter.next();
67 let row = iter.next();
68 col.zip(row)
69 }
70}
71
72/// Trait for shared data
73///
74/// By design, all methods take only `&self` and only allow immutable access to
75/// data.
76#[autoimpl(for<T: trait + ?Sized>
77 &T, &mut T, std::rc::Rc<T>, std::sync::Arc<T>, Box<T>)]
78pub trait SharedData: Debug {
79 /// Key type
80 type Key: DataKey;
81
82 /// Item type
83 type Item: Clone;
84
85 /// A borrow of the item type
86 ///
87 /// This type must support [`Borrow`] over [`Self::Item`]. This is, for
88 /// example, supported by `Self::Item` and `&Self::Item`.
89 ///
90 /// It is also recommended (but not required) that the type support
91 /// [`std::ops::Deref`]: this allows easier usage of [`Self::borrow`].
92 ///
93 /// TODO(spec): once Rust supports some form of specialization, `AsRef` will
94 /// presumably get blanket impls over `T` and `&T`, and will then be more
95 /// appropriate to use than `Borrow`.
96 type ItemRef<'b>: Borrow<Self::Item>
97 where
98 Self: 'b;
99
100 /// Check whether a key has data
101 fn contains_key(&self, key: &Self::Key) -> bool;
102
103 /// Borrow an item by `key`
104 ///
105 /// Returns `None` if `key` has no associated item.
106 ///
107 /// Depending on the implementation, this may involve some form of lock
108 /// such as `RefCell::borrow` or `Mutex::lock`. The implementation should
109 /// panic on lock failure, not return `None`.
110 fn borrow(&self, key: &Self::Key) -> Option<Self::ItemRef<'_>>;
111
112 /// Access a borrow of an item
113 ///
114 /// This is a convenience method over [`Self::borrow`].
115 fn with_ref<V>(&self, key: &Self::Key, f: impl FnOnce(&Self::Item) -> V) -> Option<V>
116 where
117 Self: Sized,
118 {
119 self.borrow(key).map(|borrow| f(borrow.borrow()))
120 }
121
122 /// Get data by key (clone)
123 ///
124 /// Returns `None` if `key` has no associated item.
125 ///
126 /// This has a default implementation over [`Self::borrow`].
127 #[inline]
128 fn get_cloned(&self, key: &Self::Key) -> Option<Self::Item> {
129 self.borrow(key).map(|r| r.borrow().to_owned())
130 }
131}
132
133/// Trait for viewable data lists
134///
135/// Provided implementations: `[T]`, `Vec<T>`.
136/// Warning: these implementations do not communicate changes to data.
137/// Non-static lists should use a custom type and trait implementation.
138#[allow(clippy::len_without_is_empty)]
139#[autoimpl(for<T: trait + ?Sized> &T, &mut T, std::rc::Rc<T>, std::sync::Arc<T>, Box<T>)]
140pub trait ListData: SharedData {
141 /// No data is available
142 fn is_empty(&self) -> bool {
143 self.len() == 0
144 }
145
146 /// Number of data items available
147 ///
148 /// Note: users may assume this is `O(1)`.
149 fn len(&self) -> usize;
150
151 /// Iterate over up to `limit` keys from `start`
152 ///
153 /// An example where `type Key = usize`:
154 /// ```ignore
155 /// fn iter_from(&self, start: usize, limit: usize) -> impl Iterator<Item = usize> {
156 /// start.min(self.len)..(start + limit).min(self.len)
157 /// }
158 /// ```
159 ///
160 /// This method is called on every update so should be reasonably fast.
161 fn iter_from(&self, start: usize, limit: usize) -> impl Iterator<Item = Self::Key>;
162}
163
164/// Trait for viewable data matrices
165///
166/// Data matrices are a kind of table where each cell has the same type.
167#[autoimpl(for<T: trait + ?Sized> &T, &mut T, std::rc::Rc<T>, std::sync::Arc<T>, Box<T>)]
168pub trait MatrixData: SharedData {
169 /// Column key type
170 type ColKey;
171 /// Row key type
172 type RowKey;
173
174 /// No data is available
175 fn is_empty(&self) -> bool;
176
177 /// Number of `(cols, rows)` available
178 ///
179 /// Note: users may assume this is `O(1)`.
180 fn len(&self) -> (usize, usize);
181
182 /// Iterate over up to `limit` column keys from `start`
183 ///
184 /// The result will be in deterministic implementation-defined order, with
185 /// a length of `max(limit, data_len - start)` where `data_len` is the number of
186 /// items available.
187 fn col_iter_from(&self, start: usize, limit: usize) -> impl Iterator<Item = Self::ColKey>;
188
189 /// Iterate over up to `limit` row keys from `start`
190 ///
191 /// The result will be in deterministic implementation-defined order, with
192 /// a length of `max(limit, data_len - start)` where `data_len` is the number of
193 /// items available.
194 fn row_iter_from(&self, start: usize, limit: usize) -> impl Iterator<Item = Self::RowKey>;
195
196 /// Make a key from parts
197 fn make_key(&self, col: &Self::ColKey, row: &Self::RowKey) -> Self::Key;
198}