PdfEx.OT (pdf_ex v0.1.0)

Copy Markdown View Source

Operational transformation for collaborative editing (Tier 3, T3.1).

Ops address glyphs by opaque seq-based UID, which a text edit renumbers. OT works instead in a stable address space Addr{contents_ref, op_index, glyph_idx}: op_index never shifts (edits preserve the show-op count) and glyph_idx shifts only within a run that lost an earlier glyph. So different-run edits commute and the transform only handles same-run cases.

Summary

Functions

Resolves a glyph uid to its stable Addr (immune to the seq-based UID renumbering a text edit causes).

Resolves a Pending back to a concrete PdfEx.Op against the current document.

Builds a Pending op in stable-address space from op, tagged with the base_version it was built against.

Resolves a stable Addr back to the current glyph uid in doc.

Transforms b to apply after the already-applied concurrent a (same base). Returns :noop when b's intent is subsumed. See the spec's locked matrix.

Folds transform/2 over the applied concurrent ops; short-circuits to :noop if any transform drops pending.

Functions

address(doc, uid)

@spec address(PdfEx.Document.t(), binary()) ::
  {:ok, PdfEx.OT.Addr.t()} | {:error, PdfEx.Error.t()}

Resolves a glyph uid to its stable Addr (immune to the seq-based UID renumbering a text edit causes).

materialize(doc, p)

@spec materialize(PdfEx.Document.t(), PdfEx.OT.Pending.t()) ::
  {:ok, PdfEx.Op.t()} | {:error, PdfEx.Error.t()}

Resolves a Pending back to a concrete PdfEx.Op against the current document.

pending(doc, op, base_version)

@spec pending(PdfEx.Document.t(), PdfEx.Op.t(), non_neg_integer()) ::
  {:ok, PdfEx.OT.Pending.t()} | {:error, PdfEx.Error.t()}

Builds a Pending op in stable-address space from op, tagged with the base_version it was built against.

resolve(doc, addr)

@spec resolve(PdfEx.Document.t(), PdfEx.OT.Addr.t()) ::
  {:ok, binary()} | {:error, PdfEx.Error.t()}

Resolves a stable Addr back to the current glyph uid in doc.

transform(b, a)

@spec transform(PdfEx.OT.Pending.t(), PdfEx.OT.Pending.t()) ::
  {:ok, PdfEx.OT.Pending.t()} | :noop

Transforms b to apply after the already-applied concurrent a (same base). Returns :noop when b's intent is subsumed. See the spec's locked matrix.

transform_against(pending, applied)

@spec transform_against(PdfEx.OT.Pending.t(), [PdfEx.OT.Pending.t()]) ::
  {:ok, PdfEx.OT.Pending.t()} | :noop

Folds transform/2 over the applied concurrent ops; short-circuits to :noop if any transform drops pending.