spru_util/rotating/
mod.rs1pub mod error;
2
3use std::marker::PhantomData;
4
5use derive_where::derive_where;
6use spru::common::error::AnyResult;
7use tagset::tagset;
8use telety::telety;
9
10use crate::cloned;
11
12#[telety(crate::rotating)]
14#[derive(Debug, Clone)]
15#[derive_where(Default)]
16#[derive(serde::Serialize, serde::Deserialize)]
17pub struct Rotating<T> {
18 items: Vec<T>,
19 position: usize,
20}
21
22impl<T> Rotating<T> {
23 pub fn as_slice(&self) -> &[T] {
24 self.items.as_slice()
25 }
26
27 pub fn position(&self) -> Option<usize> {
29 if self.items.is_empty() {
30 None
31 } else {
32 Some(self.position)
33 }
34 }
35
36 pub fn current(&self) -> Option<&T> {
38 self.items.get(self.position)
39 }
40
41 pub fn len(&self) -> usize {
42 self.items.len()
43 }
44
45 pub fn is_empty(&self) -> bool {
46 self.items.is_empty()
47 }
48
49 pub fn expect<U>(&self, expected_value: &U) -> Result<&T, error::Expected>
50 where
51 T: PartialEq<U>,
52 {
53 if let Some(current) = self.current()
54 && current == expected_value
55 {
56 return Ok(current);
57 }
58 Err(error::Expected)
59 }
60}
61
62pub fn create<T>(items: Vec<T>, position: usize) -> Create<T> {
63 assert!(items.is_empty() || position < items.len());
64
65 cloned::create(Rotating { items, position })
66}
67
68pub fn default<T>() -> Create<T> {
69 create(vec![], 0)
70}
71
72pub fn rotate<T>(reverse: bool) -> Rotate<T> {
73 Rotate {
74 reverse,
75 _p: PhantomData,
76 }
77}
78
79pub fn set_position<T>(position: usize) -> SetPosition<T> {
80 SetPosition {
81 position,
82 _p: PhantomData,
83 }
84}
85
86pub fn insert<T>(position: usize, item: T) -> Insert<T> {
87 Insert {
88 position,
89 item,
90 set_to_inserted: false,
91 }
92}
93
94pub fn remove<T>(position: usize) -> Remove<T> {
95 Remove {
96 position,
97 _p: PhantomData,
98 }
99}
100
101pub fn destroy<T>() -> Destroy<T> {
102 cloned::destroy()
103}
104
105#[telety(crate::rotating)]
106#[tagset(Create<T>)]
107#[tagset(Rotate<T>)]
108#[tagset(SetPosition<T>)]
109#[tagset(Insert<T>)]
110#[tagset(Remove<T>)]
111#[tagset(Destroy<T>)]
112#[tagset(reserved(..16))]
113pub struct Actions<T>;
114
115pub type Create<T> = cloned::Create<Rotating<T>>;
116
117pub type Destroy<T> = cloned::Destroy<Rotating<T>>;
118
119#[derive_where(Debug, Clone, Default, Serialize, Deserialize)]
120#[derive(spru::action::Update)]
121#[must_use]
122pub struct Rotate<T> {
123 reverse: bool,
124 _p: PhantomData<T>,
125}
126
127impl<T> spru::action::Update for Rotate<T>
128where
129 T: Clone,
130{
131 type T = Rotating<T>;
132 type Undo = Self;
133
134 #[allow(refining_impl_trait)]
135 fn update(&self, value: &mut Self::T) -> AnyResult<Option<Self::Undo>> {
136 let Self { reverse, _p } = *self;
137
138 let len = value.items.len();
139 if len > 0 {
140 let old_index = value.position;
141 let new_index = if reverse {
142 if old_index == 0 {
143 len - 1
144 } else {
145 old_index - 1
146 }
147 } else if old_index == len - 1 {
148 0
149 } else {
150 old_index + 1
151 };
152
153 if old_index != new_index {
154 value.position = new_index;
155 return Ok(Some(Self {
156 reverse: !reverse,
157 _p,
158 }));
159 }
160 }
161
162 Ok(None)
163 }
164}
165
166#[derive_where(Debug, Clone, Default, Serialize, Deserialize)]
167#[derive(spru::action::Update)]
168#[must_use]
169pub struct SetPosition<T> {
170 position: usize,
171 _p: PhantomData<T>,
172}
173
174impl<T> spru::action::Update for SetPosition<T>
175where
176 T: Clone,
177{
178 type T = Rotating<T>;
179 type Undo = Self;
180
181 #[allow(refining_impl_trait)]
182 fn update(&self, value: &mut Self::T) -> AnyResult<Option<Self::Undo>> {
183 let Self { mut position, _p } = *self;
184
185 if position >= value.items.len() {
186 Err(Error::InvalidPosition(position, value.items.len()).into())
187 } else if position != value.position {
188 std::mem::swap(&mut value.position, &mut position);
189
190 Ok(Some(Self { position, _p }))
191 } else {
192 Ok(None)
193 }
194 }
195}
196
197#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, spru::action::Update)]
198#[must_use]
199pub struct Insert<T> {
200 position: usize,
201 item: T,
202 set_to_inserted: bool,
203}
204
205impl<T> spru::action::Update for Insert<T>
206where
207 T: Clone,
208{
209 type T = Rotating<T>;
210 type Undo = Remove<T>;
211
212 #[allow(refining_impl_trait)]
213 fn update(&self, value: &mut Self::T) -> AnyResult<Self::Undo> {
214 let Self {
215 position,
216 ref item,
217 set_to_inserted,
218 } = *self;
219
220 if position <= value.items.len() {
221 value.items.insert(position, item.clone());
222
223 if set_to_inserted {
224 value.position = position;
226 } else if value.position >= position && value.items.len() > 1 {
227 value.position += 1;
230 }
231
232 Ok(Remove {
233 position,
234 _p: PhantomData,
235 })
236 } else {
237 Err(Error::InvalidPosition(position, value.items.len()).into())
238 }
239 }
240}
241
242#[derive_where(Debug, Clone, Default, Serialize, Deserialize)]
243#[derive(spru::action::Update)]
244#[must_use]
245pub struct Remove<T> {
246 position: usize,
247 _p: PhantomData<fn(T) -> T>,
248}
249
250impl<T> spru::action::Update for Remove<T>
251where
252 T: Clone,
253{
254 type T = Rotating<T>;
255 type Undo = Insert<T>;
256
257 #[allow(refining_impl_trait)]
258 fn update(&self, value: &mut Self::T) -> AnyResult<Self::Undo> {
259 let Self { position, _p } = *self;
260
261 if position < value.items.len() {
262 let set_to_inserted = position == value.position;
263 if position < value.position {
264 value.position -= 1;
265 }
266 let item = value.items.remove(position);
267 if value.position == value.items.len() {
268 value.position = 0;
269 }
270 Ok(Insert {
271 position,
272 item,
273 set_to_inserted,
274 })
275 } else {
276 Err(Error::InvalidPosition(position, value.items.len()).into())
277 }
278 }
279}
280
281#[derive(Debug, Clone, crate::FromInfallible, thiserror::Error)]
282#[non_exhaustive]
283pub enum Error {
284 #[error("Invalid position {0}, len() is {1}")]
285 InvalidPosition(usize, usize),
286}