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