proto.rs

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