@@ -12,6 +12,8 @@ use crate::error::{CrdtError, Result};
1212use crate :: row_lookup:: RowLookup ;
1313use crate :: validator:: bitemporal:: { VALID_UNTIL , VALID_UNTIL_OPEN } ;
1414
15+ use super :: document_cell:: DocumentCell ;
16+
1517/// A row is live when its `_ts_valid_until` field is absent, null, or the
1618/// open sentinel (`i64::MAX`). Rows with any finite `_ts_valid_until` are
1719/// treated as superseded, independent of wall-clock time — the write path
@@ -41,7 +43,7 @@ fn key_is_container(row: &LoroMap, key: &str) -> bool {
4143pub struct CrdtState {
4244 /// Kept private to this state module so callers cannot clone or share a
4345 /// raw Loro handle around the preview's pending-check/fork critical section.
44- pub ( in crate :: state) doc : LoroDoc ,
46+ pub ( in crate :: state) doc : DocumentCell ,
4547 pub ( super ) peer_id : u64 ,
4648 /// Loro auto-commit state must stay single-owner. This makes accidental
4749 /// cross-thread sharing of a `CrdtState` a compile error.
@@ -51,16 +53,39 @@ pub struct CrdtState {
5153impl CrdtState {
5254 /// Create a new empty state for the given peer.
5355 pub fn new ( peer_id : u64 ) -> Result < Self > {
54- let doc = LoroDoc :: new ( ) ;
55- doc. set_peer_id ( peer_id)
56- . map_err ( |e| CrdtError :: Loro ( format ! ( "failed to set peer_id {peer_id}: {e}" ) ) ) ?;
5756 Ok ( Self {
58- doc,
57+ doc : DocumentCell :: new ( Self :: new_doc ( peer_id ) ? ) ,
5958 peer_id,
6059 _single_owner : PhantomData ,
6160 } )
6261 }
6362
63+ /// Load a state from an encoded document this process produced itself — a
64+ /// snapshot read back from durable storage, or a pre-image exported moments
65+ /// earlier for transaction rollback.
66+ ///
67+ /// Pairs `new` with [`CrdtState::import_local`], because those two steps
68+ /// belong together: a caller that assembles them by hand has to know that
69+ /// its own bytes must not go through the peer ceilings, and a caller that
70+ /// gets that wrong writes a document it can no longer open. See
71+ /// `import_local` for why the ceilings do not apply here.
72+ pub fn from_local_snapshot ( peer_id : u64 , snapshot : & [ u8 ] ) -> Result < Self > {
73+ let state = Self :: new ( peer_id) ?;
74+ state. import_local ( snapshot) ?;
75+ Ok ( state)
76+ }
77+
78+ /// A fresh Loro document bound to `peer_id`.
79+ ///
80+ /// Shared by `new` and by the compaction paths, which need the same
81+ /// peer-bound document before loading a shallow snapshot into it.
82+ pub ( in crate :: state) fn new_doc ( peer_id : u64 ) -> Result < LoroDoc > {
83+ let doc = LoroDoc :: new ( ) ;
84+ doc. set_peer_id ( peer_id)
85+ . map_err ( |e| CrdtError :: Loro ( format ! ( "failed to set peer_id {peer_id}: {e}" ) ) ) ?;
86+ Ok ( doc)
87+ }
88+
6489 /// Fetch a row's existing `LoroMap` container, or create one if absent.
6590 /// Shared by `upsert` and `set_fields` — both need the same row handle
6691 /// before diverging on prune-vs-preserve semantics.
@@ -284,9 +309,13 @@ impl CrdtState {
284309 }
285310
286311 /// List all collection names (top-level map keys in the Loro doc).
312+ ///
313+ /// Reads the shallow value: the keys are at the top level, and
314+ /// `get_deep_value` would materialise every row and field of every
315+ /// collection to reach them — O(document) for a list whose size is the
316+ /// number of collections. Name resolution calls this per query.
287317 pub fn collection_names ( & self ) -> Vec < String > {
288- let root = self . doc . get_deep_value ( ) ;
289- match root {
318+ match self . doc . get_value ( ) {
290319 LoroValue :: Map ( map) => map. keys ( ) . map ( |k| k. to_string ( ) ) . collect ( ) ,
291320 _ => Vec :: new ( ) ,
292321 }
0 commit comments