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::time::Instant;
 12use std::{
 13    cmp,
 14    fmt::Debug,
 15    io, iter,
 16    time::{Duration, SystemTime, UNIX_EPOCH},
 17};
 18use std::{fmt, mem};
 19
 20include!(concat!(env!("OUT_DIR"), "/zed.messages.rs"));
 21
 22pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static {
 23    const NAME: &'static str;
 24    const PRIORITY: MessagePriority;
 25    fn into_envelope(
 26        self,
 27        id: u32,
 28        responding_to: Option<u32>,
 29        original_sender_id: Option<PeerId>,
 30    ) -> Envelope;
 31    fn from_envelope(envelope: Envelope) -> Option<Self>;
 32}
 33
 34pub trait EntityMessage: EnvelopedMessage {
 35    type Entity;
 36    fn remote_entity_id(&self) -> u64;
 37}
 38
 39pub trait RequestMessage: EnvelopedMessage {
 40    type Response: EnvelopedMessage;
 41}
 42
 43pub trait AnyTypedEnvelope: 'static + Send + Sync {
 44    fn payload_type_id(&self) -> TypeId;
 45    fn payload_type_name(&self) -> &'static str;
 46    fn as_any(&self) -> &dyn Any;
 47    fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
 48    fn is_background(&self) -> bool;
 49    fn original_sender_id(&self) -> Option<PeerId>;
 50    fn sender_id(&self) -> ConnectionId;
 51    fn message_id(&self) -> u32;
 52}
 53
 54pub enum MessagePriority {
 55    Foreground,
 56    Background,
 57}
 58
 59impl<T: EnvelopedMessage> AnyTypedEnvelope for TypedEnvelope<T> {
 60    fn payload_type_id(&self) -> TypeId {
 61        TypeId::of::<T>()
 62    }
 63
 64    fn payload_type_name(&self) -> &'static str {
 65        T::NAME
 66    }
 67
 68    fn as_any(&self) -> &dyn Any {
 69        self
 70    }
 71
 72    fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
 73        self
 74    }
 75
 76    fn is_background(&self) -> bool {
 77        matches!(T::PRIORITY, MessagePriority::Background)
 78    }
 79
 80    fn original_sender_id(&self) -> Option<PeerId> {
 81        self.original_sender_id
 82    }
 83
 84    fn sender_id(&self) -> ConnectionId {
 85        self.sender_id
 86    }
 87
 88    fn message_id(&self) -> u32 {
 89        self.message_id
 90    }
 91}
 92
 93impl PeerId {
 94    pub fn from_u64(peer_id: u64) -> Self {
 95        let owner_id = (peer_id >> 32) as u32;
 96        let id = peer_id as u32;
 97        Self { owner_id, id }
 98    }
 99
100    pub fn as_u64(self) -> u64 {
101        ((self.owner_id as u64) << 32) | (self.id as u64)
102    }
103}
104
105impl Copy for PeerId {}
106
107impl Eq for PeerId {}
108
109impl Ord for PeerId {
110    fn cmp(&self, other: &Self) -> cmp::Ordering {
111        self.owner_id
112            .cmp(&other.owner_id)
113            .then_with(|| self.id.cmp(&other.id))
114    }
115}
116
117impl PartialOrd for PeerId {
118    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
119        Some(self.cmp(other))
120    }
121}
122
123impl std::hash::Hash for PeerId {
124    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
125        self.owner_id.hash(state);
126        self.id.hash(state);
127    }
128}
129
130impl fmt::Display for PeerId {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        write!(f, "{}/{}", self.owner_id, self.id)
133    }
134}
135
136messages!(
137    (Ack, Foreground),
138    (AckBufferOperation, Background),
139    (AckChannelMessage, Background),
140    (AddNotification, Foreground),
141    (AddProjectCollaborator, Foreground),
142    (ApplyCodeAction, Background),
143    (ApplyCodeActionResponse, Background),
144    (ApplyCompletionAdditionalEdits, Background),
145    (ApplyCompletionAdditionalEditsResponse, Background),
146    (BufferReloaded, Foreground),
147    (BufferSaved, Foreground),
148    (Call, Foreground),
149    (CallCanceled, Foreground),
150    (CancelCall, Foreground),
151    (ChannelMessageSent, Foreground),
152    (CopyProjectEntry, Foreground),
153    (CreateBufferForPeer, Foreground),
154    (CreateChannel, Foreground),
155    (CreateChannelResponse, Foreground),
156    (CreateProjectEntry, Foreground),
157    (CreateRoom, Foreground),
158    (CreateRoomResponse, Foreground),
159    (DeclineCall, Foreground),
160    (DeleteChannel, Foreground),
161    (DeleteNotification, Foreground),
162    (DeleteProjectEntry, Foreground),
163    (Error, Foreground),
164    (ExpandProjectEntry, Foreground),
165    (ExpandProjectEntryResponse, Foreground),
166    (Follow, Foreground),
167    (FollowResponse, Foreground),
168    (FormatBuffers, Foreground),
169    (FormatBuffersResponse, Foreground),
170    (FuzzySearchUsers, Foreground),
171    (GetChannelMembers, Foreground),
172    (GetChannelMembersResponse, Foreground),
173    (GetChannelMessages, Background),
174    (GetChannelMessagesById, Background),
175    (GetChannelMessagesResponse, Background),
176    (GetCodeActions, Background),
177    (GetCodeActionsResponse, Background),
178    (GetCompletions, Background),
179    (GetCompletionsResponse, Background),
180    (GetDefinition, Background),
181    (GetDefinitionResponse, Background),
182    (GetDocumentHighlights, Background),
183    (GetDocumentHighlightsResponse, Background),
184    (GetHover, Background),
185    (GetHoverResponse, Background),
186    (GetNotifications, Foreground),
187    (GetNotificationsResponse, Foreground),
188    (GetPrivateUserInfo, Foreground),
189    (GetPrivateUserInfoResponse, Foreground),
190    (GetProjectSymbols, Background),
191    (GetProjectSymbolsResponse, Background),
192    (GetReferences, Background),
193    (GetReferencesResponse, Background),
194    (GetTypeDefinition, Background),
195    (GetTypeDefinitionResponse, Background),
196    (GetImplementation, Background),
197    (GetImplementationResponse, Background),
198    (GetUsers, Foreground),
199    (Hello, Foreground),
200    (IncomingCall, Foreground),
201    (InlayHints, Background),
202    (InlayHintsResponse, Background),
203    (InviteChannelMember, Foreground),
204    (JoinChannel, Foreground),
205    (JoinChannelBuffer, Foreground),
206    (JoinChannelBufferResponse, Foreground),
207    (JoinChannelChat, Foreground),
208    (JoinChannelChatResponse, Foreground),
209    (JoinProject, Foreground),
210    (JoinHostedProject, Foreground),
211    (JoinProjectResponse, Foreground),
212    (JoinRoom, Foreground),
213    (JoinRoomResponse, Foreground),
214    (LeaveChannelBuffer, Background),
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    (GetImplementation, GetImplementationResponse),
320    (GetDocumentHighlights, GetDocumentHighlightsResponse),
321    (GetHover, GetHoverResponse),
322    (GetNotifications, GetNotificationsResponse),
323    (GetPrivateUserInfo, GetPrivateUserInfoResponse),
324    (GetProjectSymbols, GetProjectSymbolsResponse),
325    (GetReferences, GetReferencesResponse),
326    (GetTypeDefinition, GetTypeDefinitionResponse),
327    (GetUsers, UsersResponse),
328    (IncomingCall, Ack),
329    (InlayHints, InlayHintsResponse),
330    (InviteChannelMember, Ack),
331    (JoinChannel, JoinRoomResponse),
332    (JoinChannelBuffer, JoinChannelBufferResponse),
333    (JoinChannelChat, JoinChannelChatResponse),
334    (JoinHostedProject, JoinProjectResponse),
335    (JoinProject, JoinProjectResponse),
336    (JoinRoom, JoinRoomResponse),
337    (LeaveChannelBuffer, Ack),
338    (LeaveRoom, Ack),
339    (MarkNotificationRead, Ack),
340    (MoveChannel, Ack),
341    (OnTypeFormatting, OnTypeFormattingResponse),
342    (OpenBufferById, OpenBufferResponse),
343    (OpenBufferByPath, OpenBufferResponse),
344    (OpenBufferForSymbol, OpenBufferForSymbolResponse),
345    (PerformRename, PerformRenameResponse),
346    (Ping, Ack),
347    (PrepareRename, PrepareRenameResponse),
348    (RefreshInlayHints, Ack),
349    (RejoinChannelBuffers, RejoinChannelBuffersResponse),
350    (RejoinRoom, RejoinRoomResponse),
351    (ReloadBuffers, ReloadBuffersResponse),
352    (RemoveChannelMember, Ack),
353    (RemoveChannelMessage, Ack),
354    (RemoveContact, Ack),
355    (RenameChannel, RenameChannelResponse),
356    (RenameProjectEntry, ProjectEntryResponse),
357    (RequestContact, Ack),
358    (
359        ResolveCompletionDocumentation,
360        ResolveCompletionDocumentationResponse
361    ),
362    (ResolveInlayHint, ResolveInlayHintResponse),
363    (RespondToChannelInvite, Ack),
364    (RespondToContactRequest, Ack),
365    (SaveBuffer, BufferSaved),
366    (SearchProject, SearchProjectResponse),
367    (SendChannelMessage, SendChannelMessageResponse),
368    (SetChannelMemberRole, Ack),
369    (SetChannelVisibility, Ack),
370    (ShareProject, ShareProjectResponse),
371    (SynchronizeBuffers, SynchronizeBuffersResponse),
372    (Test, Test),
373    (UpdateBuffer, Ack),
374    (UpdateParticipantLocation, Ack),
375    (UpdateProject, Ack),
376    (UpdateWorktree, Ack),
377    (LspExtExpandMacro, LspExtExpandMacroResponse),
378    (SetRoomParticipantRole, Ack),
379);
380
381entity_messages!(
382    {project_id, ShareProject},
383    AddProjectCollaborator,
384    ApplyCodeAction,
385    ApplyCompletionAdditionalEdits,
386    BufferReloaded,
387    BufferSaved,
388    CopyProjectEntry,
389    CreateBufferForPeer,
390    CreateProjectEntry,
391    DeleteProjectEntry,
392    ExpandProjectEntry,
393    FormatBuffers,
394    GetCodeActions,
395    GetCompletions,
396    GetDefinition,
397    GetImplementation,
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, Instant), anyhow::Error> {
520        while let Some(bytes) = self.stream.next().await {
521            let received_at = Instant::now();
522            match bytes? {
523                WebSocketMessage::Binary(bytes) => {
524                    zstd::stream::copy_decode(bytes.as_slice(), &mut self.encoding_buffer).unwrap();
525                    let envelope = Envelope::decode(self.encoding_buffer.as_slice())
526                        .map_err(io::Error::from)?;
527
528                    self.encoding_buffer.clear();
529                    self.encoding_buffer.shrink_to(MAX_BUFFER_LEN);
530                    return Ok((Message::Envelope(envelope), received_at));
531                }
532                WebSocketMessage::Ping(_) => return Ok((Message::Ping, received_at)),
533                WebSocketMessage::Pong(_) => return Ok((Message::Pong, received_at)),
534                WebSocketMessage::Close(_) => break,
535                _ => {}
536            }
537        }
538        Err(anyhow!("connection closed"))
539    }
540}
541
542impl From<Timestamp> for SystemTime {
543    fn from(val: Timestamp) -> Self {
544        UNIX_EPOCH
545            .checked_add(Duration::new(val.seconds, val.nanos))
546            .unwrap()
547    }
548}
549
550impl From<SystemTime> for Timestamp {
551    fn from(time: SystemTime) -> Self {
552        let duration = time.duration_since(UNIX_EPOCH).unwrap();
553        Self {
554            seconds: duration.as_secs(),
555            nanos: duration.subsec_nanos(),
556        }
557    }
558}
559
560impl From<u128> for Nonce {
561    fn from(nonce: u128) -> Self {
562        let upper_half = (nonce >> 64) as u64;
563        let lower_half = nonce as u64;
564        Self {
565            upper_half,
566            lower_half,
567        }
568    }
569}
570
571impl From<Nonce> for u128 {
572    fn from(nonce: Nonce) -> Self {
573        let upper_half = (nonce.upper_half as u128) << 64;
574        let lower_half = nonce.lower_half as u128;
575        upper_half | lower_half
576    }
577}
578
579pub fn split_worktree_update(
580    mut message: UpdateWorktree,
581    max_chunk_size: usize,
582) -> impl Iterator<Item = UpdateWorktree> {
583    let mut done_files = false;
584
585    let mut repository_map = message
586        .updated_repositories
587        .into_iter()
588        .map(|repo| (repo.work_directory_id, repo))
589        .collect::<HashMap<_, _>>();
590
591    iter::from_fn(move || {
592        if done_files {
593            return None;
594        }
595
596        let updated_entries_chunk_size = cmp::min(message.updated_entries.len(), max_chunk_size);
597        let updated_entries: Vec<_> = message
598            .updated_entries
599            .drain(..updated_entries_chunk_size)
600            .collect();
601
602        let removed_entries_chunk_size = cmp::min(message.removed_entries.len(), max_chunk_size);
603        let removed_entries = message
604            .removed_entries
605            .drain(..removed_entries_chunk_size)
606            .collect();
607
608        done_files = message.updated_entries.is_empty() && message.removed_entries.is_empty();
609
610        let mut updated_repositories = Vec::new();
611
612        if !repository_map.is_empty() {
613            for entry in &updated_entries {
614                if let Some(repo) = repository_map.remove(&entry.id) {
615                    updated_repositories.push(repo)
616                }
617            }
618        }
619
620        let removed_repositories = if done_files {
621            mem::take(&mut message.removed_repositories)
622        } else {
623            Default::default()
624        };
625
626        if done_files {
627            updated_repositories.extend(mem::take(&mut repository_map).into_values());
628        }
629
630        Some(UpdateWorktree {
631            project_id: message.project_id,
632            worktree_id: message.worktree_id,
633            root_name: message.root_name.clone(),
634            abs_path: message.abs_path.clone(),
635            updated_entries,
636            removed_entries,
637            scan_id: message.scan_id,
638            is_last_update: done_files && message.is_last_update,
639            updated_repositories,
640            removed_repositories,
641        })
642    })
643}
644
645#[cfg(test)]
646mod tests {
647    use super::*;
648
649    #[gpui::test]
650    async fn test_buffer_size() {
651        let (tx, rx) = futures::channel::mpsc::unbounded();
652        let mut sink = MessageStream::new(tx.sink_map_err(|_| anyhow!("")));
653        sink.write(Message::Envelope(Envelope {
654            payload: Some(envelope::Payload::UpdateWorktree(UpdateWorktree {
655                root_name: "abcdefg".repeat(10),
656                ..Default::default()
657            })),
658            ..Default::default()
659        }))
660        .await
661        .unwrap();
662        assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
663        sink.write(Message::Envelope(Envelope {
664            payload: Some(envelope::Payload::UpdateWorktree(UpdateWorktree {
665                root_name: "abcdefg".repeat(1000000),
666                ..Default::default()
667            })),
668            ..Default::default()
669        }))
670        .await
671        .unwrap();
672        assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
673
674        let mut stream = MessageStream::new(rx.map(anyhow::Ok));
675        stream.read().await.unwrap();
676        assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
677        stream.read().await.unwrap();
678        assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
679    }
680
681    #[gpui::test]
682    fn test_converting_peer_id_from_and_to_u64() {
683        let peer_id = PeerId {
684            owner_id: 10,
685            id: 3,
686        };
687        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
688        let peer_id = PeerId {
689            owner_id: u32::MAX,
690            id: 3,
691        };
692        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
693        let peer_id = PeerId {
694            owner_id: 10,
695            id: u32::MAX,
696        };
697        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
698        let peer_id = PeerId {
699            owner_id: u32::MAX,
700            id: u32::MAX,
701        };
702        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
703    }
704}