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    (LspExtSwitchSourceHeader, Background),
410    (LspExtSwitchSourceHeaderResponse, Background),
411    (AddWorktree, Foreground),
412    (AddWorktreeResponse, Foreground),
413);
414
415request_messages!(
416    (AcceptTermsOfService, AcceptTermsOfServiceResponse),
417    (ApplyCodeAction, ApplyCodeActionResponse),
418    (
419        ApplyCompletionAdditionalEdits,
420        ApplyCompletionAdditionalEditsResponse
421    ),
422    (Call, Ack),
423    (CancelCall, Ack),
424    (CopyProjectEntry, ProjectEntryResponse),
425    (ComputeEmbeddings, ComputeEmbeddingsResponse),
426    (CreateChannel, CreateChannelResponse),
427    (CreateProjectEntry, ProjectEntryResponse),
428    (CreateRoom, CreateRoomResponse),
429    (DeclineCall, Ack),
430    (DeleteChannel, Ack),
431    (DeleteProjectEntry, ProjectEntryResponse),
432    (ExpandProjectEntry, ExpandProjectEntryResponse),
433    (Follow, FollowResponse),
434    (FormatBuffers, FormatBuffersResponse),
435    (FuzzySearchUsers, UsersResponse),
436    (GetCachedEmbeddings, GetCachedEmbeddingsResponse),
437    (GetChannelMembers, GetChannelMembersResponse),
438    (GetChannelMessages, GetChannelMessagesResponse),
439    (GetChannelMessagesById, GetChannelMessagesResponse),
440    (GetCodeActions, GetCodeActionsResponse),
441    (GetCompletions, GetCompletionsResponse),
442    (GetDefinition, GetDefinitionResponse),
443    (GetDeclaration, GetDeclarationResponse),
444    (GetImplementation, GetImplementationResponse),
445    (GetDocumentHighlights, GetDocumentHighlightsResponse),
446    (GetHover, GetHoverResponse),
447    (GetLlmToken, GetLlmTokenResponse),
448    (GetNotifications, GetNotificationsResponse),
449    (GetPrivateUserInfo, GetPrivateUserInfoResponse),
450    (GetProjectSymbols, GetProjectSymbolsResponse),
451    (GetReferences, GetReferencesResponse),
452    (GetSignatureHelp, GetSignatureHelpResponse),
453    (GetSupermavenApiKey, GetSupermavenApiKeyResponse),
454    (GetTypeDefinition, GetTypeDefinitionResponse),
455    (LinkedEditingRange, LinkedEditingRangeResponse),
456    (ListRemoteDirectory, ListRemoteDirectoryResponse),
457    (UpdateDevServerProject, Ack),
458    (GetUsers, UsersResponse),
459    (IncomingCall, Ack),
460    (InlayHints, InlayHintsResponse),
461    (InviteChannelMember, Ack),
462    (JoinChannel, JoinRoomResponse),
463    (JoinChannelBuffer, JoinChannelBufferResponse),
464    (JoinChannelChat, JoinChannelChatResponse),
465    (JoinHostedProject, JoinProjectResponse),
466    (JoinProject, JoinProjectResponse),
467    (JoinRoom, JoinRoomResponse),
468    (LeaveChannelBuffer, Ack),
469    (LeaveRoom, Ack),
470    (MarkNotificationRead, Ack),
471    (MoveChannel, Ack),
472    (OnTypeFormatting, OnTypeFormattingResponse),
473    (OpenBufferById, OpenBufferResponse),
474    (OpenBufferByPath, OpenBufferResponse),
475    (OpenBufferForSymbol, OpenBufferForSymbolResponse),
476    (OpenNewBuffer, OpenBufferResponse),
477    (PerformRename, PerformRenameResponse),
478    (Ping, Ack),
479    (PrepareRename, PrepareRenameResponse),
480    (CountLanguageModelTokens, CountLanguageModelTokensResponse),
481    (RefreshInlayHints, Ack),
482    (RejoinChannelBuffers, RejoinChannelBuffersResponse),
483    (RejoinRoom, RejoinRoomResponse),
484    (ReloadBuffers, ReloadBuffersResponse),
485    (RemoveChannelMember, Ack),
486    (RemoveChannelMessage, Ack),
487    (UpdateChannelMessage, Ack),
488    (RemoveContact, Ack),
489    (RenameChannel, RenameChannelResponse),
490    (RenameProjectEntry, ProjectEntryResponse),
491    (RequestContact, Ack),
492    (
493        ResolveCompletionDocumentation,
494        ResolveCompletionDocumentationResponse
495    ),
496    (ResolveInlayHint, ResolveInlayHintResponse),
497    (RespondToChannelInvite, Ack),
498    (RespondToContactRequest, Ack),
499    (SaveBuffer, BufferSaved),
500    (SearchProject, SearchProjectResponse),
501    (SendChannelMessage, SendChannelMessageResponse),
502    (SetChannelMemberRole, Ack),
503    (SetChannelVisibility, Ack),
504    (ShareProject, ShareProjectResponse),
505    (SynchronizeBuffers, SynchronizeBuffersResponse),
506    (TaskContextForLocation, TaskContext),
507    (TaskTemplates, TaskTemplatesResponse),
508    (Test, Test),
509    (UpdateBuffer, Ack),
510    (UpdateParticipantLocation, Ack),
511    (UpdateProject, Ack),
512    (UpdateWorktree, Ack),
513    (LspExtExpandMacro, LspExtExpandMacroResponse),
514    (SetRoomParticipantRole, Ack),
515    (BlameBuffer, BlameBufferResponse),
516    (CreateDevServerProject, CreateDevServerProjectResponse),
517    (CreateDevServer, CreateDevServerResponse),
518    (ShutdownDevServer, Ack),
519    (ShareDevServerProject, ShareProjectResponse),
520    (JoinDevServerProject, JoinProjectResponse),
521    (RejoinRemoteProjects, RejoinRemoteProjectsResponse),
522    (ReconnectDevServer, ReconnectDevServerResponse),
523    (ValidateDevServerProjectRequest, Ack),
524    (MultiLspQuery, MultiLspQueryResponse),
525    (DeleteDevServer, Ack),
526    (DeleteDevServerProject, Ack),
527    (RegenerateDevServerToken, RegenerateDevServerTokenResponse),
528    (RenameDevServer, Ack),
529    (RestartLanguageServers, Ack),
530    (OpenContext, OpenContextResponse),
531    (CreateContext, CreateContextResponse),
532    (SynchronizeContexts, SynchronizeContextsResponse),
533    (LspExtSwitchSourceHeader, LspExtSwitchSourceHeaderResponse),
534    (AddWorktree, AddWorktreeResponse),
535);
536
537entity_messages!(
538    {project_id, ShareProject},
539    AddProjectCollaborator,
540    ApplyCodeAction,
541    ApplyCompletionAdditionalEdits,
542    BlameBuffer,
543    BufferReloaded,
544    BufferSaved,
545    CopyProjectEntry,
546    CreateBufferForPeer,
547    CreateProjectEntry,
548    DeleteProjectEntry,
549    ExpandProjectEntry,
550    FormatBuffers,
551    GetCodeActions,
552    GetCompletions,
553    GetDefinition,
554    GetDeclaration,
555    GetImplementation,
556    GetDocumentHighlights,
557    GetHover,
558    GetProjectSymbols,
559    GetReferences,
560    GetSignatureHelp,
561    GetTypeDefinition,
562    InlayHints,
563    JoinProject,
564    LeaveProject,
565    LinkedEditingRange,
566    MultiLspQuery,
567    RestartLanguageServers,
568    OnTypeFormatting,
569    OpenNewBuffer,
570    OpenBufferById,
571    OpenBufferByPath,
572    OpenBufferForSymbol,
573    PerformRename,
574    PrepareRename,
575    RefreshInlayHints,
576    ReloadBuffers,
577    RemoveProjectCollaborator,
578    RenameProjectEntry,
579    ResolveCompletionDocumentation,
580    ResolveInlayHint,
581    SaveBuffer,
582    SearchProject,
583    StartLanguageServer,
584    SynchronizeBuffers,
585    TaskContextForLocation,
586    TaskTemplates,
587    UnshareProject,
588    UpdateBuffer,
589    UpdateBufferFile,
590    UpdateDiagnosticSummary,
591    UpdateDiffBase,
592    UpdateLanguageServer,
593    UpdateProject,
594    UpdateProjectCollaborator,
595    UpdateWorktree,
596    UpdateWorktreeSettings,
597    LspExtExpandMacro,
598    AdvertiseContexts,
599    OpenContext,
600    CreateContext,
601    UpdateContext,
602    SynchronizeContexts,
603    LspExtSwitchSourceHeader
604);
605
606entity_messages!(
607    {channel_id, Channel},
608    ChannelMessageSent,
609    ChannelMessageUpdate,
610    RemoveChannelMessage,
611    UpdateChannelMessage,
612    UpdateChannelBuffer,
613    UpdateChannelBufferCollaborators,
614);
615
616impl From<Timestamp> for SystemTime {
617    fn from(val: Timestamp) -> Self {
618        UNIX_EPOCH
619            .checked_add(Duration::new(val.seconds, val.nanos))
620            .unwrap()
621    }
622}
623
624impl From<SystemTime> for Timestamp {
625    fn from(time: SystemTime) -> Self {
626        let duration = time.duration_since(UNIX_EPOCH).unwrap();
627        Self {
628            seconds: duration.as_secs(),
629            nanos: duration.subsec_nanos(),
630        }
631    }
632}
633
634impl From<u128> for Nonce {
635    fn from(nonce: u128) -> Self {
636        let upper_half = (nonce >> 64) as u64;
637        let lower_half = nonce as u64;
638        Self {
639            upper_half,
640            lower_half,
641        }
642    }
643}
644
645impl From<Nonce> for u128 {
646    fn from(nonce: Nonce) -> Self {
647        let upper_half = (nonce.upper_half as u128) << 64;
648        let lower_half = nonce.lower_half as u128;
649        upper_half | lower_half
650    }
651}
652
653pub fn split_worktree_update(
654    mut message: UpdateWorktree,
655    max_chunk_size: usize,
656) -> impl Iterator<Item = UpdateWorktree> {
657    let mut done_files = false;
658
659    let mut repository_map = message
660        .updated_repositories
661        .into_iter()
662        .map(|repo| (repo.work_directory_id, repo))
663        .collect::<HashMap<_, _>>();
664
665    iter::from_fn(move || {
666        if done_files {
667            return None;
668        }
669
670        let updated_entries_chunk_size = cmp::min(message.updated_entries.len(), max_chunk_size);
671        let updated_entries: Vec<_> = message
672            .updated_entries
673            .drain(..updated_entries_chunk_size)
674            .collect();
675
676        let removed_entries_chunk_size = cmp::min(message.removed_entries.len(), max_chunk_size);
677        let removed_entries = message
678            .removed_entries
679            .drain(..removed_entries_chunk_size)
680            .collect();
681
682        done_files = message.updated_entries.is_empty() && message.removed_entries.is_empty();
683
684        let mut updated_repositories = Vec::new();
685
686        if !repository_map.is_empty() {
687            for entry in &updated_entries {
688                if let Some(repo) = repository_map.remove(&entry.id) {
689                    updated_repositories.push(repo)
690                }
691            }
692        }
693
694        let removed_repositories = if done_files {
695            mem::take(&mut message.removed_repositories)
696        } else {
697            Default::default()
698        };
699
700        if done_files {
701            updated_repositories.extend(mem::take(&mut repository_map).into_values());
702        }
703
704        Some(UpdateWorktree {
705            project_id: message.project_id,
706            worktree_id: message.worktree_id,
707            root_name: message.root_name.clone(),
708            abs_path: message.abs_path.clone(),
709            updated_entries,
710            removed_entries,
711            scan_id: message.scan_id,
712            is_last_update: done_files && message.is_last_update,
713            updated_repositories,
714            removed_repositories,
715        })
716    })
717}
718
719#[cfg(test)]
720mod tests {
721    use super::*;
722
723    #[test]
724    fn test_converting_peer_id_from_and_to_u64() {
725        let peer_id = PeerId {
726            owner_id: 10,
727            id: 3,
728        };
729        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
730        let peer_id = PeerId {
731            owner_id: u32::MAX,
732            id: 3,
733        };
734        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
735        let peer_id = PeerId {
736            owner_id: 10,
737            id: u32::MAX,
738        };
739        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
740        let peer_id = PeerId {
741            owner_id: u32::MAX,
742            id: u32::MAX,
743        };
744        assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
745    }
746}