1use crate::{
3 CausalContext, CausalDotStore, ExtensionType, Identifier, MvReg, OrArray, OrMap,
4 crdts::{
5 TypeVariantValue, Value,
6 orarray::{Position, Uid},
7 snapshot::{self, ToValue},
8 },
9};
10use std::{convert::Infallible, fmt};
11
12pub fn values<C>(m: &OrArray<C>) -> snapshot::OrArray<snapshot::AllValues<'_, C::ValueRef<'_>>>
40where
41 C: ExtensionType,
42{
43 m.values()
44}
45
46#[allow(clippy::type_complexity)]
49pub fn value<C>(
50 m: &OrArray<C>,
51) -> Result<
52 snapshot::OrArray<snapshot::CollapsedValue<'_, C::ValueRef<'_>>>,
53 Box<snapshot::SingleValueError<<&OrArray<C> as ToValue>::LeafValue>>,
54>
55where
56 C: ExtensionType,
57{
58 m.value()
59}
60
61pub fn create<C>() -> impl Fn(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
63where
64 C: ExtensionType + fmt::Debug + PartialEq,
65{
66 move |m, cc, id| m.create(cc, id)
67}
68
69pub fn insert<O, C>(
71 o: O,
72 idx: usize,
73) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
74where
75 O: FnOnce(&CausalContext, Identifier) -> CausalDotStore<Value<C>>,
76 C: ExtensionType + fmt::Debug + PartialEq,
77{
78 move |m, cc, id| {
79 let uid = cc.next_dot_for(id).into();
80 let p = create_position_for_index(m, idx);
81 m.insert(uid, o, p, cc, id)
82 }
83}
84
85pub fn insert_map<O, C>(
87 o: O,
88 idx: usize,
89) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
90where
91 O: FnOnce(&CausalContext, Identifier) -> CausalDotStore<OrMap<String, C>>,
92 C: ExtensionType + fmt::Debug + PartialEq,
93{
94 insert(move |cc, id| (o)(cc, id).map_store(Value::Map), idx)
95}
96
97pub fn insert_array<O, C>(
99 o: O,
100 idx: usize,
101) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
102where
103 O: FnOnce(&CausalContext, Identifier) -> CausalDotStore<OrArray<C>>,
104 C: ExtensionType + fmt::Debug + PartialEq,
105{
106 insert(move |cc, id| (o)(cc, id).map_store(Value::Array), idx)
107}
108
109pub fn insert_register<O, C>(
111 o: O,
112 idx: usize,
113) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
114where
115 O: FnOnce(&CausalContext, Identifier) -> CausalDotStore<MvReg>,
116 C: ExtensionType + fmt::Debug + PartialEq,
117{
118 insert(move |cc, id| (o)(cc, id).map_store(Value::Register), idx)
119}
120
121pub fn apply<O, C>(
123 o: O,
124 idx: usize,
125) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
126where
127 O: FnOnce(&TypeVariantValue<C>, &CausalContext, Identifier) -> CausalDotStore<Value<C>>,
128 C: ExtensionType + fmt::Debug + PartialEq,
129{
130 move |m, cc, id| {
131 let uid = uid_from_index(m, idx);
132 assert_ne!(idx, m.len(), "index out of bounds");
133 let p = create_position_for_index(m, idx);
134 m.apply(uid, o, p, cc, id)
135 }
136}
137
138pub fn apply_to_map<O, C>(
140 o: O,
141 idx: usize,
142) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
143where
144 O: FnOnce(&OrMap<String, C>, &CausalContext, Identifier) -> CausalDotStore<OrMap<String, C>>,
145 C: ExtensionType + fmt::Debug + PartialEq,
146{
147 apply(
148 move |m, cc, id| (o)(&m.map, cc, id).map_store(Value::Map),
149 idx,
150 )
151}
152
153pub fn apply_to_array<O, C>(
155 o: O,
156 idx: usize,
157) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
158where
159 O: FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>,
160 C: ExtensionType + fmt::Debug + PartialEq,
161{
162 apply(
163 move |m, cc, id| (o)(&m.array, cc, id).map_store(Value::Array),
164 idx,
165 )
166}
167
168pub fn apply_to_register<O, C>(
170 o: O,
171 idx: usize,
172) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
173where
174 O: FnOnce(&MvReg, &CausalContext, Identifier) -> CausalDotStore<MvReg>,
175 C: ExtensionType + fmt::Debug + PartialEq,
176{
177 apply(
178 move |m, cc, id| (o)(&m.reg, cc, id).map_store(Value::Register),
179 idx,
180 )
181}
182
183pub fn mv<C>(
185 from: usize,
186 to: usize,
187) -> impl Fn(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
188where
189 C: ExtensionType + fmt::Debug + PartialEq,
190{
191 move |m, cc, id| {
192 let uid = uid_from_index(m, from);
193 let p = create_position_for_index(m, to);
194 m.mv(uid, p, cc, id)
195 }
196}
197
198pub fn delete<'s, C>(
200 idx: usize,
201) -> impl Fn(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>> + 's
202where
203 C: ExtensionType + fmt::Debug + PartialEq,
204{
205 move |m, cc, id| {
206 let uid = uid_from_index(m, idx);
207 m.delete(uid, cc, id)
208 }
209}
210
211pub fn clear<C>() -> impl Fn(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
213where
214 C: ExtensionType + fmt::Debug + PartialEq,
215{
216 move |m, cc, id| m.clear(cc, id)
217}
218
219fn ids<C>(m: &OrArray<C>) -> Vec<((), Uid, Position)> {
220 m.with_list(|_, _, _| Ok::<_, Infallible>(Some(())))
222 .unwrap()
223}
224
225fn create_position_for_index<C>(m: &OrArray<C>, idx: usize) -> Position {
231 if idx == 0 {
239 let min_p = m.iter_as_is().map(|(_, _, p)| p).min();
240 return Position::between(None, min_p);
241 }
242 if idx == m.len() {
243 let max_p = m.iter_as_is().map(|(_, _, p)| p).max();
244 return Position::between(max_p, None);
245 }
246
247 assert!(
248 idx < m.len(),
249 "index out of bounds ({idx} when length is {})",
250 m.len()
251 );
252 let ids = ids(m);
255 let pos_at_index = ids.get(idx).map(|(_, _, p)| *p);
256 let pos_at_previous_index = if idx == 0 {
257 None
258 } else {
259 Some(
260 ids.get(idx - 1)
261 .expect("we check for out-of-bounds above")
262 .2,
263 )
264 };
265 Position::between(pos_at_previous_index, pos_at_index)
266}
267
268fn uid_from_index<C>(m: &OrArray<C>, idx: usize) -> Uid {
269 ids(m)[idx].1
270}