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}