Put vector clock serialization logic alongside other serialization logic

Max Brunsfeld and Nathan Sobo created

This way, the `clock` crate doesn't depend on the `rpc` crate.

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

crates/clock/Cargo.toml           |  1 
crates/clock/src/clock.rs         | 31 ----------------------
crates/language/src/proto.rs      | 45 ++++++++++++++++++++++++--------
crates/project/src/lsp_command.rs | 26 +++++++++---------
crates/project/src/project.rs     | 26 +++++++++---------
crates/project/src/worktree.rs    | 15 ++++++----
6 files changed, 68 insertions(+), 76 deletions(-)

Detailed changes

crates/clock/Cargo.toml 🔗

@@ -9,4 +9,3 @@ doctest = false
 
 [dependencies]
 smallvec = { version = "1.6", features = ["union"] }
-rpc = { path = "../rpc" }

crates/clock/src/clock.rs 🔗

@@ -69,37 +69,6 @@ impl<'a> AddAssign<&'a Local> for Local {
 #[derive(Clone, Default, Hash, Eq, PartialEq)]
 pub struct Global(SmallVec<[u32; 8]>);
 
-impl From<Vec<rpc::proto::VectorClockEntry>> for Global {
-    fn from(message: Vec<rpc::proto::VectorClockEntry>) -> Self {
-        let mut version = Self::new();
-        for entry in message {
-            version.observe(Local {
-                replica_id: entry.replica_id as ReplicaId,
-                value: entry.timestamp,
-            });
-        }
-        version
-    }
-}
-
-impl<'a> From<&'a Global> for Vec<rpc::proto::VectorClockEntry> {
-    fn from(version: &'a Global) -> Self {
-        version
-            .iter()
-            .map(|entry| rpc::proto::VectorClockEntry {
-                replica_id: entry.replica_id as u32,
-                timestamp: entry.value,
-            })
-            .collect()
-    }
-}
-
-impl From<Global> for Vec<rpc::proto::VectorClockEntry> {
-    fn from(version: Global) -> Self {
-        (&version).into()
-    }
-}
-
 impl Global {
     pub fn new() -> Self {
         Self::default()

crates/language/src/proto.rs 🔗

@@ -25,13 +25,13 @@ pub fn serialize_operation(operation: &Operation) -> proto::Operation {
                 replica_id: undo.id.replica_id as u32,
                 local_timestamp: undo.id.value,
                 lamport_timestamp: lamport_timestamp.value,
-                version: From::from(&undo.version),
+                version: serialize_version(&undo.version),
                 transaction_ranges: undo
                     .transaction_ranges
                     .iter()
                     .map(serialize_range)
                     .collect(),
-                transaction_version: From::from(&undo.transaction_version),
+                transaction_version: serialize_version(&undo.transaction_version),
                 counts: undo
                     .counts
                     .iter()
@@ -77,7 +77,7 @@ pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::
         replica_id: operation.timestamp.replica_id as u32,
         local_timestamp: operation.timestamp.local,
         lamport_timestamp: operation.timestamp.lamport,
-        version: From::from(&operation.version),
+        version: serialize_version(&operation.version),
         ranges: operation.ranges.iter().map(serialize_range).collect(),
         new_text: operation.new_text.clone(),
     }
@@ -116,7 +116,7 @@ pub fn serialize_buffer_fragment(fragment: &text::Fragment) -> proto::BufferFrag
                 timestamp: clock.value,
             })
             .collect(),
-        max_undos: From::from(&fragment.max_undos),
+        max_undos: serialize_version(&fragment.max_undos),
     }
 }
 
@@ -188,7 +188,7 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
                         replica_id: undo.replica_id as ReplicaId,
                         value: undo.local_timestamp,
                     },
-                    version: undo.version.into(),
+                    version: deserialize_version(undo.version),
                     counts: undo
                         .counts
                         .into_iter()
@@ -207,7 +207,7 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
                         .into_iter()
                         .map(deserialize_range)
                         .collect(),
-                    transaction_version: undo.transaction_version.into(),
+                    transaction_version: deserialize_version(undo.transaction_version),
                 },
             }),
             proto::operation::Variant::UpdateSelections(message) => {
@@ -260,7 +260,7 @@ pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation
             local: edit.local_timestamp,
             lamport: edit.lamport_timestamp,
         },
-        version: edit.version.into(),
+        version: deserialize_version(edit.version),
         ranges: edit.ranges.into_iter().map(deserialize_range).collect(),
         new_text: edit.new_text,
     }
@@ -309,7 +309,7 @@ pub fn deserialize_buffer_fragment(
             replica_id: entry.replica_id as ReplicaId,
             value: entry.timestamp,
         })),
-        max_undos: From::from(message.max_undos),
+        max_undos: deserialize_version(message.max_undos),
     }
 }
 
@@ -472,8 +472,8 @@ pub fn serialize_transaction(transaction: &Transaction) -> proto::Transaction {
             .copied()
             .map(serialize_local_timestamp)
             .collect(),
-        start: (&transaction.start).into(),
-        end: (&transaction.end).into(),
+        start: serialize_version(&transaction.start),
+        end: serialize_version(&transaction.end),
         ranges: transaction.ranges.iter().map(serialize_range).collect(),
     }
 }
@@ -490,8 +490,8 @@ pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transa
             .into_iter()
             .map(deserialize_local_timestamp)
             .collect(),
-        start: transaction.start.into(),
-        end: transaction.end.into(),
+        start: deserialize_version(transaction.start.into()),
+        end: deserialize_version(transaction.end),
         ranges: transaction
             .ranges
             .into_iter()
@@ -524,3 +524,24 @@ pub fn serialize_range(range: &Range<FullOffset>) -> proto::Range {
 pub fn deserialize_range(range: proto::Range) -> Range<FullOffset> {
     FullOffset(range.start as usize)..FullOffset(range.end as usize)
 }
+
+pub fn deserialize_version(message: Vec<proto::VectorClockEntry>) -> clock::Global {
+    let mut version = clock::Global::new();
+    for entry in message {
+        version.observe(clock::Local {
+            replica_id: entry.replica_id as ReplicaId,
+            value: entry.timestamp,
+        });
+    }
+    version
+}
+
+pub fn serialize_version(version: &clock::Global) -> Vec<proto::VectorClockEntry> {
+    version
+        .iter()
+        .map(|entry| proto::VectorClockEntry {
+            replica_id: entry.replica_id as u32,
+            timestamp: entry.value,
+        })
+        .collect()
+}

crates/project/src/lsp_command.rs 🔗

@@ -5,7 +5,7 @@ use client::{proto, PeerId};
 use gpui::{AppContext, AsyncAppContext, ModelHandle};
 use language::{
     point_from_lsp,
-    proto::{deserialize_anchor, serialize_anchor},
+    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
     range_from_lsp, Anchor, Bias, Buffer, PointUtf16, ToLspPosition, ToPointUtf16,
 };
 use lsp::{DocumentHighlightKind, ServerCapabilities};
@@ -126,7 +126,7 @@ impl LspCommand for PrepareRename {
             position: Some(language::proto::serialize_anchor(
                 &buffer.anchor_before(self.position),
             )),
-            version: (&buffer.version()).into(),
+            version: serialize_version(&buffer.version()),
         }
     }
 
@@ -142,7 +142,7 @@ impl LspCommand for PrepareRename {
             .ok_or_else(|| anyhow!("invalid position"))?;
         buffer
             .update(&mut cx, |buffer, _| {
-                buffer.wait_for_version(message.version.into())
+                buffer.wait_for_version(deserialize_version(message.version))
             })
             .await;
 
@@ -166,7 +166,7 @@ impl LspCommand for PrepareRename {
             end: range
                 .as_ref()
                 .map(|range| language::proto::serialize_anchor(&range.end)),
-            version: buffer_version.into(),
+            version: serialize_version(buffer_version),
         }
     }
 
@@ -180,7 +180,7 @@ impl LspCommand for PrepareRename {
         if message.can_rename {
             buffer
                 .update(&mut cx, |buffer, _| {
-                    buffer.wait_for_version(message.version.into())
+                    buffer.wait_for_version(deserialize_version(message.version))
                 })
                 .await;
             let start = message.start.and_then(deserialize_anchor);
@@ -255,7 +255,7 @@ impl LspCommand for PerformRename {
                 &buffer.anchor_before(self.position),
             )),
             new_name: self.new_name.clone(),
-            version: (&buffer.version()).into(),
+            version: serialize_version(&buffer.version()),
         }
     }
 
@@ -271,7 +271,7 @@ impl LspCommand for PerformRename {
             .ok_or_else(|| anyhow!("invalid position"))?;
         buffer
             .update(&mut cx, |buffer, _| {
-                buffer.wait_for_version(message.version.into())
+                buffer.wait_for_version(deserialize_version(message.version))
             })
             .await;
         Ok(Self {
@@ -407,7 +407,7 @@ impl LspCommand for GetDefinition {
             position: Some(language::proto::serialize_anchor(
                 &buffer.anchor_before(self.position),
             )),
-            version: (&buffer.version()).into(),
+            version: serialize_version(&buffer.version()),
         }
     }
 
@@ -423,7 +423,7 @@ impl LspCommand for GetDefinition {
             .ok_or_else(|| anyhow!("invalid position"))?;
         buffer
             .update(&mut cx, |buffer, _| {
-                buffer.wait_for_version(message.version.into())
+                buffer.wait_for_version(deserialize_version(message.version))
             })
             .await;
         Ok(Self {
@@ -566,7 +566,7 @@ impl LspCommand for GetReferences {
             position: Some(language::proto::serialize_anchor(
                 &buffer.anchor_before(self.position),
             )),
-            version: (&buffer.version()).into(),
+            version: serialize_version(&buffer.version()),
         }
     }
 
@@ -582,7 +582,7 @@ impl LspCommand for GetReferences {
             .ok_or_else(|| anyhow!("invalid position"))?;
         buffer
             .update(&mut cx, |buffer, _| {
-                buffer.wait_for_version(message.version.into())
+                buffer.wait_for_version(deserialize_version(message.version))
             })
             .await;
         Ok(Self {
@@ -706,7 +706,7 @@ impl LspCommand for GetDocumentHighlights {
             position: Some(language::proto::serialize_anchor(
                 &buffer.anchor_before(self.position),
             )),
-            version: (&buffer.version()).into(),
+            version: serialize_version(&buffer.version()),
         }
     }
 
@@ -722,7 +722,7 @@ impl LspCommand for GetDocumentHighlights {
             .ok_or_else(|| anyhow!("invalid position"))?;
         buffer
             .update(&mut cx, |buffer, _| {
-                buffer.wait_for_version(message.version.into())
+                buffer.wait_for_version(deserialize_version(message.version))
             })
             .await;
         Ok(Self {

crates/project/src/project.rs 🔗

@@ -15,7 +15,7 @@ use gpui::{
     UpgradeModelHandle, WeakModelHandle,
 };
 use language::{
-    proto::{deserialize_anchor, serialize_anchor},
+    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
     range_from_lsp, Anchor, AnchorRangeExt, Bias, Buffer, CodeAction, CodeLabel, Completion,
     Diagnostic, DiagnosticEntry, File as _, Language, LanguageRegistry, Operation, PointUtf16,
     ToLspPosition, ToOffset, ToPointUtf16, Transaction,
@@ -1713,14 +1713,14 @@ impl Project {
                 project_id,
                 buffer_id,
                 position: Some(language::proto::serialize_anchor(&anchor)),
-                version: (&source_buffer.version()).into(),
+                version: serialize_version(&source_buffer.version()),
             };
             cx.spawn_weak(|_, mut cx| async move {
                 let response = rpc.request(message).await?;
 
                 source_buffer_handle
                     .update(&mut cx, |buffer, _| {
-                        buffer.wait_for_version(response.version.into())
+                        buffer.wait_for_version(deserialize_version(response.version))
                     })
                     .await;
 
@@ -1910,13 +1910,13 @@ impl Project {
                         buffer_id,
                         start: Some(language::proto::serialize_anchor(&range.start)),
                         end: Some(language::proto::serialize_anchor(&range.end)),
-                        version: (&version).into(),
+                        version: serialize_version(&version),
                     })
                     .await?;
 
                 buffer_handle
                     .update(&mut cx, |buffer, _| {
-                        buffer.wait_for_version(response.version.into())
+                        buffer.wait_for_version(deserialize_version(response.version))
                     })
                     .await;
 
@@ -2915,7 +2915,7 @@ impl Project {
         mut cx: AsyncAppContext,
     ) -> Result<proto::BufferSaved> {
         let buffer_id = envelope.payload.buffer_id;
-        let requested_version = envelope.payload.version.try_into()?;
+        let requested_version = deserialize_version(envelope.payload.version);
 
         let (project_id, buffer) = this.update(&mut cx, |this, cx| {
             let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
@@ -2936,7 +2936,7 @@ impl Project {
         Ok(proto::BufferSaved {
             project_id,
             buffer_id,
-            version: (&saved_version).into(),
+            version: serialize_version(&saved_version),
             mtime: Some(mtime.into()),
         })
     }
@@ -2981,7 +2981,7 @@ impl Project {
             .position
             .and_then(language::proto::deserialize_anchor)
             .ok_or_else(|| anyhow!("invalid position"))?;
-        let version = clock::Global::from(envelope.payload.version);
+        let version = deserialize_version(envelope.payload.version);
         let buffer = this.read_with(&cx, |this, cx| {
             this.opened_buffers
                 .get(&envelope.payload.buffer_id)
@@ -3001,7 +3001,7 @@ impl Project {
                 .iter()
                 .map(language::proto::serialize_completion)
                 .collect(),
-            version: (&version).into(),
+            version: serialize_version(&version),
         })
     }
 
@@ -3062,7 +3062,7 @@ impl Project {
         })?;
         buffer
             .update(&mut cx, |buffer, _| {
-                buffer.wait_for_version(envelope.payload.version.into())
+                buffer.wait_for_version(deserialize_version(envelope.payload.version))
             })
             .await;
 
@@ -3077,7 +3077,7 @@ impl Project {
                 .iter()
                 .map(language::proto::serialize_code_action)
                 .collect(),
-            version: (&version).into(),
+            version: serialize_version(&version),
         })
     }
 
@@ -3445,7 +3445,7 @@ impl Project {
         _: Arc<Client>,
         mut cx: AsyncAppContext,
     ) -> Result<()> {
-        let version = envelope.payload.version.try_into()?;
+        let version = deserialize_version(envelope.payload.version);
         let mtime = envelope
             .payload
             .mtime
@@ -3473,7 +3473,7 @@ impl Project {
         mut cx: AsyncAppContext,
     ) -> Result<()> {
         let payload = envelope.payload.clone();
-        let version = payload.version.try_into()?;
+        let version = deserialize_version(payload.version);
         let mtime = payload
             .mtime
             .ok_or_else(|| anyhow!("missing mtime"))?

crates/project/src/worktree.rs 🔗

@@ -17,7 +17,10 @@ use gpui::{
     executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
     Task,
 };
-use language::{Buffer, DiagnosticEntry, Operation, PointUtf16, Rope};
+use language::{
+    proto::{deserialize_version, serialize_version},
+    Buffer, DiagnosticEntry, Operation, PointUtf16, Rope,
+};
 use lazy_static::lazy_static;
 use parking_lot::Mutex;
 use postage::{
@@ -30,7 +33,7 @@ use smol::channel::{self, Sender};
 use std::{
     any::Any,
     cmp::{self, Ordering},
-    convert::{TryFrom, TryInto},
+    convert::TryFrom,
     ffi::{OsStr, OsString},
     fmt,
     future::Future,
@@ -1423,7 +1426,7 @@ impl language::File for File {
                         rpc.send(proto::BufferSaved {
                             project_id,
                             buffer_id,
-                            version: (&version).into(),
+                            version: serialize_version(&version),
                             mtime: Some(entry.mtime.into()),
                         })?;
                     }
@@ -1438,10 +1441,10 @@ impl language::File for File {
                         .request(proto::SaveBuffer {
                             project_id,
                             buffer_id,
-                            version: (&version).into(),
+                            version: serialize_version(&version),
                         })
                         .await?;
-                    let version = response.version.try_into()?;
+                    let version = deserialize_version(response.version);
                     let mtime = response
                         .mtime
                         .ok_or_else(|| anyhow!("missing mtime"))?
@@ -1518,7 +1521,7 @@ impl language::LocalFile for File {
                 .send(proto::BufferReloaded {
                     project_id,
                     buffer_id,
-                    version: version.into(),
+                    version: serialize_version(&version),
                     mtime: Some(mtime.into()),
                 })
                 .log_err();