diff --git a/pmacs-protocol/Cargo.toml b/pmacs-protocol/Cargo.toml index bcad954..27adff8 100644 --- a/pmacs-protocol/Cargo.toml +++ b/pmacs-protocol/Cargo.toml @@ -32,13 +32,11 @@ cast_precision_loss = "allow" similar_names = "allow" multiple_crate_versions = "allow" -[features] -# Mirrors the `crdt` feature on the parent `pmacs` crate. When enabled, -# the `InstanceMessage::CrdtOp` / `FrontendEvent::CrdtOp` variants exist -# and the wire-level `CrdtOp` struct is in scope. When disabled, those -# variants are compiled out so v0.1-era binaries built without `crdt` -# match the pre-v1.0 wire surface byte-for-byte. -crdt = [] +# No features — the wire type set is unconditional. `CrdtOp` is +# always compiled (matching the original `pmacs::rope::CrdtOp`'s +# "not `#[cfg]`-gated to avoid feature-flag proliferation through +# every Edit consumer" decision); the parent `pmacs` crate's `crdt` +# feature gates loro and op-application, not wire shape. [dependencies] serde = { workspace = true } diff --git a/pmacs-protocol/src/crdt.rs b/pmacs-protocol/src/crdt.rs new file mode 100644 index 0000000..6f186a7 --- /dev/null +++ b/pmacs-protocol/src/crdt.rs @@ -0,0 +1,44 @@ +//! `CrdtOp` — moved from `pmacs::rope` in session 1 of the `pmacs-gpu` +//! arc. Carried on the `InstanceMessage::CrdtOp` / +//! `FrontendEvent::CrdtOp` wire variants when an attached session +//! negotiated `crdt_replica: true`. +//! +//! The type is unconditional (not `#[cfg]`-gated) — the comment on +//! the original `pmacs::rope::CrdtOp` explained why: "Always present +//! (not `#[cfg]`-gated) to avoid feature-flag proliferation through +//! every Edit consumer." Keeping the same shape here. The `crdt` +//! feature on the parent `pmacs` crate gates loro and the actual +//! application of CRDT ops; the wire-type definition stays compiled +//! unconditionally so consumers (`pmacs-gpu`, debug tools) don't have +//! to mirror the feature flag to handle a wire-level variant they +//! may never see. + +/// T M10.2 Day 3: CRDT-op metadata carried by `Edit` in CRDT mode. +/// +/// Two fields: +/// +/// * `peer_id` — the producing-frontend identity. M10.4's per-frontend +/// undo reads this as the "is this op mine?" filter; saves the +/// consumer from parsing the op bytes to extract identity. +/// * `bytes` — wire-format serialization of the CRDT ops produced by +/// the originating edit, as returned by loro's +/// `ExportMode::updates_owned(pre_version)`. M10.5+ sends these +/// over the wire; receiving frontends import them via loro's +/// `import` to apply on their local CRDT. +/// +/// Constructed by `Buffer::apply_edit` (and `undo` / `redo`) in CRDT +/// mode; rope's edit constructors set `Edit::crdt_op` to `None` and +/// the Buffer wraps after the rope returns. +/// +/// T M10.5: serde derives added so this type can be the payload of +/// `InstanceMessage::CrdtOp` and `FrontendEvent::CrdtOp` on the wire. +/// `bytes` is opaque to the protocol layer — it's loro's incremental- +/// update format; the receiving end's `CrdtState::import_updates` +/// decodes it. +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct CrdtOp { + /// Producing frontend's identity (loro `PeerID`). + pub peer_id: u64, + /// Wire-format op bytes (loro `ExportMode::updates_owned` output). + pub bytes: Vec, +} diff --git a/pmacs-protocol/src/lib.rs b/pmacs-protocol/src/lib.rs index 521526a..45dfd1b 100644 --- a/pmacs-protocol/src/lib.rs +++ b/pmacs-protocol/src/lib.rs @@ -35,12 +35,14 @@ //! directly. pub mod cell; +pub mod crdt; pub mod ids; pub use cell::{ Attachment, Cell, CellCoord, CellSize, Color, DiffSpan, Glyph, Style, UnderlineStyle, }; +pub use crdt::CrdtOp; pub use ids::{BufferId, ByteRange, FrontendId, Position}; -// The `SemanticFrame` family, top-level message envelopes, and the -// feature-gated `CrdtOp` follow in subsequent commits within this PR. +// The `SemanticFrame` family and the top-level message envelopes +// follow in the final commit within this PR. diff --git a/src/rope.rs b/src/rope.rs index 86af642..3081158 100644 --- a/src/rope.rs +++ b/src/rope.rs @@ -330,35 +330,10 @@ pub struct Edit { pub crdt_op: Option>, } -/// T M10.2 Day 3: CRDT-op metadata carried by [`Edit`] in CRDT mode. -/// -/// Two fields: -/// -/// * `peer_id` — the producing-frontend identity. M10.4's per-frontend -/// undo reads this as the "is this op mine?" filter; saves the -/// consumer from parsing the op bytes to extract identity. -/// * `bytes` — wire-format serialization of the CRDT ops produced by -/// the originating edit, as returned by loro's -/// `ExportMode::updates_owned(pre_version)`. M10.5+ sends these -/// over the wire; receiving frontends import them via loro's -/// `import` to apply on their local CRDT. -/// -/// Constructed by `Buffer::apply_edit` (and `undo` / `redo`) in CRDT -/// mode; rope's edit constructors set `Edit::crdt_op` to `None` and -/// the Buffer wraps after the rope returns. -/// -/// T M10.5: serde derives added so this type can be the payload of -/// `InstanceMessage::CrdtOp` and `FrontendEvent::CrdtOp` on the wire. -/// `bytes` is opaque to the protocol layer — it's loro's incremental- -/// update format; the receiving end's `CrdtState::import_updates` -/// decodes it. -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct CrdtOp { - /// Producing frontend's identity (loro `PeerID`). - pub peer_id: u64, - /// Wire-format op bytes (loro `ExportMode::updates_owned` output). - pub bytes: Vec, -} +// `CrdtOp` moved to `pmacs-protocol::crdt` (session 1 of the +// `pmacs-gpu` arc — see `docs/pmacs-gpu-design.md`). Re-exported here +// so existing `crate::rope::CrdtOp` import paths continue to resolve. +pub use pmacs_protocol::CrdtOp; /// A half-open byte range `[start, end)` into a rope. ///