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