1use crate::expr::arena::with_arena;
25use crate::expr::path;
26use crate::expr::rules::{self, Shape, Step};
27use crate::expr::{Path, Seg};
28use crate::state::splice;
29use crate::state::{Lookup, RunContext};
30use bumpalo::Bump;
31use datavalue::{DataValue, OwnedDataValue};
32
33#[derive(Clone, Debug, Default)]
35pub(crate) struct Overlay(Vec<(Path, Write)>);
36
37#[derive(Clone, Debug, PartialEq)]
41#[non_exhaustive]
42pub enum Write {
43 Set(OwnedDataValue),
46 Blocked(OwnedDataValue),
51 Removed,
53}
54
55impl Overlay {
56 pub(crate) fn is_empty(&self) -> bool {
58 self.0.is_empty()
59 }
60
61 pub(crate) fn set(&mut self, base: DataValue<'_>, path: &Path, value: OwnedDataValue) {
65 let lands = self.lands(base, path.segs());
66 self.push(path, value, lands);
67 }
68
69 pub(crate) fn push(&mut self, path: &Path, value: OwnedDataValue, lands: bool) {
73 let write = if lands {
74 Write::Set(value)
75 } else {
76 Write::Blocked(value)
77 };
78 self.0.push((path.clone(), write));
79 }
80
81 pub(crate) fn remove(&mut self, path: &Path) {
83 self.0.push((path.clone(), Write::Removed));
84 }
85
86 pub(crate) fn lookup(&self, path: &Path) -> Lookup<'_> {
90 let p = path.segs();
91 for (at, write) in self.0.iter().rev() {
92 let e = at.segs();
93 let set = match write {
94 Write::Set(value) => Some(value),
95 Write::Removed => None,
96 Write::Blocked(_) => continue,
97 };
98 match relation(e, p) {
99 Rel::Apart => {}
100 Rel::Siblings { at, e: x, p: y } if !moves(e.len(), set.is_some(), at, x, y) => {}
101 Rel::Above => {
102 return match set {
103 Some(value) => Lookup::Owned(path::get(value, &p[e.len()..])),
104 None if may_shift(e) => Lookup::Dirty,
105 None => Lookup::Owned(None),
106 };
107 }
108 Rel::Below | Rel::Siblings { .. } | Rel::Unsure => return Lookup::Dirty,
109 }
110 }
111 Lookup::Clean
112 }
113
114 pub(crate) fn splice_onto<'a>(&'a self, root: DataValue<'a>, arena: &'a Bump) -> DataValue<'a> {
117 self.0.iter().fold(root, |root, (path, write)| {
118 let spliced = match write {
119 Write::Set(value) => splice::set(arena, root, path.segs(), value.view_in(arena)),
120 Write::Removed => splice::remove(arena, root, path.segs()),
121 Write::Blocked(_) => return root,
122 };
123 debug_assert!(
124 spliced.is_some(),
125 "a write lands on the root it was made on"
126 );
127 spliced.unwrap_or(root)
128 })
129 }
130
131 pub(crate) fn into_writes(self) -> Vec<(Path, Write)> {
133 self.0
134 }
135
136 pub(crate) fn apply(self, rc: &mut RunContext<'_, '_>) {
141 for (path, write) in self.0 {
142 match write {
143 Write::Set(value) | Write::Blocked(value) => {
144 rc.set_segs(path.segs(), value, None);
145 }
146 Write::Removed => {
147 rc.remove_segs(path.segs());
148 }
149 }
150 }
151 }
152
153 fn lands(&self, base: DataValue<'_>, segs: &[Seg]) -> bool {
159 if self.is_empty() {
160 return splice::resolve(base, segs).is_some();
161 }
162 let mut holder = Shape::Object;
164 for i in 1..segs.len() {
165 let last = i + 1 == segs.len();
166 let child = if last {
169 None
170 } else {
171 match self.held_at(base, &segs[..=i]) {
172 Some(held) => held,
173 None => {
174 return with_arena(|arena| {
175 splice::resolve(self.splice_onto(base, arena), segs).is_some()
176 });
177 }
178 }
179 };
180 match rules::step(holder, &segs[i], child, last) {
181 Step::Block => return false,
182 Step::Create => return true,
183 Step::Into => holder = child.unwrap_or(Shape::Null),
184 }
185 }
186 true
187 }
188
189 fn held_at(&self, base: DataValue<'_>, q: &[Seg]) -> Option<Option<Shape>> {
192 let mut created = None;
196 for (at, write) in self.0.iter().rev() {
197 let e = at.segs();
198 let set = match write {
199 Write::Set(value) => Some(value),
200 Write::Removed => None,
201 Write::Blocked(_) => continue,
202 };
203 match relation(e, q) {
204 Rel::Apart => {}
205 Rel::Siblings { at, e: x, p: y } if !moves(e.len(), set.is_some(), at, x, y) => {}
206 Rel::Below => {
207 if set.is_some() {
208 created = Some(&e[q.len()]);
209 }
210 }
211 Rel::Above => {
212 let held = match set {
213 Some(value) => path::get(value, &q[e.len()..]).map(Shape::of_owned),
214 None if may_shift(e) => return None,
215 None => None,
216 };
217 return Some(or_created(held, created));
218 }
219 Rel::Siblings { .. } | Rel::Unsure => return None,
220 }
221 }
222 Some(or_created(
223 splice::get(base, q).map(|v| Shape::of_view(&v)),
224 created,
225 ))
226 }
227}
228
229fn or_created(held: Option<Shape>, below: Option<&Seg>) -> Option<Shape> {
234 match (held, below) {
235 (None | Some(Shape::Null), Some(next)) => Some(rules::container_for(next)),
236 (held, _) => held,
237 }
238}
239
240#[derive(Clone, Copy, Debug, PartialEq, Eq)]
242enum Rel {
243 Above,
245 Below,
247 Apart,
249 Siblings { at: usize, e: usize, p: usize },
252 Unsure,
256}
257
258fn relation(e: &[Seg], p: &[Seg]) -> Rel {
259 for (i, (a, b)) in e.iter().zip(p).enumerate() {
260 let one_key = a.hash == b.hash && a.key == b.key;
261 if one_key && a.index == b.index {
262 continue;
263 }
264 return match (a.index, b.index) {
265 (Some(x), Some(y)) if x != y => Rel::Siblings { at: i, e: x, p: y },
266 (Some(_), Some(_)) => Rel::Unsure,
267 _ if one_key => Rel::Unsure,
268 _ => Rel::Apart,
269 };
270 }
271 if e.len() <= p.len() {
272 Rel::Above
273 } else {
274 Rel::Below
275 }
276}
277
278fn moves(e_len: usize, set: bool, at: usize, x: usize, y: usize) -> bool {
283 if set { x > y } else { e_len == at + 1 && x < y }
284}
285
286fn may_shift(e: &[Seg]) -> bool {
289 e.last().is_some_and(|seg| seg.index.is_some())
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295 use crate::state::tests::random::{self, Rng};
296 use crate::state::{RunContext, Tuning};
297
298 fn step(rng: &mut Rng, overlay: &mut Overlay, base: DataValue<'_>, model: &mut OwnedDataValue) {
302 let Ok(path) = random::rooted_path(rng, model).parse::<Path>() else {
303 return;
304 };
305 if rng.chance(1, 3) {
306 if path.is_root() || path.get(model).is_none() {
307 return;
308 }
309 path::remove(model, path.segs());
310 overlay.remove(&path);
311 } else {
312 let value = random::value(rng);
313 if path.check_set(&value).is_err() {
314 return;
315 }
316 path.assign(model, value.clone());
317 overlay.set(base, &path, value);
318 }
319 }
320
321 #[test]
322 fn the_overlay_is_its_writes_applied_in_order() {
323 let mut rng = Rng::new(0x5eed_0f0e_71a7);
324 for case in 0..1500 {
325 let owned = random::rooted_tree(&mut rng, 3);
326 let arena = Bump::new();
327 let base = owned.view_in(&arena);
328 let mut overlay = Overlay::default();
329 let mut model = owned.clone();
330 for at in 0..1 + rng.below(6) {
331 step(&mut rng, &mut overlay, base, &mut model);
332 let here = Bump::new();
333 let root = overlay.splice_onto(base, &here);
334 let want = random::exact(&model);
335 assert_eq!(
336 random::exact(&root.to_owned()),
337 want,
338 "case {case} step {at}: the spliced root"
339 );
340 for _ in 0..4 {
342 let Ok(read) = random::rooted_path(&mut rng, &model).parse::<Path>() else {
343 continue;
344 };
345 let got = match overlay.lookup(&read) {
346 Lookup::Clean => read.get(&owned).cloned(),
347 Lookup::Owned(v) => v.cloned(),
348 Lookup::Dirty => splice::get(root, read.segs()).map(|v| v.to_owned()),
349 };
350 assert_eq!(
351 got.as_ref().map(random::exact),
352 read.get(&model).map(random::exact),
353 "case {case} step {at}: a read of {read}"
354 );
355 }
356 }
357 let mut slot = owned.clone();
359 let mut rc = RunContext::new(&mut slot, Tuning::default());
360 if rng.chance(1, 2) {
361 rc.read(|_, _| ());
362 }
363 overlay.apply(&mut rc);
364 rc.finish();
365 assert_eq!(
366 random::exact(&slot),
367 random::exact(&model),
368 "case {case}: applied"
369 );
370 }
371 }
372
373 fn draw(rng: &mut Rng, own: &OwnedDataValue) -> Option<(Path, Option<OwnedDataValue>)> {
378 let path = random::rooted_path(rng, own).parse::<Path>().ok()?;
379 if rng.chance(1, 3) {
380 (!path.is_root() && path.get(own).is_some()).then_some((path, None))
381 } else {
382 let value = random::value(rng);
383 path.check_set(&value)
384 .is_ok()
385 .then_some((path, Some(value)))
386 }
387 }
388
389 fn write(context: &mut OwnedDataValue, path: &Path, value: Option<&OwnedDataValue>) {
392 match value {
393 Some(value) => {
394 path.assign(context, value.clone());
395 }
396 None => {
397 path::remove(context, path.segs());
398 }
399 }
400 }
401
402 #[test]
409 fn overlays_planned_over_one_base_compose_in_order() {
410 let mut rng = Rng::new(0xc0_4405_e0f1);
411 for case in 0..1500 {
412 let owned = random::rooted_tree(&mut rng, 3);
413 let arena = Bump::new();
414 let base = owned.view_in(&arena);
415 let mut sequential = owned.clone();
416 let mut overlays = Vec::new();
417 for _ in 0..2 + rng.below(2) {
418 let mut overlay = Overlay::default();
419 let mut own = owned.clone();
420 for _ in 0..1 + rng.below(5) {
421 let Some((path, value)) = draw(&mut rng, &own) else {
422 continue;
423 };
424 write(&mut own, &path, value.as_ref());
425 write(&mut sequential, &path, value.as_ref());
426 match value {
427 Some(value) => overlay.set(base, &path, value),
428 None => overlay.remove(&path),
429 }
430 }
431 overlays.push(overlay);
432 }
433 let mut slot = owned.clone();
434 let mut rc = RunContext::new(&mut slot, Tuning::default());
435 if rng.chance(1, 2) {
436 rc.read(|_, _| ());
437 }
438 for overlay in overlays {
439 overlay.apply(&mut rc);
440 }
441 rc.finish();
442 let (got, want) = (random::exact(&slot), random::exact(&sequential));
443 assert!(got == want, "case {case}: {}", random::diff(&got, &want));
444 }
445 }
446
447 fn parse(dotted: &str) -> Path {
448 dotted.parse().unwrap()
449 }
450
451 fn dv(v: serde_json::Value) -> OwnedDataValue {
452 OwnedDataValue::from(&v)
453 }
454
455 fn spliced(overlay: &Overlay, base: DataValue<'_>) -> String {
458 let arena = Bump::new();
459 random::exact(&overlay.splice_onto(base, &arena).to_owned())
460 }
461
462 #[test]
463 fn a_key_removed_and_written_again_moves_to_its_objects_end() {
464 let owned = dv(serde_json::json!({"data": {"a": 1, "b": 2, "c": 3}}));
465 let arena = Bump::new();
466 let base = owned.view_in(&arena);
467 let mut overlay = Overlay::default();
468 overlay.remove(&parse("data.a"));
469 overlay.set(base, &parse("data.a"), dv(serde_json::json!(4)));
470 assert_eq!(spliced(&overlay, base), r#"{"data":{"b":2,"c":3,"a":4}}"#);
471 }
472
473 #[test]
474 fn a_new_key_removed_and_written_again_follows_a_later_new_key() {
475 let owned = dv(serde_json::json!({"data": {"a": 1}}));
476 let arena = Bump::new();
477 let base = owned.view_in(&arena);
478 let mut overlay = Overlay::default();
479 overlay.set(base, &parse("data.n"), dv(serde_json::json!(1)));
480 overlay.set(base, &parse("data.m"), dv(serde_json::json!(2)));
481 overlay.remove(&parse("data.n"));
482 overlay.set(base, &parse("data.n"), dv(serde_json::json!(3)));
483 assert_eq!(spliced(&overlay, base), r#"{"data":{"a":1,"m":2,"n":3}}"#);
484 }
485
486 #[test]
487 fn padding_and_a_removed_element_are_read_as_written() {
488 let owned = dv(serde_json::json!({"data": {"list": [1, 2]}}));
489 let arena = Bump::new();
490 let base = owned.view_in(&arena);
491 let mut overlay = Overlay::default();
492 overlay.set(base, &parse("data.list.4"), dv(serde_json::json!(5)));
493 assert_eq!(overlay.lookup(&parse("data.list.3")), Lookup::Dirty);
496 assert_eq!(
497 spliced(&overlay, base),
498 r#"{"data":{"list":[1,2,null,null,5]}}"#
499 );
500 overlay.remove(&parse("data.list.0"));
501 assert_eq!(
502 spliced(&overlay, base),
503 r#"{"data":{"list":[2,null,null,5]}}"#
504 );
505 }
506}