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