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    (AcceptTermsOfService, Foreground),
191    (AcceptTermsOfServiceResponse, Foreground),
192    (Ack, Foreground),
193    (AckBufferOperation, Background),
194    (AckChannelMessage, Background),
195    (AddNotification, Foreground),
196    (AddProjectCollaborator, Foreground),
197    (ApplyCodeAction, Background),
198    (ApplyCodeActionResponse, Background),
199    (ApplyCompletionAdditionalEdits, Background),
200    (ApplyCompletionAdditionalEditsResponse, Background),
201    (BufferReloaded, Foreground),
202    (BufferSaved, Foreground),
203    (Call, Foreground),
204    (CallCanceled, Foreground),
205    (CancelCall, Foreground),
206    (ChannelMessageSent, Foreground),
207    (ChannelMessageUpdate, Foreground),
208    (ComputeEmbeddings, Background),
209    (ComputeEmbeddingsResponse, Background),
210    (CopyProjectEntry, Foreground),
211    (CreateBufferForPeer, Foreground),
212    (CreateChannel, Foreground),
213    (CreateChannelResponse, Foreground),
214    (CreateProjectEntry, Foreground),
215    (CreateRoom, Foreground),
216    (CreateRoomResponse, Foreground),
217    (DeclineCall, Foreground),
218    (DeleteChannel, Foreground),
219    (DeleteNotification, Foreground),
220    (UpdateNotification, Foreground),
221    (DeleteProjectEntry, Foreground),
222    (EndStream, Foreground),
223    (Error, Foreground),
224    (ExpandProjectEntry, Foreground),
225    (ExpandProjectEntryResponse, Foreground),
226    (Follow, Foreground),
227    (FollowResponse, Foreground),
228    (FormatBuffers, Foreground),
229    (FormatBuffersResponse, Foreground),
230    (FuzzySearchUsers, Foreground),
231    (GetCachedEmbeddings, Background),
232    (GetCachedEmbeddingsResponse, Background),
233    (GetChannelMembers, Foreground),
234    (GetChannelMembersResponse, Foreground),
235    (GetChannelMessages, Background),
236    (GetChannelMessagesById, Background),
237    (GetChannelMessagesResponse, Background),
238    (GetCodeActions, Background),
239    (GetCodeActionsResponse, Background),
240    (GetCompletions, Background),
241    (GetCompletionsResponse, Background),
242    (GetDefinition, Background),
243    (GetDefinitionResponse, Background),
244    (GetDeclaration, Background),
245    (GetDeclarationResponse, Background),
246    (GetDocumentHighlights, Background),
247    (GetDocumentHighlightsResponse, Background),
248    (GetHover, Background),
249    (GetHoverResponse, Background),
250    (GetNotifications, Foreground),
251    (GetNotificationsResponse, Foreground),
252    (GetPrivateUserInfo, Foreground),
253    (GetPrivateUserInfoResponse, Foreground),
254    (GetProjectSymbols, Background),
255    (GetProjectSymbolsResponse, Background),
256    (GetReferences, Background),
257    (GetReferencesResponse, Background),
258    (GetSignatureHelp, Background),
259    (GetSignatureHelpResponse, Background),
260    (GetSupermavenApiKey, Background),
261    (GetSupermavenApiKeyResponse, Background),
262    (GetTypeDefinition, Background),
263    (GetTypeDefinitionResponse, Background),
264    (GetImplementation, Background),
265    (GetImplementationResponse, Background),
266    (GetLlmToken, Background),
267    (GetLlmTokenResponse, Background),
268    (GetUsers, Foreground),
269    (Hello, Foreground),
270    (IncomingCall, Foreground),
271    (InlayHints, Background),
272    (InlayHintsResponse, Background),
273    (InviteChannelMember, Foreground),
274    (JoinChannel, Foreground),
275    (JoinChannelBuffer, Foreground),
276    (JoinChannelBufferResponse, Foreground),
277    (JoinChannelChat, Foreground),
278    (JoinChannelChatResponse, Foreground),
279    (JoinProject, Foreground),
280    (JoinHostedProject, Foreground),
281    (JoinProjectResponse, Foreground),
282    (JoinRoom, Foreground),
283    (JoinRoomResponse, Foreground),
284    (LeaveChannelBuffer, Background),
285    (LeaveChannelChat, Foreground),
286    (LeaveProject, Foreground),
287    (LeaveRoom, Foreground),
288    (MarkNotificationRead, Foreground),
289    (MoveChannel, Foreground),
290    (OnTypeFormatting, Background),
291    (OnTypeFormattingResponse, Background),
292    (OpenBufferById, Background),
293    (OpenBufferByPath, Background),
294    (OpenBufferForSymbol, Background),
295    (OpenBufferForSymbolResponse, Background),
296    (OpenBufferResponse, Background),
297    (PerformRename, Background),
298    (PerformRenameResponse, Background),
299    (Ping, Foreground),
300    (PrepareRename, Background),
301    (PrepareRenameResponse, Background),
302    (ProjectEntryResponse, Foreground),
303    (CountLanguageModelTokens, Background),
304    (CountLanguageModelTokensResponse, Background),
305    (RefreshInlayHints, Foreground),
306    (RejoinChannelBuffers, Foreground),
307    (RejoinChannelBuffersResponse, Foreground),
308    (RejoinRoom, Foreground),
309    (RejoinRoomResponse, Foreground),
310    (ReloadBuffers, Foreground),
311    (ReloadBuffersResponse, Foreground),
312    (RemoveChannelMember, Foreground),
313    (RemoveChannelMessage, Foreground),
314    (UpdateChannelMessage, Foreground),
315    (RemoveContact, Foreground),
316    (RemoveProjectCollaborator, Foreground),
317    (RenameChannel, Foreground),
318    (RenameChannelResponse, Foreground),
319    (RenameProjectEntry, Foreground),
320    (RequestContact, Foreground),
321    (ResolveCompletionDocumentation, Background),
322    (ResolveCompletionDocumentationResponse, Background),
323    (ResolveInlayHint, Background),
324    (ResolveInlayHintResponse, Background),
325    (RespondToChannelInvite, Foreground),
326    (RespondToContactRequest, Foreground),
327    (RoomUpdated, Foreground),
328    (SaveBuffer, Foreground),
329    (SetChannelMemberRole, Foreground),
330    (SetChannelVisibility, Foreground),
331    (SearchProject, Background),
332    (SearchProjectResponse, Background),
333    (SendChannelMessage, Background),
334    (SendChannelMessageResponse, Background),
335    (ShareProject, Foreground),
336    (ShareProjectResponse, Foreground),
337    (ShowContacts, Foreground),
338    (StartLanguageServer, Foreground),
339    (SubscribeToChannels, Foreground),
340    (SynchronizeBuffers, Foreground),
341    (SynchronizeBuffersResponse, Foreground),
342    (TaskContextForLocation, Background),
343    (TaskContext, Background),
344    (TaskTemplates, Background),
345    (TaskTemplatesResponse, Background),
346    (Test, Foreground),
347    (Unfollow, Foreground),
348    (UnshareProject, Foreground),
349    (UpdateBuffer, Foreground),
350    (UpdateBufferFile, Foreground),
351    (UpdateChannelBuffer, Foreground),
352    (UpdateChannelBufferCollaborators, Foreground),
353    (UpdateChannels, Foreground),
354    (UpdateUserChannels, Foreground),
355    (UpdateContacts, Foreground),
356    (UpdateDiagnosticSummary, Foreground),
357    (UpdateDiffBase, Foreground),
358    (UpdateFollowers, Foreground),
359    (UpdateInviteInfo, Foreground),
360    (UpdateLanguageServer, Foreground),
361    (UpdateParticipantLocation, Foreground),
362    (UpdateProject, Foreground),
363    (UpdateProjectCollaborator, Foreground),
364    (UpdateUserPlan, Foreground),
365    (UpdateWorktree, Foreground),
366    (UpdateWorktreeSettings, Foreground),
367    (UsersResponse, Foreground),
368    (LspExtExpandMacro, Background),
369    (LspExtExpandMacroResponse, Background),
370    (SetRoomParticipantRole, Foreground),
371    (BlameBuffer, Foreground),
372    (BlameBufferResponse, Foreground),
373    (CreateDevServerProject, Background),
374    (CreateDevServerProjectResponse, Foreground),
375    (CreateDevServer, Foreground),
376    (CreateDevServerResponse, Foreground),
377    (DevServerInstructions, Foreground),
378    (ShutdownDevServer, Foreground),
379    (ReconnectDevServer, Foreground),
380    (ReconnectDevServerResponse, Foreground),
381    (ShareDevServerProject, Foreground),
382    (JoinDevServerProject, Foreground),
383    (RejoinRemoteProjects, Foreground),
384    (RejoinRemoteProjectsResponse, Foreground),
385    (MultiLspQuery, Background),
386    (MultiLspQueryResponse, Background),
387    (DevServerProjectsUpdate, Foreground),
388    (ValidateDevServerProjectRequest, Background),
389    (ListRemoteDirectory, Background),
390    (ListRemoteDirectoryResponse, Background),
391    (UpdateDevServerProject, Background),
392    (DeleteDevServer, Foreground),
393    (DeleteDevServerProject, Foreground),
394    (RegenerateDevServerToken, Foreground),
395    (RegenerateDevServerTokenResponse, Foreground),
396    (RenameDevServer, Foreground),
397    (OpenNewBuffer, Foreground),
398    (RestartLanguageServers, Foreground),
399    (LinkedEditingRange, Background),
400    (LinkedEditingRangeResponse, Background),
401    (AdvertiseContexts, Foreground),
402    (OpenContext, Foreground),
403    (OpenContextResponse, Foreground),
404    (CreateContext, Foreground),
405    (CreateContextResponse, Foreground),
406    (UpdateContext, Foreground),
407    (SynchronizeContexts, Foreground),
408    (SynchronizeContextsResponse, Foreground),
409    (AddWorktree, Foreground),
410    (AddWorktreeResponse, Foreground),
411);
412
413request_messages!(
414    (AcceptTermsOfService, AcceptTermsOfServiceResponse),
415    (ApplyCodeAction, ApplyCodeActionResponse),
416    (
417        ApplyCompletionAdditionalEdits,
418        ApplyCompletionAdditionalEditsResponse
419    ),
420    (Call, Ack),
421    (CancelCall, Ack),
422    (CopyProjectEntry, ProjectEntryResponse),
423    (ComputeEmbeddings, ComputeEmbeddingsResponse),
424    (CreateChannel, CreateChannelResponse),
425    (CreateProjectEntry, ProjectEntryResponse),
426    (CreateRoom, CreateRoomResponse),
427    (DeclineCall, Ack),
428    (DeleteChannel, Ack),
429    (DeleteProjectEntry, ProjectEntryResponse),
430    (ExpandProjectEntry, ExpandProjectEntryResponse),
431    (Follow, FollowResponse),
432    (FormatBuffers, FormatBuffersResponse),
433    (FuzzySearchUsers, UsersResponse),
434    (GetCachedEmbeddings, GetCachedEmbeddingsResponse),
435    (GetChannelMembers, GetChannelMembersResponse),
436    (GetChannelMessages, GetChannelMessagesResponse),
437    (GetChannelMessagesById, GetChannelMessagesResponse),
438    (GetCodeActions, GetCodeActionsResponse),
439    (GetCompletions, GetCompletionsResponse),
440    (GetDefinition, GetDefinitionResponse),
441    (GetDeclaration, GetDeclarationResponse),
442    (GetImplementation, GetImplementationResponse),
443    (GetDocumentHighlights, GetDocumentHighlightsResponse),
444    (GetHover, GetHoverResponse),
445    (GetLlmToken, GetLlmTokenResponse),
446    (GetNotifications, GetNotificationsResponse),
447    (GetPrivateUserInfo, GetPrivateUserInfoResponse),
448    (GetProjectSymbols, GetProjectSymbolsResponse),
449    (GetReferences, GetReferencesResponse),
450    (GetSignatureHelp, GetSignatureHelpResponse),
451    (GetSupermavenApiKey, GetSupermavenApiKeyResponse),
452    (GetTypeDefinition, GetTypeDefinitionResponse),
453    (LinkedEditingRange, LinkedEditingRangeResponse),
454    (ListRemoteDirectory, ListRemoteDirectoryResponse),
455    (UpdateDevServerProject, Ack),
456    (GetUsers, UsersResponse),
457    (IncomingCall, Ack),
458    (InlayHints, InlayHintsResponse),
459    (InviteChannelMember, Ack),
460    (JoinChannel, JoinRoomResponse),
461    (JoinChannelBuffer, JoinChannelBufferResponse),
462    (JoinChannelChat, JoinChannelChatResponse),
463    (JoinHostedProject, JoinProjectResponse),
464    (JoinProject, JoinProjectResponse),
465    (JoinRoom, JoinRoomResponse),
466    (LeaveChannelBuffer, Ack),
467    (LeaveRoom, Ack),
468    (MarkNotificationRead, Ack),
469    (MoveChannel, Ack),
470    (OnTypeFormatting, OnTypeFormattingResponse),
471    (OpenBufferById, OpenBufferResponse),
472    (OpenBufferByPath, OpenBufferResponse),
473    (OpenBufferForSymbol, OpenBufferForSymbolResponse),
474    (OpenNewBuffer, OpenBufferResponse),
475    (PerformRename, PerformRenameResponse),
476    (Ping, Ack),
477    (PrepareRename, PrepareRenameResponse),
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    GetDeclaration,
552    GetImplementation,
553    GetDocumentHighlights,
554    GetHover,
555    GetProjectSymbols,
556    GetReferences,
557    GetSignatureHelp,
558    GetTypeDefinition,
559    InlayHints,
560    JoinProject,
561    LeaveProject,
562    LinkedEditingRange,
563    MultiLspQuery,
564    RestartLanguageServers,
565    OnTypeFormatting,
566    OpenNewBuffer,
567    OpenBufferById,
568    OpenBufferByPath,
569    OpenBufferForSymbol,
570    PerformRename,
571    PrepareRename,
572    RefreshInlayHints,
573    ReloadBuffers,
574    RemoveProjectCollaborator,
575    RenameProjectEntry,
576    ResolveCompletionDocumentation,
577    ResolveInlayHint,
578    SaveBuffer,
579    SearchProject,
580    StartLanguageServer,
581    SynchronizeBuffers,
582    TaskContextForLocation,
583    TaskTemplates,
584    UnshareProject,
585    UpdateBuffer,
586    UpdateBufferFile,
587    UpdateDiagnosticSummary,
588    UpdateDiffBase,
589    UpdateLanguageServer,
590    UpdateProject,
591    UpdateProjectCollaborator,
592    UpdateWorktree,
593    UpdateWorktreeSettings,
594    LspExtExpandMacro,
595    AdvertiseContexts,
596    OpenContext,
597    CreateContext,
598    UpdateContext,
599    SynchronizeContexts,
600);
601
602entity_messages!(
603    {channel_id, Channel},
604    ChannelMessageSent,
605    ChannelMessageUpdate,
606    RemoveChannelMessage,
607    UpdateChannelMessage,
608    UpdateChannelBuffer,
609    UpdateChannelBufferCollaborators,
610);
611
612impl From<Timestamp> for SystemTime {
613    fn from(val: Timestamp) -> Self {
614        UNIX_EPOCH
615            .checked_add(Duration::new(val.seconds, val.nanos))
616            .unwrap()
617    }
618}
619
620impl From<SystemTime> for Timestamp {
621    fn from(time: SystemTime) -> Self {
622        let duration = time.duration_since(UNIX_EPOCH).unwrap();
623        Self {
624            seconds: duration.as_secs(),
625            nanos: duration.subsec_nanos(),
626        }
627    }
628}
629
630impl From<u128> for Nonce {
631    fn from(nonce: u128) -> Self {
632        let upper_half = (nonce >> 64) as u64;
633        let lower_half = nonce as u64;
634        Self {
635            upper_half,
636            lower_half,
637        }
638    }
639}
640
641impl From<Nonce> for u128 {
642    fn from(nonce: Nonce) -> Self {
643        let upper_half = (nonce.upper_half as u128) << 64;
644        let lower_half = nonce.lower_half as u128;
645        upper_half | lower_half
646    }
647}
648
649pub fn split_worktree_update(
650    mut message: UpdateWorktree,
651    max_chunk_size: usize,
652) -> impl Iterator<Item = UpdateWorktree> {
653    let mut done_files = false;
654
655    let mut repository_map = message
656        .updated_repositories
657        .into_iter()
658        .map(|repo| (repo.work_directory_id, repo))
659        .collect::<HashMap<_, _>>();
660
661    iter::from_fn(move || {
662        if done_files {
663            return None;
664        }
665
666        let updated_entries_chunk_size = cmp::min(message.updated_entries.len(), max_chunk_size);
667        let updated_entries: Vec<_> = message
668            .updated_entries
669            .drain(..updated_entries_chunk_size)
670            .collect();
671
672        let removed_entries_chunk_size = cmp::min(message.removed_entries.len(), max_chunk_size);
673        let removed_entries = message
674            .removed_entries
675            .drain(..removed_entries_chunk_size)
676            .collect();
677
678        done_files = message.updated_entries.is_empty() && message.removed_entries.is_empty();
679
680        let mut updated_repositories = Vec::new();
681
682        if !repository_map.is_empty() {
683            for entry in &updated_entries {
684                if let Some(repo) = repository_map.remove(&entry.id) {
685                    updated_repositories.push(repo)
686                }
687            }
688        }
689
690        let removed_repositories = if done_files {
691            mem::take(&mut message.removed_repositories)
692        } else {
693            Default::default()
694        };
695
696        if done_files {
697            updated_repositories.extend(mem::take(&mut repository_map).into_values());
698        }
699
700        Some(UpdateWorktree {
701            project_id: message.project_id,
702            worktree_id: message.worktree_id,
703            root_name: message.root_name.clone(),
704            abs_path: message.abs_path.clone(),
705            updated_entries,
706            removed_entries,
707            scan_id: message.scan_id,
708            is_last_update: done_files && message.is_last_update,
709            updated_repositories,
710            removed_repositories,
711        })
712    })
713}
714
715#[cfg(test)]
716mod tests {
717    use super::*;
718
719    #[test]
720    fn test_converting_peer_id_from_and_to_u64() {
721        let peer_id = PeerId {
722            owner_id: 10,
723            id: 3,
724        };
725        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
726        let peer_id = PeerId {
727            owner_id: u32::MAX,
728            id: 3,
729        };
730        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
731        let peer_id = PeerId {
732            owner_id: 10,
733            id: u32::MAX,
734        };
735        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
736        let peer_id = PeerId {
737            owner_id: u32::MAX,
738            id: u32::MAX,
739        };
740        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
741    }
742}