common/snapshot.rs
1// Generated by Qleany v1.11.0 from snapshot.tera
2
3use crate::types::EntityId;
4use serde::{Deserialize, Serialize};
5use std::any::Any;
6
7/// Snapshot of an entity tree for undo.
8///
9/// Capture is O(1): `store_snapshot` is a whole-store `im::HashMap` clone (structural
10/// sharing). Restore is *scoped*: `root_ids` records the subtree roots passed to
11/// `snapshot(ids)`, and the per-entity `Repository::restore` walks that subtree (in both
12/// the snapshot and the live store) and reconciles only it, leaving other trunks untouched.
13#[derive(Debug, Clone, Default, Serialize, Deserialize)]
14pub struct EntityTreeSnapshot {
15 /// Whole-store snapshot captured at `snapshot(ids)` time (O(1) `im` clone).
16 #[serde(skip)]
17 pub store_snapshot: Option<StoreSnapshot>,
18 /// The subtree roots (the `ids` passed to `snapshot`). Restore is scoped to these.
19 #[serde(default)]
20 pub root_ids: Vec<EntityId>,
21}
22
23// ─────────────────────────────────────────────────────────────────────────────
24// Store-level snapshot (type-erased so snapshot.rs doesn't depend on HashMapStore)
25// ─────────────────────────────────────────────────────────────────────────────
26
27/// Trait for type-erased store snapshots.
28pub trait StoreSnapshotTrait: std::fmt::Debug + Send + Sync {
29 fn clone_box(&self) -> Box<dyn StoreSnapshotTrait>;
30 fn as_any(&self) -> &dyn Any;
31}
32
33impl Clone for Box<dyn StoreSnapshotTrait> {
34 fn clone(&self) -> Self {
35 self.clone_box()
36 }
37}
38
39/// Type-erased store snapshot for undo fast path.
40#[derive(Debug, Clone)]
41pub struct StoreSnapshot {
42 inner: Box<dyn StoreSnapshotTrait>,
43}
44
45impl StoreSnapshot {
46 pub fn new<T: StoreSnapshotTrait + 'static>(inner: T) -> Self {
47 Self {
48 inner: Box::new(inner),
49 }
50 }
51
52 pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
53 self.inner.as_any().downcast_ref()
54 }
55}