Skip to main content

dotloom_document/
document.rs

1//! The document container.
2
3use std::collections::{BTreeMap, BTreeSet};
4
5use serde::{Deserialize, Serialize, Serializer, ser::SerializeMap};
6use serde_json::Value;
7
8use crate::{
9    Constraint, ConstraintId, DocError, Entity, EntityId, Group, GroupId, Layer, LayerId, Meta, SCHEMA_VERSION,
10    Settings,
11};
12
13/// A Dotloom document: the single editable source of truth (owned by the engine).
14///
15/// Entities are kept in a map keyed by stable ID plus a separate draw order, so
16/// reordering never changes identity. IDs for every object kind come from one
17/// monotonically increasing allocator (`next_id`) and are never reused.
18#[derive(Debug, Clone, PartialEq, Deserialize)]
19#[serde(try_from = "DocumentRepr")]
20pub struct Document {
21    /// Metadata.
22    pub meta: Meta,
23    /// Settings.
24    pub settings: Settings,
25    layers: Vec<Layer>,
26    entities: BTreeMap<EntityId, Entity>,
27    order: Vec<EntityId>,
28    groups: BTreeMap<GroupId, Group>,
29    constraints: BTreeMap<ConstraintId, Constraint>,
30    next_id: u64,
31    /// Unknown top-level fields preserved on save.
32    pub extra: BTreeMap<String, Value>,
33}
34
35#[derive(Deserialize)]
36#[serde(rename_all = "camelCase")]
37struct DocumentRepr {
38    schema: u32,
39    #[serde(default)]
40    meta: Meta,
41    #[serde(default)]
42    settings: Settings,
43    #[serde(default)]
44    layers: Vec<Layer>,
45    #[serde(default)]
46    entities: Vec<Entity>,
47    #[serde(default)]
48    groups: Vec<Group>,
49    #[serde(default)]
50    constraints: Vec<Constraint>,
51    next_id: u64,
52    #[serde(flatten)]
53    extra: BTreeMap<String, Value>,
54}
55
56impl TryFrom<DocumentRepr> for Document {
57    type Error = DocError;
58
59    fn try_from(r: DocumentRepr) -> Result<Self, DocError> {
60        if r.schema != SCHEMA_VERSION {
61            return Err(DocError::Malformed(format!(
62                "schema {} must be migrated before deserialization (current {SCHEMA_VERSION})",
63                r.schema
64            )));
65        }
66        let mut entities = BTreeMap::new();
67        let mut order = Vec::with_capacity(r.entities.len());
68        for e in r.entities {
69            order.push(e.id);
70            if entities.insert(e.id, e).is_some() {
71                return Err(DocError::DuplicateId(order.last().map(ToString::to_string).unwrap_or_default()));
72            }
73        }
74        let mut groups = BTreeMap::new();
75        for g in r.groups {
76            let id = g.id;
77            if groups.insert(id, g).is_some() {
78                return Err(DocError::DuplicateId(id.to_string()));
79            }
80        }
81        let mut constraints = BTreeMap::new();
82        for c in r.constraints {
83            let id = c.id;
84            if constraints.insert(id, c).is_some() {
85                return Err(DocError::DuplicateId(id.to_string()));
86            }
87        }
88        let mut seen_layers = BTreeSet::new();
89        for l in &r.layers {
90            if !seen_layers.insert(l.id) {
91                return Err(DocError::DuplicateId(l.id.to_string()));
92            }
93        }
94        Ok(Self {
95            meta: r.meta,
96            settings: r.settings,
97            layers: r.layers,
98            entities,
99            order,
100            groups,
101            constraints,
102            next_id: r.next_id,
103            extra: r.extra,
104        })
105    }
106}
107
108struct OrderedEntities<'a>(&'a Document);
109
110impl Serialize for OrderedEntities<'_> {
111    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
112        s.collect_seq(self.0.order.iter().filter_map(|id| self.0.entities.get(id)))
113    }
114}
115
116impl Serialize for Document {
117    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
118        let mut m = s.serialize_map(Some(8 + self.extra.len()))?;
119        m.serialize_entry("schema", &SCHEMA_VERSION)?;
120        m.serialize_entry("meta", &self.meta)?;
121        m.serialize_entry("settings", &self.settings)?;
122        m.serialize_entry("layers", &self.layers)?;
123        m.serialize_entry("entities", &OrderedEntities(self))?;
124        m.serialize_entry("groups", &self.groups.values().collect::<Vec<_>>())?;
125        m.serialize_entry("constraints", &self.constraints.values().collect::<Vec<_>>())?;
126        m.serialize_entry("nextId", &self.next_id)?;
127        // Unknown top-level fields from newer producers are written back unchanged.
128        for (k, v) in &self.extra {
129            m.serialize_entry(k, v)?;
130        }
131        m.end()
132    }
133}
134
135impl Default for Document {
136    fn default() -> Self {
137        Self::new()
138    }
139}
140
141/// What references an entity.
142#[derive(Debug, Clone, Default, PartialEq, Eq)]
143pub struct Dependents {
144    /// Constraints that reference the entity.
145    pub constraints: Vec<ConstraintId>,
146    /// Entities whose properties reference the entity.
147    pub entities: Vec<EntityId>,
148    /// Groups that contain the entity.
149    pub groups: Vec<GroupId>,
150}
151
152impl Document {
153    /// Empty document with one default layer.
154    #[must_use]
155    pub fn new() -> Self {
156        Self {
157            meta: Meta::default(),
158            settings: Settings::default(),
159            layers: vec![Layer::new(LayerId(1), "Layer 1")],
160            entities: BTreeMap::new(),
161            order: Vec::new(),
162            groups: BTreeMap::new(),
163            constraints: BTreeMap::new(),
164            next_id: 2,
165            extra: BTreeMap::new(),
166        }
167    }
168
169    /// Allocate a fresh ID (shared by all object kinds).
170    pub fn alloc_id(&mut self) -> u64 {
171        let id = self.next_id;
172        self.next_id = self.next_id.saturating_add(1);
173        id
174    }
175
176    /// Next ID that will be allocated.
177    #[must_use]
178    pub const fn next_id(&self) -> u64 {
179        self.next_id
180    }
181
182    /// Raise the allocator so that `id` is never handed out again.
183    pub fn reserve_id(&mut self, id: u64) {
184        if id >= self.next_id {
185            self.next_id = id.saturating_add(1);
186        }
187    }
188
189    // --- entities -------------------------------------------------------------
190
191    /// Number of entities.
192    #[must_use]
193    pub fn entity_count(&self) -> usize {
194        self.entities.len()
195    }
196
197    /// Entity by ID.
198    #[must_use]
199    pub fn entity(&self, id: EntityId) -> Option<&Entity> {
200        self.entities.get(&id)
201    }
202
203    /// Mutable entity by ID (engine use; callers must re-validate).
204    pub fn entity_mut(&mut self, id: EntityId) -> Option<&mut Entity> {
205        self.entities.get_mut(&id)
206    }
207
208    /// Entities in draw order.
209    pub fn entities(&self) -> impl Iterator<Item = &Entity> {
210        self.order.iter().filter_map(|id| self.entities.get(id))
211    }
212
213    /// Draw order.
214    #[must_use]
215    pub fn order(&self) -> &[EntityId] {
216        &self.order
217    }
218
219    /// Insert an entity at the top of the draw order (or replace one with the same
220    /// ID in place).
221    pub fn insert_entity(&mut self, e: Entity) {
222        self.reserve_id(e.id.0);
223        if !self.entities.contains_key(&e.id) {
224            self.order.push(e.id);
225        }
226        self.entities.insert(e.id, e);
227    }
228
229    /// Insert an entity at a draw-order index.
230    pub fn insert_entity_at(&mut self, e: Entity, index: usize) {
231        self.reserve_id(e.id.0);
232        let id = e.id;
233        if self.entities.insert(id, e).is_none() {
234            let i = index.min(self.order.len());
235            self.order.insert(i, id);
236        }
237    }
238
239    /// Remove an entity (does not touch constraints or references; see
240    /// [`Document::dependents`]). Returns the entity and its draw-order index.
241    pub fn remove_entity(&mut self, id: EntityId) -> Option<(Entity, usize)> {
242        let e = self.entities.remove(&id)?;
243        let idx = self.order.iter().position(|x| *x == id).unwrap_or(self.order.len());
244        if idx < self.order.len() {
245            self.order.remove(idx);
246        }
247        for g in self.groups.values_mut() {
248            g.members.retain(|m| *m != id);
249        }
250        Some((e, idx))
251    }
252
253    /// Move an entity to a draw-order index. IDs never change.
254    pub fn reorder(&mut self, id: EntityId, index: usize) -> Result<(), DocError> {
255        let pos = self.order.iter().position(|x| *x == id).ok_or(DocError::UnknownEntity(id))?;
256        self.order.remove(pos);
257        let i = index.min(self.order.len());
258        self.order.insert(i, id);
259        Ok(())
260    }
261
262    /// Draw-order index of an entity.
263    #[must_use]
264    pub fn order_index(&self, id: EntityId) -> Option<usize> {
265        self.order.iter().position(|x| *x == id)
266    }
267
268    // --- layers ---------------------------------------------------------------
269
270    /// Layers in display order.
271    #[must_use]
272    pub fn layers(&self) -> &[Layer] {
273        &self.layers
274    }
275
276    /// Layer by ID.
277    #[must_use]
278    pub fn layer(&self, id: LayerId) -> Option<&Layer> {
279        self.layers.iter().find(|l| l.id == id)
280    }
281
282    /// Mutable layer by ID.
283    pub fn layer_mut(&mut self, id: LayerId) -> Option<&mut Layer> {
284        self.layers.iter_mut().find(|l| l.id == id)
285    }
286
287    /// Insert or replace a layer (appended when new).
288    pub fn upsert_layer(&mut self, l: Layer) {
289        self.reserve_id(l.id.0);
290        if let Some(slot) = self.layers.iter_mut().find(|x| x.id == l.id) {
291            *slot = l;
292        } else {
293            self.layers.push(l);
294        }
295    }
296
297    /// Replace the whole layer list (used by undo/redo).
298    pub fn set_layers(&mut self, layers: Vec<Layer>) {
299        for l in &layers {
300            self.reserve_id(l.id.0);
301        }
302        self.layers = layers;
303    }
304
305    /// Insert a layer at an index.
306    pub fn insert_layer_at(&mut self, l: Layer, index: usize) {
307        self.reserve_id(l.id.0);
308        let i = index.min(self.layers.len());
309        self.layers.insert(i, l);
310    }
311
312    /// Remove a layer. Fails while entities still use it.
313    pub fn remove_layer(&mut self, id: LayerId) -> Result<(Layer, usize), DocError> {
314        if self.entities.values().any(|e| e.layer == id) {
315            return Err(DocError::InvalidValue(format!("layer {id} is not empty")));
316        }
317        let pos = self.layers.iter().position(|l| l.id == id).ok_or(DocError::UnknownLayer(id))?;
318        Ok((self.layers.remove(pos), pos))
319    }
320
321    // --- groups ---------------------------------------------------------------
322
323    /// Groups.
324    pub fn groups(&self) -> impl Iterator<Item = &Group> {
325        self.groups.values()
326    }
327
328    /// Group by ID.
329    #[must_use]
330    pub fn group(&self, id: GroupId) -> Option<&Group> {
331        self.groups.get(&id)
332    }
333
334    /// Insert or replace a group.
335    pub fn upsert_group(&mut self, g: Group) {
336        self.reserve_id(g.id.0);
337        self.groups.insert(g.id, g);
338    }
339
340    /// Remove a group (members stay in the document).
341    pub fn remove_group(&mut self, id: GroupId) -> Option<Group> {
342        let g = self.groups.remove(&id)?;
343        for other in self.groups.values_mut() {
344            other.children.retain(|c| *c != id);
345        }
346        Some(g)
347    }
348
349    /// Group that directly contains an entity.
350    #[must_use]
351    pub fn group_of(&self, id: EntityId) -> Option<GroupId> {
352        self.groups.values().find(|g| g.members.contains(&id)).map(|g| g.id)
353    }
354
355    // --- constraints ----------------------------------------------------------
356
357    /// Constraints.
358    pub fn constraints(&self) -> impl Iterator<Item = &Constraint> {
359        self.constraints.values()
360    }
361
362    /// Number of constraints.
363    #[must_use]
364    pub fn constraint_count(&self) -> usize {
365        self.constraints.len()
366    }
367
368    /// Constraint by ID.
369    #[must_use]
370    pub fn constraint(&self, id: ConstraintId) -> Option<&Constraint> {
371        self.constraints.get(&id)
372    }
373
374    /// Insert or replace a constraint.
375    pub fn upsert_constraint(&mut self, c: Constraint) {
376        self.reserve_id(c.id.0);
377        self.constraints.insert(c.id, c);
378    }
379
380    /// Remove a constraint.
381    pub fn remove_constraint(&mut self, id: ConstraintId) -> Option<Constraint> {
382        self.constraints.remove(&id)
383    }
384
385    // --- queries --------------------------------------------------------------
386
387    /// Everything that references `id` (O(n); the engine keeps an index).
388    #[must_use]
389    pub fn dependents(&self, id: EntityId) -> Dependents {
390        Dependents {
391            constraints: self
392                .constraints
393                .values()
394                .filter(|c| c.rule.entities().contains(&id) || c.owner == Some(id))
395                .map(|c| c.id)
396                .collect(),
397            entities: self
398                .entities
399                .values()
400                .filter(|e| e.id != id && e.referenced_entities().any(|r| r == id))
401                .map(|e| e.id)
402                .collect(),
403            groups: self.groups.values().filter(|g| g.members.contains(&id)).map(|g| g.id).collect(),
404        }
405    }
406
407    /// Whether any ID of any kind equals `raw`.
408    #[must_use]
409    pub fn id_in_use(&self, raw: u64) -> bool {
410        self.entities.contains_key(&EntityId(raw))
411            || self.constraints.contains_key(&ConstraintId(raw))
412            || self.groups.contains_key(&GroupId(raw))
413            || self.layers.iter().any(|l| l.id.0 == raw)
414    }
415}