proto.rs

  1#![allow(non_snake_case)]
  2
  3use super::{entity_messages, messages, request_messages, ConnectionId, TypedEnvelope};
  4use anyhow::{anyhow, Result};
  5use async_tungstenite::tungstenite::Message as WebSocketMessage;
  6use collections::HashMap;
  7use futures::{SinkExt as _, StreamExt as _};
  8use prost::Message as _;
  9use serde::Serialize;
 10use std::any::{Any, TypeId};
 11use std::{
 12    cmp,
 13    fmt::Debug,
 14    io, iter,
 15    time::{Duration, SystemTime, UNIX_EPOCH},
 16};
 17use std::{fmt, mem};
 18
 19include!(concat!(env!("OUT_DIR"), "/zed.messages.rs"));
 20
 21pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static {
 22    const NAME: &'static str;
 23    const PRIORITY: MessagePriority;
 24    fn into_envelope(
 25        self,
 26        id: u32,
 27        responding_to: Option<u32>,
 28        original_sender_id: Option<PeerId>,
 29    ) -> Envelope;
 30    fn from_envelope(envelope: Envelope) -> Option<Self>;
 31}
 32
 33pub trait EntityMessage: EnvelopedMessage {
 34    type Entity;
 35    fn remote_entity_id(&self) -> u64;
 36}
 37
 38pub trait RequestMessage: EnvelopedMessage {
 39    type Response: EnvelopedMessage;
 40}
 41
 42pub trait AnyTypedEnvelope: 'static + Send + Sync {
 43    fn payload_type_id(&self) -> TypeId;
 44    fn payload_type_name(&self) -> &'static str;
 45    fn as_any(&self) -> &dyn Any;
 46    fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
 47    fn is_background(&self) -> bool;
 48    fn original_sender_id(&self) -> Option<PeerId>;
 49    fn sender_id(&self) -> ConnectionId;
 50    fn message_id(&self) -> u32;
 51}
 52
 53pub enum MessagePriority {
 54    Foreground,
 55    Background,
 56}
 57
 58impl<T: EnvelopedMessage> AnyTypedEnvelope for TypedEnvelope<T> {
 59    fn payload_type_id(&self) -> TypeId {
 60        TypeId::of::<T>()
 61    }
 62
 63    fn payload_type_name(&self) -> &'static str {
 64        T::NAME
 65    }
 66
 67    fn as_any(&self) -> &dyn Any {
 68        self
 69    }
 70
 71    fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
 72        self
 73    }
 74
 75    fn is_background(&self) -> bool {
 76        matches!(T::PRIORITY, MessagePriority::Background)
 77    }
 78
 79    fn original_sender_id(&self) -> Option<PeerId> {
 80        self.original_sender_id
 81    }
 82
 83    fn sender_id(&self) -> ConnectionId {
 84        self.sender_id
 85    }
 86
 87    fn message_id(&self) -> u32 {
 88        self.message_id
 89    }
 90}
 91
 92impl PeerId {
 93    pub fn from_u64(peer_id: u64) -> Self {
 94        let owner_id = (peer_id >> 32) as u32;
 95        let id = peer_id as u32;
 96        Self { owner_id, id }
 97    }
 98
 99    pub fn as_u64(self) -> u64 {
100        ((self.owner_id as u64) << 32) | (self.id as u64)
101    }
102}
103
104impl Copy for PeerId {}
105
106impl Eq for PeerId {}
107
108impl Ord for PeerId {
109    fn cmp(&self, other: &Self) -> cmp::Ordering {
110        self.owner_id
111            .cmp(&other.owner_id)
112            .then_with(|| self.id.cmp(&other.id))
113    }
114}
115
116impl PartialOrd for PeerId {
117    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
118        Some(self.cmp(other))
119    }
120}
121
122impl std::hash::Hash for PeerId {
123    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
124        self.owner_id.hash(state);
125        self.id.hash(state);
126    }
127}
128
129impl fmt::Display for PeerId {
130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131        write!(f, "{}/{}", self.owner_id, self.id)
132    }
133}
134
135messages!(
136    (Ack, Foreground),
137    (AckBufferOperation, Background),
138    (AckChannelMessage, Background),
139    (AddNotification, Foreground),
140    (AddProjectCollaborator, Foreground),
141    (ApplyCodeAction, Background),
142    (ApplyCodeActionResponse, Background),
143    (ApplyCompletionAdditionalEdits, Background),
144    (ApplyCompletionAdditionalEditsResponse, Background),
145    (BufferReloaded, Foreground),
146    (BufferSaved, Foreground),
147    (Call, Foreground),
148    (CallCanceled, Foreground),
149    (CancelCall, Foreground),
150    (ChannelMessageSent, Foreground),
151    (CopyProjectEntry, Foreground),
152    (CreateBufferForPeer, Foreground),
153    (CreateChannel, Foreground),
154    (CreateChannelResponse, Foreground),
155    (CreateProjectEntry, Foreground),
156    (CreateRoom, Foreground),
157    (CreateRoomResponse, Foreground),
158    (DeclineCall, Foreground),
159    (DeleteChannel, Foreground),
160    (DeleteNotification, Foreground),
161    (DeleteProjectEntry, Foreground),
162    (Error, Foreground),
163    (ExpandProjectEntry, Foreground),
164    (ExpandProjectEntryResponse, Foreground),
165    (Follow, Foreground),
166    (FollowResponse, Foreground),
167    (FormatBuffers, Foreground),
168    (FormatBuffersResponse, Foreground),
169    (FuzzySearchUsers, Foreground),
170    (GetChannelMembers, Foreground),
171    (GetChannelMembersResponse, Foreground),
172    (GetChannelMessages, Background),
173    (GetChannelMessagesById, Background),
174    (GetChannelMessagesResponse, Background),
175    (GetCodeActions, Background),
176    (GetCodeActionsResponse, Background),
177    (GetCompletions, Background),
178    (GetCompletionsResponse, Background),
179    (GetDefinition, Background),
180    (GetDefinitionResponse, Background),
181    (GetDocumentHighlights, Background),
182    (GetDocumentHighlightsResponse, Background),
183    (GetHover, Background),
184    (GetHoverResponse, Background),
185    (GetNotifications, Foreground),
186    (GetNotificationsResponse, Foreground),
187    (GetPrivateUserInfo, Foreground),
188    (GetPrivateUserInfoResponse, Foreground),
189    (GetProjectSymbols, Background),
190    (GetProjectSymbolsResponse, Background),
191    (GetReferences, Background),
192    (GetReferencesResponse, Background),
193    (GetTypeDefinition, Background),
194    (GetTypeDefinitionResponse, Background),
195    (GetUsers, Foreground),
196    (Hello, Foreground),
197    (IncomingCall, Foreground),
198    (InlayHints, Background),
199    (InlayHintsResponse, Background),
200    (InviteChannelMember, Foreground),
201    (JoinChannel2, Foreground),
202    (JoinChannel, Foreground),
203    (JoinChannelBuffer, Foreground),
204    (JoinChannelBufferResponse, Foreground),
205    (JoinChannelChat, Foreground),
206    (JoinChannelChatResponse, Foreground),
207    (JoinProject, Foreground),
208    (JoinProjectResponse, Foreground),
209    (JoinRoom, Foreground),
210    (JoinRoomResponse, Foreground),
211    (LeaveChannelBuffer, Background),
212    (JoinChannelCall, Foreground),
213    (JoinChannelCallResponse, Foreground),
214    (LeaveChannelCall, Foreground),
215    (LeaveChannelChat, Foreground),
216    (LeaveProject, Foreground),
217    (LeaveRoom, Foreground),
218    (MarkNotificationRead, Foreground),
219    (MoveChannel, Foreground),
220    (OnTypeFormatting, Background),
221    (OnTypeFormattingResponse, Background),
222    (OpenBufferById, Background),
223    (OpenBufferByPath, Background),
224    (OpenBufferForSymbol, Background),
225    (OpenBufferForSymbolResponse, Background),
226    (OpenBufferResponse, Background),
227    (PerformRename, Background),
228    (PerformRenameResponse, Background),
229    (Ping, Foreground),
230    (PrepareRename, Background),
231    (PrepareRenameResponse, Background),
232    (ProjectEntryResponse, Foreground),
233    (RefreshInlayHints, Foreground),
234    (RejoinChannelBuffers, Foreground),
235    (RejoinChannelBuffersResponse, Foreground),
236    (RejoinRoom, Foreground),
237    (RejoinRoomResponse, Foreground),
238    (ReloadBuffers, Foreground),
239    (ReloadBuffersResponse, Foreground),
240    (RemoveChannelMember, Foreground),
241    (RemoveChannelMessage, Foreground),
242    (RemoveContact, Foreground),
243    (RemoveProjectCollaborator, Foreground),
244    (RenameChannel, Foreground),
245    (RenameChannelResponse, Foreground),
246    (RenameProjectEntry, Foreground),
247    (RequestContact, Foreground),
248    (ResolveCompletionDocumentation, Background),
249    (ResolveCompletionDocumentationResponse, Background),
250    (ResolveInlayHint, Background),
251    (ResolveInlayHintResponse, Background),
252    (RespondToChannelInvite, Foreground),
253    (RespondToContactRequest, Foreground),
254    (RoomUpdated, Foreground),
255    (SaveBuffer, Foreground),
256    (SetChannelMemberRole, Foreground),
257    (SetChannelVisibility, Foreground),
258    (SearchProject, Background),
259    (SearchProjectResponse, Background),
260    (SendChannelMessage, Background),
261    (SendChannelMessageResponse, Background),
262    (ShareProject, Foreground),
263    (ShareProjectResponse, Foreground),
264    (ShowContacts, Foreground),
265    (StartLanguageServer, Foreground),
266    (SynchronizeBuffers, Foreground),
267    (SynchronizeBuffersResponse, Foreground),
268    (Test, Foreground),
269    (Unfollow, Foreground),
270    (UnshareProject, Foreground),
271    (UpdateBuffer, Foreground),
272    (UpdateBufferFile, Foreground),
273    (UpdateChannelBuffer, Foreground),
274    (UpdateChannelBufferCollaborators, Foreground),
275    (UpdateChannels, Foreground),
276    (UpdateUserChannels, Foreground),
277    (UpdateContacts, Foreground),
278    (UpdateDiagnosticSummary, Foreground),
279    (UpdateDiffBase, Foreground),
280    (UpdateFollowers, Foreground),
281    (UpdateInviteInfo, Foreground),
282    (UpdateLanguageServer, Foreground),
283    (UpdateParticipantLocation, Foreground),
284    (UpdateProject, Foreground),
285    (UpdateProjectCollaborator, Foreground),
286    (UpdateWorktree, Foreground),
287    (UpdateWorktreeSettings, Foreground),
288    (UsersResponse, Foreground),
289    (LspExtExpandMacro, Background),
290    (LspExtExpandMacroResponse, Background),
291    (SetRoomParticipantRole, Foreground),
292);
293
294request_messages!(
295    (ApplyCodeAction, ApplyCodeActionResponse),
296    (
297        ApplyCompletionAdditionalEdits,
298        ApplyCompletionAdditionalEditsResponse
299    ),
300    (Call, Ack),
301    (CancelCall, Ack),
302    (CopyProjectEntry, ProjectEntryResponse),
303    (CreateChannel, CreateChannelResponse),
304    (CreateProjectEntry, ProjectEntryResponse),
305    (CreateRoom, CreateRoomResponse),
306    (DeclineCall, Ack),
307    (DeleteChannel, Ack),
308    (DeleteProjectEntry, ProjectEntryResponse),
309    (ExpandProjectEntry, ExpandProjectEntryResponse),
310    (Follow, FollowResponse),
311    (FormatBuffers, FormatBuffersResponse),
312    (FuzzySearchUsers, UsersResponse),
313    (GetChannelMembers, GetChannelMembersResponse),
314    (GetChannelMessages, GetChannelMessagesResponse),
315    (GetChannelMessagesById, GetChannelMessagesResponse),
316    (GetCodeActions, GetCodeActionsResponse),
317    (GetCompletions, GetCompletionsResponse),
318    (GetDefinition, GetDefinitionResponse),
319    (GetDocumentHighlights, GetDocumentHighlightsResponse),
320    (GetHover, GetHoverResponse),
321    (GetNotifications, GetNotificationsResponse),
322    (GetPrivateUserInfo, GetPrivateUserInfoResponse),
323    (GetProjectSymbols, GetProjectSymbolsResponse),
324    (GetReferences, GetReferencesResponse),
325    (GetTypeDefinition, GetTypeDefinitionResponse),
326    (GetUsers, UsersResponse),
327    (IncomingCall, Ack),
328    (InlayHints, InlayHintsResponse),
329    (InviteChannelMember, Ack),
330    (JoinChannel, JoinRoomResponse),
331    (JoinChannel2, JoinRoomResponse),
332    (JoinChannelCall, JoinChannelCallResponse),
333    (LeaveChannelCall, Ack),
334    (JoinChannelBuffer, JoinChannelBufferResponse),
335    (JoinChannelChat, JoinChannelChatResponse),
336    (JoinProject, JoinProjectResponse),
337    (JoinRoom, JoinRoomResponse),
338    (LeaveChannelBuffer, Ack),
339    (LeaveRoom, Ack),
340    (MarkNotificationRead, Ack),
341    (MoveChannel, Ack),
342    (OnTypeFormatting, OnTypeFormattingResponse),
343    (OpenBufferById, OpenBufferResponse),
344    (OpenBufferByPath, OpenBufferResponse),
345    (OpenBufferForSymbol, OpenBufferForSymbolResponse),
346    (PerformRename, PerformRenameResponse),
347    (Ping, Ack),
348    (PrepareRename, PrepareRenameResponse),
349    (RefreshInlayHints, Ack),
350    (RejoinChannelBuffers, RejoinChannelBuffersResponse),
351    (RejoinRoom, RejoinRoomResponse),
352    (ReloadBuffers, ReloadBuffersResponse),
353    (RemoveChannelMember, Ack),
354    (RemoveChannelMessage, Ack),
355    (RemoveContact, Ack),
356    (RenameChannel, RenameChannelResponse),
357    (RenameProjectEntry, ProjectEntryResponse),
358    (RequestContact, Ack),
359    (
360        ResolveCompletionDocumentation,
361        ResolveCompletionDocumentationResponse
362    ),
363    (ResolveInlayHint, ResolveInlayHintResponse),
364    (RespondToChannelInvite, Ack),
365    (RespondToContactRequest, Ack),
366    (SaveBuffer, BufferSaved),
367    (SearchProject, SearchProjectResponse),
368    (SendChannelMessage, SendChannelMessageResponse),
369    (SetChannelMemberRole, Ack),
370    (SetChannelVisibility, Ack),
371    (ShareProject, ShareProjectResponse),
372    (SynchronizeBuffers, SynchronizeBuffersResponse),
373    (Test, Test),
374    (UpdateBuffer, Ack),
375    (UpdateParticipantLocation, Ack),
376    (UpdateProject, Ack),
377    (UpdateWorktree, Ack),
378    (LspExtExpandMacro, LspExtExpandMacroResponse),
379    (SetRoomParticipantRole, Ack),
380);
381
382entity_messages!(
383    {project_id, ShareProject},
384    AddProjectCollaborator,
385    ApplyCodeAction,
386    ApplyCompletionAdditionalEdits,
387    BufferReloaded,
388    BufferSaved,
389    CopyProjectEntry,
390    CreateBufferForPeer,
391    CreateProjectEntry,
392    DeleteProjectEntry,
393    ExpandProjectEntry,
394    FormatBuffers,
395    GetCodeActions,
396    GetCompletions,
397    GetDefinition,
398    GetDocumentHighlights,
399    GetHover,
400    GetProjectSymbols,
401    GetReferences,
402    GetTypeDefinition,
403    InlayHints,
404    JoinProject,
405    LeaveProject,
406    OnTypeFormatting,
407    OpenBufferById,
408    OpenBufferByPath,
409    OpenBufferForSymbol,
410    PerformRename,
411    PrepareRename,
412    RefreshInlayHints,
413    ReloadBuffers,
414    RemoveProjectCollaborator,
415    RenameProjectEntry,
416    ResolveCompletionDocumentation,
417    ResolveInlayHint,
418    SaveBuffer,
419    SearchProject,
420    StartLanguageServer,
421    SynchronizeBuffers,
422    UnshareProject,
423    UpdateBuffer,
424    UpdateBufferFile,
425    UpdateDiagnosticSummary,
426    UpdateDiffBase,
427    UpdateLanguageServer,
428    UpdateProject,
429    UpdateProjectCollaborator,
430    UpdateWorktree,
431    UpdateWorktreeSettings,
432    LspExtExpandMacro,
433);
434
435entity_messages!(
436    {channel_id, Channel},
437    ChannelMessageSent,
438    RemoveChannelMessage,
439    UpdateChannelBuffer,
440    UpdateChannelBufferCollaborators,
441);
442
443const KIB: usize = 1024;
444const MIB: usize = KIB * 1024;
445const MAX_BUFFER_LEN: usize = MIB;
446
447/// A stream of protobuf messages.
448pub struct MessageStream<S> {
449    stream: S,
450    encoding_buffer: Vec<u8>,
451}
452
453#[allow(clippy::large_enum_variant)]
454#[derive(Debug)]
455pub enum Message {
456    Envelope(Envelope),
457    Ping,
458    Pong,
459}
460
461impl<S> MessageStream<S> {
462    pub fn new(stream: S) -> Self {
463        Self {
464            stream,
465            encoding_buffer: Vec::new(),
466        }
467    }
468
469    pub fn inner_mut(&mut self) -> &mut S {
470        &mut self.stream
471    }
472}
473
474impl<S> MessageStream<S>
475where
476    S: futures::Sink<WebSocketMessage, Error = anyhow::Error> + Unpin,
477{
478    pub async fn write(&mut self, message: Message) -> Result<(), anyhow::Error> {
479        #[cfg(any(test, feature = "test-support"))]
480        const COMPRESSION_LEVEL: i32 = -7;
481
482        #[cfg(not(any(test, feature = "test-support")))]
483        const COMPRESSION_LEVEL: i32 = 4;
484
485        match message {
486            Message::Envelope(message) => {
487                self.encoding_buffer.reserve(message.encoded_len());
488                message
489                    .encode(&mut self.encoding_buffer)
490                    .map_err(io::Error::from)?;
491                let buffer =
492                    zstd::stream::encode_all(self.encoding_buffer.as_slice(), COMPRESSION_LEVEL)
493                        .unwrap();
494
495                self.encoding_buffer.clear();
496                self.encoding_buffer.shrink_to(MAX_BUFFER_LEN);
497                self.stream.send(WebSocketMessage::Binary(buffer)).await?;
498            }
499            Message::Ping => {
500                self.stream
501                    .send(WebSocketMessage::Ping(Default::default()))
502                    .await?;
503            }
504            Message::Pong => {
505                self.stream
506                    .send(WebSocketMessage::Pong(Default::default()))
507                    .await?;
508            }
509        }
510
511        Ok(())
512    }
513}
514
515impl<S> MessageStream<S>
516where
517    S: futures::Stream<Item = Result<WebSocketMessage, anyhow::Error>> + Unpin,
518{
519    pub async fn read(&mut self) -> Result<Message, anyhow::Error> {
520        while let Some(bytes) = self.stream.next().await {
521            match bytes? {
522                WebSocketMessage::Binary(bytes) => {
523                    zstd::stream::copy_decode(bytes.as_slice(), &mut self.encoding_buffer).unwrap();
524                    let envelope = Envelope::decode(self.encoding_buffer.as_slice())
525                        .map_err(io::Error::from)?;
526
527                    self.encoding_buffer.clear();
528                    self.encoding_buffer.shrink_to(MAX_BUFFER_LEN);
529                    return Ok(Message::Envelope(envelope));
530                }
531                WebSocketMessage::Ping(_) => return Ok(Message::Ping),
532                WebSocketMessage::Pong(_) => return Ok(Message::Pong),
533                WebSocketMessage::Close(_) => break,
534                _ => {}
535            }
536        }
537        Err(anyhow!("connection closed"))
538    }
539}
540
541impl From<Timestamp> for SystemTime {
542    fn from(val: Timestamp) -> Self {
543        UNIX_EPOCH
544            .checked_add(Duration::new(val.seconds, val.nanos))
545            .unwrap()
546    }
547}
548
549impl From<SystemTime> for Timestamp {
550    fn from(time: SystemTime) -> Self {
551        let duration = time.duration_since(UNIX_EPOCH).unwrap();
552        Self {
553            seconds: duration.as_secs(),
554            nanos: duration.subsec_nanos(),
555        }
556    }
557}
558
559impl From<u128> for Nonce {
560    fn from(nonce: u128) -> Self {
561        let upper_half = (nonce >> 64) as u64;
562        let lower_half = nonce as u64;
563        Self {
564            upper_half,
565            lower_half,
566        }
567    }
568}
569
570impl From<Nonce> for u128 {
571    fn from(nonce: Nonce) -> Self {
572        let upper_half = (nonce.upper_half as u128) << 64;
573        let lower_half = nonce.lower_half as u128;
574        upper_half | lower_half
575    }
576}
577
578pub fn split_worktree_update(
579    mut message: UpdateWorktree,
580    max_chunk_size: usize,
581) -> impl Iterator<Item = UpdateWorktree> {
582    let mut done_files = false;
583
584    let mut repository_map = message
585        .updated_repositories
586        .into_iter()
587        .map(|repo| (repo.work_directory_id, repo))
588        .collect::<HashMap<_, _>>();
589
590    iter::from_fn(move || {
591        if done_files {
592            return None;
593        }
594
595        let updated_entries_chunk_size = cmp::min(message.updated_entries.len(), max_chunk_size);
596        let updated_entries: Vec<_> = message
597            .updated_entries
598            .drain(..updated_entries_chunk_size)
599            .collect();
600
601        let removed_entries_chunk_size = cmp::min(message.removed_entries.len(), max_chunk_size);
602        let removed_entries = message
603            .removed_entries
604            .drain(..removed_entries_chunk_size)
605            .collect();
606
607        done_files = message.updated_entries.is_empty() && message.removed_entries.is_empty();
608
609        let mut updated_repositories = Vec::new();
610
611        if !repository_map.is_empty() {
612            for entry in &updated_entries {
613                if let Some(repo) = repository_map.remove(&entry.id) {
614                    updated_repositories.push(repo)
615                }
616            }
617        }
618
619        let removed_repositories = if done_files {
620            mem::take(&mut message.removed_repositories)
621        } else {
622            Default::default()
623        };
624
625        if done_files {
626            updated_repositories.extend(mem::take(&mut repository_map).into_values());
627        }
628
629        Some(UpdateWorktree {
630            project_id: message.project_id,
631            worktree_id: message.worktree_id,
632            root_name: message.root_name.clone(),
633            abs_path: message.abs_path.clone(),
634            updated_entries,
635            removed_entries,
636            scan_id: message.scan_id,
637            is_last_update: done_files && message.is_last_update,
638            updated_repositories,
639            removed_repositories,
640        })
641    })
642}
643
644#[cfg(test)]
645mod tests {
646    use super::*;
647
648    #[gpui::test]
649    async fn test_buffer_size() {
650        let (tx, rx) = futures::channel::mpsc::unbounded();
651        let mut sink = MessageStream::new(tx.sink_map_err(|_| anyhow!("")));
652        sink.write(Message::Envelope(Envelope {
653            payload: Some(envelope::Payload::UpdateWorktree(UpdateWorktree {
654                root_name: "abcdefg".repeat(10),
655                ..Default::default()
656            })),
657            ..Default::default()
658        }))
659        .await
660        .unwrap();
661        assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
662        sink.write(Message::Envelope(Envelope {
663            payload: Some(envelope::Payload::UpdateWorktree(UpdateWorktree {
664                root_name: "abcdefg".repeat(1000000),
665                ..Default::default()
666            })),
667            ..Default::default()
668        }))
669        .await
670        .unwrap();
671        assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
672
673        let mut stream = MessageStream::new(rx.map(anyhow::Ok));
674        stream.read().await.unwrap();
675        assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
676        stream.read().await.unwrap();
677        assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
678    }
679
680    #[gpui::test]
681    fn test_converting_peer_id_from_and_to_u64() {
682        let peer_id = PeerId {
683            owner_id: 10,
684            id: 3,
685        };
686        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
687        let peer_id = PeerId {
688            owner_id: u32::MAX,
689            id: 3,
690        };
691        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
692        let peer_id = PeerId {
693            owner_id: 10,
694            id: u32::MAX,
695        };
696        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
697        let peer_id = PeerId {
698            owner_id: u32::MAX,
699            id: u32::MAX,
700        };
701        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
702    }
703}