Skip to main content

lattice_host/diff/
resolver.rs

1//! Host-owned `BufferRegistry`-backed impls of the diff subsystem's
2//! resolver seams (DX.6, coupling C6).
3//!
4//! The diff subsystem (now `lattice-diff`) depends only on the
5//! abstractions [`BufferTextProvider`] / [`DocumentBufferResolver`].
6//! Their production impls bridge to [`crate::buffer_registry::BufferRegistry`]
7//! — a host type — so they CANNOT live in `lattice-diff`; they stay here.
8//! Re-exported under `crate::diff::subsystem::*` (see `diff/mod.rs`) so
9//! every existing call site reads
10//! `crate::diff::subsystem::BufferRegistry{TextProvider,DocumentResolver}`
11//! exactly as before the move.
12
13use lattice_core::BufferId;
14use lattice_protocol::ids::DocumentId;
15use ropey::Rope;
16
17use lattice_diff::subsystem::{BufferTextProvider, DocumentBufferResolver};
18
19/// D.3.a (2026-05-29): the production [`BufferTextProvider`]
20/// impl. Bridges the trait to the host's [`crate::buffer_registry::BufferRegistry`]:
21/// `buffer_rope(id)` walks `BufferRegistry::document_handle(id)
22/// -> RopeDocumentHandle::snapshot() -> snapshot.buffer.to_rope()`.
23///
24/// All operations are RCU-style reads (registry mutex held only
25/// long enough to clone an `Arc<DocumentSnapshot>`; rope clone
26/// is `Arc`-share of chunks). Safe to call from
27/// `spawn_blocking`. Returns `None` for non-document buffers
28/// or for ids the registry has dropped — the diff subsystem's
29/// `BufferSource` impl maps `None` to an empty rope per its
30/// documented contract.
31#[derive(Clone, Debug)]
32pub struct BufferRegistryTextProvider {
33    registry: crate::buffer_registry::BufferRegistry,
34}
35
36impl BufferRegistryTextProvider {
37    pub fn new(registry: crate::buffer_registry::BufferRegistry) -> Self {
38        Self { registry }
39    }
40}
41
42impl BufferTextProvider for BufferRegistryTextProvider {
43    fn buffer_rope(&self, id: BufferId) -> Option<Rope> {
44        let handle = self.registry.document_handle(id)?;
45        Some(handle.snapshot().buffer.to_rope())
46    }
47}
48
49/// D.3.a.1 (2026-05-29): production [`DocumentBufferResolver`]
50/// impl. Bridges `DocumentId` → `BufferId` via
51/// `BufferRegistry::buffer_id_for_document`. Stored on `Editor`
52/// for the editor's lifetime and handed to
53/// `DiffSubsystem::bind` so the drainer task can translate
54/// bus events.
55#[derive(Clone, Debug)]
56pub struct BufferRegistryDocumentResolver {
57    registry: crate::buffer_registry::BufferRegistry,
58}
59
60impl BufferRegistryDocumentResolver {
61    pub fn new(registry: crate::buffer_registry::BufferRegistry) -> Self {
62        Self { registry }
63    }
64}
65
66impl DocumentBufferResolver for BufferRegistryDocumentResolver {
67    fn buffer_id_for(&self, document_id: DocumentId) -> Option<BufferId> {
68        self.registry.buffer_id_for_document(document_id)
69    }
70}