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}