kas_view/clerk/generator.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//! Data generation (high-level) traits
7
8use super::{AsyncClerk, Changes, Clerk, Key, Token, TokenChanges, TokenClerk};
9use kas::Id;
10use kas::event::ConfigCx;
11#[allow(unused)] use kas::{Events, Widget};
12use std::fmt::Debug;
13use std::ops::Range;
14
15/// Indicates whether an update to a generator changes any available data
16#[derive(Clone, Debug, PartialEq, Eq)]
17#[must_use]
18pub enum GeneratorChanges<Index> {
19 /// `None` indicates that no changes to the data has occurred.
20 None,
21 /// Indicates that [`Clerk::len`] may have changed but generated
22 /// values have not changed.
23 LenOnly,
24 /// Indicates that items in the given range may require an update.
25 /// The `generate` method will be called for each index in the
26 /// intersection of the given range with the visible data range.
27 Range(Range<Index>),
28 /// `Any` indicates that changes to the data set may have occurred.
29 Any,
30}
31
32/// Interface for generators over indexed data
33pub trait IndexedGenerator<Index>: Clerk<Index, Item: Clone + Default + PartialEq> {
34 /// Update the generator
35 ///
36 /// This is called by [`kas::Events::update`]. It should update `self` as
37 /// required reflecting possible data-changes and indicate through the
38 /// returned [`GeneratorChanges`] value the updates required to tokens and
39 /// views.
40 ///
41 /// Note: this method is called automatically when input data changes. When
42 /// data owned or referenced by the `IndexedGenerator` implementation is
43 /// changed it may be necessary to explicitly update the view controller,
44 /// e.g. using [`ConfigCx::update`].
45 ///
46 /// This method may be called frequently and without changes to `data`.
47 fn update(&mut self, data: &Self::Data) -> GeneratorChanges<Index>;
48
49 /// Generate an item
50 fn generate(&self, data: &Self::Data, index: Index) -> Self::Item;
51}
52
53/// Interface for generators over keyed data
54pub trait KeyedGenerator<Index>: Clerk<Index, Item: Clone + Default + PartialEq> {
55 /// Key type
56 ///
57 /// All data items should have a stable key so that data items may be
58 /// tracked through changing queries. This allows focus and selection to
59 /// correctly track items when the data query or filter changes.
60 ///
61 /// Where the query is fixed, this can just be the `Index` type.
62 type Key: Key;
63
64 /// Update the generator
65 ///
66 /// This is called by [`kas::Events::update`]. It should update `self` as
67 /// required reflecting possible data-changes and indicate through the
68 /// returned [`GeneratorChanges`] value the updates required to tokens and
69 /// views.
70 ///
71 /// Note: this method is called automatically when input data changes. When
72 /// data owned or referenced by the `KeyedGenerator` implementation is
73 /// changed it may be necessary to explicitly update the view controller,
74 /// e.g. using [`ConfigCx::update`].
75 ///
76 /// This method may be called frequently and without changes to `data`.
77 fn update(&mut self, data: &Self::Data) -> GeneratorChanges<Index>;
78
79 /// Get a key for a given `index`, if available
80 ///
81 /// This method should be fast since it may be called repeatedly.
82 /// This method is only called for `index` less than the result of
83 /// [`Clerk::len`].
84 ///
85 /// This may return `None` even when `index` is within the query's `range`
86 /// since data may be sparse; in this case the view widget at this `index`
87 /// is hidden.
88 fn key(&self, data: &Self::Data, index: Index) -> Option<Self::Key>;
89
90 /// Generate an item
91 ///
92 /// The `key` will be the result of [`Self::key`] for an `index` less than
93 /// [`Clerk::len`].
94 fn generate(&self, data: &Self::Data, key: &Self::Key) -> Self::Item;
95}
96
97impl<Index: Key, G: IndexedGenerator<Index>> KeyedGenerator<Index> for G {
98 type Key = Index;
99
100 fn update(&mut self, data: &Self::Data) -> GeneratorChanges<Index> {
101 self.update(data)
102 }
103
104 fn key(&self, _: &Self::Data, index: Index) -> Option<Self::Key> {
105 Some(index)
106 }
107
108 fn generate(&self, data: &Self::Data, key: &Self::Key) -> Self::Item {
109 self.generate(data, key.clone())
110 }
111}
112
113impl<Index, G: KeyedGenerator<Index>> AsyncClerk<Index> for G {
114 type Key = G::Key;
115
116 fn update(
117 &mut self,
118 _: &mut ConfigCx,
119 _: Id,
120 _: Range<Index>,
121 data: &Self::Data,
122 ) -> Changes<Index> {
123 match self.update(data) {
124 GeneratorChanges::None => Changes::None,
125 GeneratorChanges::LenOnly => Changes::NoPreparedItems,
126 GeneratorChanges::Range(range) => Changes::Range(range),
127 GeneratorChanges::Any => Changes::Any,
128 }
129 }
130}
131
132impl<Index, G: KeyedGenerator<Index>> TokenClerk<Index> for G {
133 type Token = Token<Self::Key, Self::Item>;
134
135 fn update_token(
136 &self,
137 data: &Self::Data,
138 index: Index,
139 update_item: bool,
140 token: &mut Option<Self::Token>,
141 ) -> TokenChanges {
142 let Some(key) = self.key(data, index) else {
143 *token = None;
144 return TokenChanges::None;
145 };
146
147 if !update_item
148 && let Some(token) = token.as_mut()
149 && token.key == key
150 {
151 return TokenChanges::None;
152 }
153
154 let item = self.generate(data, &key);
155 let mut changes = TokenChanges::Any;
156
157 if let Some(token) = token.as_mut()
158 && token.key == key
159 {
160 if token.item == item {
161 return TokenChanges::None;
162 } else {
163 changes = TokenChanges::SameKey;
164 }
165 }
166
167 *token = Some(Token { key, item });
168 changes
169 }
170
171 #[inline]
172 fn item<'r>(&'r self, _: &'r Self::Data, token: &'r Self::Token) -> &'r Self::Item {
173 &token.item
174 }
175}