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