1#![allow(non_snake_case)]
2
3pub mod error;
4mod macros;
5mod typed_envelope;
6
7pub use error::*;
8pub use typed_envelope::*;
9
10use anyhow::anyhow;
11use collections::HashMap;
12use futures::{future::BoxFuture, Future};
13pub use prost::{DecodeError, Message};
14use serde::Serialize;
15use std::{
16 any::{Any, TypeId},
17 cmp,
18 fmt::{self, Debug},
19 iter, mem,
20 sync::Arc,
21 time::{Duration, SystemTime, UNIX_EPOCH},
22};
23
24include!(concat!(env!("OUT_DIR"), "/zed.messages.rs"));
25
26pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static {
27 const NAME: &'static str;
28 const PRIORITY: MessagePriority;
29 fn into_envelope(
30 self,
31 id: u32,
32 responding_to: Option<u32>,
33 original_sender_id: Option<PeerId>,
34 ) -> Envelope;
35 fn from_envelope(envelope: Envelope) -> Option<Self>;
36}
37
38pub trait EntityMessage: EnvelopedMessage {
39 type Entity;
40 fn remote_entity_id(&self) -> u64;
41}
42
43pub trait RequestMessage: EnvelopedMessage {
44 type Response: EnvelopedMessage;
45}
46
47pub trait AnyTypedEnvelope: 'static + Send + Sync {
48 fn payload_type_id(&self) -> TypeId;
49 fn payload_type_name(&self) -> &'static str;
50 fn as_any(&self) -> &dyn Any;
51 fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
52 fn is_background(&self) -> bool;
53 fn original_sender_id(&self) -> Option<PeerId>;
54 fn sender_id(&self) -> PeerId;
55 fn message_id(&self) -> u32;
56}
57
58pub enum MessagePriority {
59 Foreground,
60 Background,
61}
62
63pub trait ProtoClient: Send + Sync {
64 fn request(
65 &self,
66 envelope: Envelope,
67 request_type: &'static str,
68 ) -> BoxFuture<'static, anyhow::Result<Envelope>>;
69
70 fn send(&self, envelope: Envelope) -> anyhow::Result<()>;
71}
72
73#[derive(Clone)]
74pub struct AnyProtoClient(Arc<dyn ProtoClient>);
75
76impl<T> From<Arc<T>> for AnyProtoClient
77where
78 T: ProtoClient + 'static,
79{
80 fn from(client: Arc<T>) -> Self {
81 Self(client)
82 }
83}
84
85impl AnyProtoClient {
86 pub fn new<T: ProtoClient + 'static>(client: Arc<T>) -> Self {
87 Self(client)
88 }
89
90 pub fn request<T: RequestMessage>(
91 &self,
92 request: T,
93 ) -> impl Future<Output = anyhow::Result<T::Response>> {
94 let envelope = request.into_envelope(0, None, None);
95 let response = self.0.request(envelope, T::NAME);
96 async move {
97 T::Response::from_envelope(response.await?)
98 .ok_or_else(|| anyhow!("received response of the wrong type"))
99 }
100 }
101
102 pub fn send<T: EnvelopedMessage>(&self, request: T) -> anyhow::Result<()> {
103 let envelope = request.into_envelope(0, None, None);
104 self.0.send(envelope)
105 }
106
107 pub fn send_dynamic(&self, message: Envelope) -> anyhow::Result<()> {
108 self.0.send(message)
109 }
110}
111
112impl<T: EnvelopedMessage> AnyTypedEnvelope for TypedEnvelope<T> {
113 fn payload_type_id(&self) -> TypeId {
114 TypeId::of::<T>()
115 }
116
117 fn payload_type_name(&self) -> &'static str {
118 T::NAME
119 }
120
121 fn as_any(&self) -> &dyn Any {
122 self
123 }
124
125 fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
126 self
127 }
128
129 fn is_background(&self) -> bool {
130 matches!(T::PRIORITY, MessagePriority::Background)
131 }
132
133 fn original_sender_id(&self) -> Option<PeerId> {
134 self.original_sender_id
135 }
136
137 fn sender_id(&self) -> PeerId {
138 self.sender_id
139 }
140
141 fn message_id(&self) -> u32 {
142 self.message_id
143 }
144}
145
146impl PeerId {
147 pub fn from_u64(peer_id: u64) -> Self {
148 let owner_id = (peer_id >> 32) as u32;
149 let id = peer_id as u32;
150 Self { owner_id, id }
151 }
152
153 pub fn as_u64(self) -> u64 {
154 ((self.owner_id as u64) << 32) | (self.id as u64)
155 }
156}
157
158impl Copy for PeerId {}
159
160impl Eq for PeerId {}
161
162impl Ord for PeerId {
163 fn cmp(&self, other: &Self) -> cmp::Ordering {
164 self.owner_id
165 .cmp(&other.owner_id)
166 .then_with(|| self.id.cmp(&other.id))
167 }
168}
169
170impl PartialOrd for PeerId {
171 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
172 Some(self.cmp(other))
173 }
174}
175
176impl std::hash::Hash for PeerId {
177 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
178 self.owner_id.hash(state);
179 self.id.hash(state);
180 }
181}
182
183impl fmt::Display for PeerId {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 write!(f, "{}/{}", self.owner_id, self.id)
186 }
187}
188
189messages!(
190 (Ack, Foreground),
191 (AckBufferOperation, Background),
192 (AckChannelMessage, Background),
193 (AddNotification, Foreground),
194 (AddProjectCollaborator, Foreground),
195 (ApplyCodeAction, Background),
196 (ApplyCodeActionResponse, Background),
197 (ApplyCompletionAdditionalEdits, Background),
198 (ApplyCompletionAdditionalEditsResponse, Background),
199 (BufferReloaded, Foreground),
200 (BufferSaved, Foreground),
201 (Call, Foreground),
202 (CallCanceled, Foreground),
203 (CancelCall, Foreground),
204 (ChannelMessageSent, Foreground),
205 (ChannelMessageUpdate, Foreground),
206 (ComputeEmbeddings, Background),
207 (ComputeEmbeddingsResponse, Background),
208 (CopyProjectEntry, Foreground),
209 (CreateBufferForPeer, Foreground),
210 (CreateChannel, Foreground),
211 (CreateChannelResponse, Foreground),
212 (CreateProjectEntry, Foreground),
213 (CreateRoom, Foreground),
214 (CreateRoomResponse, Foreground),
215 (DeclineCall, Foreground),
216 (DeleteChannel, Foreground),
217 (DeleteNotification, Foreground),
218 (UpdateNotification, Foreground),
219 (DeleteProjectEntry, Foreground),
220 (EndStream, Foreground),
221 (Error, Foreground),
222 (ExpandProjectEntry, Foreground),
223 (ExpandProjectEntryResponse, Foreground),
224 (Follow, Foreground),
225 (FollowResponse, Foreground),
226 (FormatBuffers, Foreground),
227 (FormatBuffersResponse, Foreground),
228 (FuzzySearchUsers, Foreground),
229 (GetCachedEmbeddings, Background),
230 (GetCachedEmbeddingsResponse, Background),
231 (GetChannelMembers, Foreground),
232 (GetChannelMembersResponse, Foreground),
233 (GetChannelMessages, Background),
234 (GetChannelMessagesById, Background),
235 (GetChannelMessagesResponse, Background),
236 (GetCodeActions, Background),
237 (GetCodeActionsResponse, Background),
238 (GetCompletions, Background),
239 (GetCompletionsResponse, Background),
240 (GetDefinition, Background),
241 (GetDefinitionResponse, Background),
242 (GetDeclaration, Background),
243 (GetDeclarationResponse, Background),
244 (GetDocumentHighlights, Background),
245 (GetDocumentHighlightsResponse, Background),
246 (GetHover, Background),
247 (GetHoverResponse, Background),
248 (GetNotifications, Foreground),
249 (GetNotificationsResponse, Foreground),
250 (GetPrivateUserInfo, Foreground),
251 (GetPrivateUserInfoResponse, Foreground),
252 (GetProjectSymbols, Background),
253 (GetProjectSymbolsResponse, Background),
254 (GetReferences, Background),
255 (GetReferencesResponse, Background),
256 (GetSignatureHelp, Background),
257 (GetSignatureHelpResponse, Background),
258 (GetSupermavenApiKey, Background),
259 (GetSupermavenApiKeyResponse, Background),
260 (GetTypeDefinition, Background),
261 (GetTypeDefinitionResponse, Background),
262 (GetImplementation, Background),
263 (GetImplementationResponse, Background),
264 (GetLlmToken, Background),
265 (GetLlmTokenResponse, Background),
266 (GetUsers, Foreground),
267 (Hello, Foreground),
268 (IncomingCall, Foreground),
269 (InlayHints, Background),
270 (InlayHintsResponse, Background),
271 (InviteChannelMember, Foreground),
272 (JoinChannel, Foreground),
273 (JoinChannelBuffer, Foreground),
274 (JoinChannelBufferResponse, Foreground),
275 (JoinChannelChat, Foreground),
276 (JoinChannelChatResponse, Foreground),
277 (JoinProject, Foreground),
278 (JoinHostedProject, Foreground),
279 (JoinProjectResponse, Foreground),
280 (JoinRoom, Foreground),
281 (JoinRoomResponse, Foreground),
282 (LeaveChannelBuffer, Background),
283 (LeaveChannelChat, Foreground),
284 (LeaveProject, Foreground),
285 (LeaveRoom, Foreground),
286 (MarkNotificationRead, Foreground),
287 (MoveChannel, Foreground),
288 (OnTypeFormatting, Background),
289 (OnTypeFormattingResponse, Background),
290 (OpenBufferById, Background),
291 (OpenBufferByPath, Background),
292 (OpenBufferForSymbol, Background),
293 (OpenBufferForSymbolResponse, Background),
294 (OpenBufferResponse, Background),
295 (PerformRename, Background),
296 (PerformRenameResponse, Background),
297 (Ping, Foreground),
298 (PrepareRename, Background),
299 (PrepareRenameResponse, Background),
300 (ProjectEntryResponse, Foreground),
301 (CompleteWithLanguageModel, Background),
302 (CompleteWithLanguageModelResponse, Background),
303 (StreamCompleteWithLanguageModel, Background),
304 (StreamCompleteWithLanguageModelResponse, Background),
305 (CountLanguageModelTokens, Background),
306 (CountLanguageModelTokensResponse, Background),
307 (RefreshInlayHints, Foreground),
308 (RejoinChannelBuffers, Foreground),
309 (RejoinChannelBuffersResponse, Foreground),
310 (RejoinRoom, Foreground),
311 (RejoinRoomResponse, Foreground),
312 (ReloadBuffers, Foreground),
313 (ReloadBuffersResponse, Foreground),
314 (RemoveChannelMember, Foreground),
315 (RemoveChannelMessage, Foreground),
316 (UpdateChannelMessage, Foreground),
317 (RemoveContact, Foreground),
318 (RemoveProjectCollaborator, Foreground),
319 (RenameChannel, Foreground),
320 (RenameChannelResponse, Foreground),
321 (RenameProjectEntry, Foreground),
322 (RequestContact, Foreground),
323 (ResolveCompletionDocumentation, Background),
324 (ResolveCompletionDocumentationResponse, Background),
325 (ResolveInlayHint, Background),
326 (ResolveInlayHintResponse, Background),
327 (RespondToChannelInvite, Foreground),
328 (RespondToContactRequest, Foreground),
329 (RoomUpdated, Foreground),
330 (SaveBuffer, Foreground),
331 (SetChannelMemberRole, Foreground),
332 (SetChannelVisibility, Foreground),
333 (SearchProject, Background),
334 (SearchProjectResponse, Background),
335 (SendChannelMessage, Background),
336 (SendChannelMessageResponse, Background),
337 (ShareProject, Foreground),
338 (ShareProjectResponse, Foreground),
339 (ShowContacts, Foreground),
340 (StartLanguageServer, Foreground),
341 (SubscribeToChannels, Foreground),
342 (SynchronizeBuffers, Foreground),
343 (SynchronizeBuffersResponse, Foreground),
344 (TaskContextForLocation, Background),
345 (TaskContext, Background),
346 (TaskTemplates, Background),
347 (TaskTemplatesResponse, Background),
348 (Test, Foreground),
349 (Unfollow, Foreground),
350 (UnshareProject, Foreground),
351 (UpdateBuffer, Foreground),
352 (UpdateBufferFile, Foreground),
353 (UpdateChannelBuffer, Foreground),
354 (UpdateChannelBufferCollaborators, Foreground),
355 (UpdateChannels, Foreground),
356 (UpdateUserChannels, Foreground),
357 (UpdateContacts, Foreground),
358 (UpdateDiagnosticSummary, Foreground),
359 (UpdateDiffBase, Foreground),
360 (UpdateFollowers, Foreground),
361 (UpdateInviteInfo, Foreground),
362 (UpdateLanguageServer, Foreground),
363 (UpdateParticipantLocation, Foreground),
364 (UpdateProject, Foreground),
365 (UpdateProjectCollaborator, Foreground),
366 (UpdateUserPlan, Foreground),
367 (UpdateWorktree, Foreground),
368 (UpdateWorktreeSettings, Foreground),
369 (UsersResponse, Foreground),
370 (LspExtExpandMacro, Background),
371 (LspExtExpandMacroResponse, Background),
372 (SetRoomParticipantRole, Foreground),
373 (BlameBuffer, Foreground),
374 (BlameBufferResponse, Foreground),
375 (CreateDevServerProject, Background),
376 (CreateDevServerProjectResponse, Foreground),
377 (CreateDevServer, Foreground),
378 (CreateDevServerResponse, Foreground),
379 (DevServerInstructions, Foreground),
380 (ShutdownDevServer, Foreground),
381 (ReconnectDevServer, Foreground),
382 (ReconnectDevServerResponse, Foreground),
383 (ShareDevServerProject, Foreground),
384 (JoinDevServerProject, Foreground),
385 (RejoinRemoteProjects, Foreground),
386 (RejoinRemoteProjectsResponse, Foreground),
387 (MultiLspQuery, Background),
388 (MultiLspQueryResponse, Background),
389 (DevServerProjectsUpdate, Foreground),
390 (ValidateDevServerProjectRequest, Background),
391 (ListRemoteDirectory, Background),
392 (ListRemoteDirectoryResponse, Background),
393 (UpdateDevServerProject, Background),
394 (DeleteDevServer, Foreground),
395 (DeleteDevServerProject, Foreground),
396 (RegenerateDevServerToken, Foreground),
397 (RegenerateDevServerTokenResponse, Foreground),
398 (RenameDevServer, Foreground),
399 (OpenNewBuffer, Foreground),
400 (RestartLanguageServers, Foreground),
401 (LinkedEditingRange, Background),
402 (LinkedEditingRangeResponse, Background),
403 (AdvertiseContexts, Foreground),
404 (OpenContext, Foreground),
405 (OpenContextResponse, Foreground),
406 (CreateContext, Foreground),
407 (CreateContextResponse, Foreground),
408 (UpdateContext, Foreground),
409 (SynchronizeContexts, Foreground),
410 (SynchronizeContextsResponse, Foreground),
411 (AddWorktree, Foreground),
412 (AddWorktreeResponse, Foreground),
413);
414
415request_messages!(
416 (ApplyCodeAction, ApplyCodeActionResponse),
417 (
418 ApplyCompletionAdditionalEdits,
419 ApplyCompletionAdditionalEditsResponse
420 ),
421 (Call, Ack),
422 (CancelCall, Ack),
423 (CopyProjectEntry, ProjectEntryResponse),
424 (ComputeEmbeddings, ComputeEmbeddingsResponse),
425 (CreateChannel, CreateChannelResponse),
426 (CreateProjectEntry, ProjectEntryResponse),
427 (CreateRoom, CreateRoomResponse),
428 (DeclineCall, Ack),
429 (DeleteChannel, Ack),
430 (DeleteProjectEntry, ProjectEntryResponse),
431 (ExpandProjectEntry, ExpandProjectEntryResponse),
432 (Follow, FollowResponse),
433 (FormatBuffers, FormatBuffersResponse),
434 (FuzzySearchUsers, UsersResponse),
435 (GetCachedEmbeddings, GetCachedEmbeddingsResponse),
436 (GetChannelMembers, GetChannelMembersResponse),
437 (GetChannelMessages, GetChannelMessagesResponse),
438 (GetChannelMessagesById, GetChannelMessagesResponse),
439 (GetCodeActions, GetCodeActionsResponse),
440 (GetCompletions, GetCompletionsResponse),
441 (GetDefinition, GetDefinitionResponse),
442 (GetDeclaration, GetDeclarationResponse),
443 (GetImplementation, GetImplementationResponse),
444 (GetDocumentHighlights, GetDocumentHighlightsResponse),
445 (GetHover, GetHoverResponse),
446 (GetLlmToken, GetLlmTokenResponse),
447 (GetNotifications, GetNotificationsResponse),
448 (GetPrivateUserInfo, GetPrivateUserInfoResponse),
449 (GetProjectSymbols, GetProjectSymbolsResponse),
450 (GetReferences, GetReferencesResponse),
451 (GetSignatureHelp, GetSignatureHelpResponse),
452 (GetSupermavenApiKey, GetSupermavenApiKeyResponse),
453 (GetTypeDefinition, GetTypeDefinitionResponse),
454 (LinkedEditingRange, LinkedEditingRangeResponse),
455 (ListRemoteDirectory, ListRemoteDirectoryResponse),
456 (UpdateDevServerProject, Ack),
457 (GetUsers, UsersResponse),
458 (IncomingCall, Ack),
459 (InlayHints, InlayHintsResponse),
460 (InviteChannelMember, Ack),
461 (JoinChannel, JoinRoomResponse),
462 (JoinChannelBuffer, JoinChannelBufferResponse),
463 (JoinChannelChat, JoinChannelChatResponse),
464 (JoinHostedProject, JoinProjectResponse),
465 (JoinProject, JoinProjectResponse),
466 (JoinRoom, JoinRoomResponse),
467 (LeaveChannelBuffer, Ack),
468 (LeaveRoom, Ack),
469 (MarkNotificationRead, Ack),
470 (MoveChannel, Ack),
471 (OnTypeFormatting, OnTypeFormattingResponse),
472 (OpenBufferById, OpenBufferResponse),
473 (OpenBufferByPath, OpenBufferResponse),
474 (OpenBufferForSymbol, OpenBufferForSymbolResponse),
475 (OpenNewBuffer, OpenBufferResponse),
476 (PerformRename, PerformRenameResponse),
477 (Ping, Ack),
478 (PrepareRename, PrepareRenameResponse),
479 (CompleteWithLanguageModel, CompleteWithLanguageModelResponse),
480 (
481 StreamCompleteWithLanguageModel,
482 StreamCompleteWithLanguageModelResponse
483 ),
484 (CountLanguageModelTokens, CountLanguageModelTokensResponse),
485 (RefreshInlayHints, Ack),
486 (RejoinChannelBuffers, RejoinChannelBuffersResponse),
487 (RejoinRoom, RejoinRoomResponse),
488 (ReloadBuffers, ReloadBuffersResponse),
489 (RemoveChannelMember, Ack),
490 (RemoveChannelMessage, Ack),
491 (UpdateChannelMessage, Ack),
492 (RemoveContact, Ack),
493 (RenameChannel, RenameChannelResponse),
494 (RenameProjectEntry, ProjectEntryResponse),
495 (RequestContact, Ack),
496 (
497 ResolveCompletionDocumentation,
498 ResolveCompletionDocumentationResponse
499 ),
500 (ResolveInlayHint, ResolveInlayHintResponse),
501 (RespondToChannelInvite, Ack),
502 (RespondToContactRequest, Ack),
503 (SaveBuffer, BufferSaved),
504 (SearchProject, SearchProjectResponse),
505 (SendChannelMessage, SendChannelMessageResponse),
506 (SetChannelMemberRole, Ack),
507 (SetChannelVisibility, Ack),
508 (ShareProject, ShareProjectResponse),
509 (SynchronizeBuffers, SynchronizeBuffersResponse),
510 (TaskContextForLocation, TaskContext),
511 (TaskTemplates, TaskTemplatesResponse),
512 (Test, Test),
513 (UpdateBuffer, Ack),
514 (UpdateParticipantLocation, Ack),
515 (UpdateProject, Ack),
516 (UpdateWorktree, Ack),
517 (LspExtExpandMacro, LspExtExpandMacroResponse),
518 (SetRoomParticipantRole, Ack),
519 (BlameBuffer, BlameBufferResponse),
520 (CreateDevServerProject, CreateDevServerProjectResponse),
521 (CreateDevServer, CreateDevServerResponse),
522 (ShutdownDevServer, Ack),
523 (ShareDevServerProject, ShareProjectResponse),
524 (JoinDevServerProject, JoinProjectResponse),
525 (RejoinRemoteProjects, RejoinRemoteProjectsResponse),
526 (ReconnectDevServer, ReconnectDevServerResponse),
527 (ValidateDevServerProjectRequest, Ack),
528 (MultiLspQuery, MultiLspQueryResponse),
529 (DeleteDevServer, Ack),
530 (DeleteDevServerProject, Ack),
531 (RegenerateDevServerToken, RegenerateDevServerTokenResponse),
532 (RenameDevServer, Ack),
533 (RestartLanguageServers, Ack),
534 (OpenContext, OpenContextResponse),
535 (CreateContext, CreateContextResponse),
536 (SynchronizeContexts, SynchronizeContextsResponse),
537 (AddWorktree, AddWorktreeResponse),
538);
539
540entity_messages!(
541 {project_id, ShareProject},
542 AddProjectCollaborator,
543 ApplyCodeAction,
544 ApplyCompletionAdditionalEdits,
545 BlameBuffer,
546 BufferReloaded,
547 BufferSaved,
548 CopyProjectEntry,
549 CreateBufferForPeer,
550 CreateProjectEntry,
551 DeleteProjectEntry,
552 ExpandProjectEntry,
553 FormatBuffers,
554 GetCodeActions,
555 GetCompletions,
556 GetDefinition,
557 GetDeclaration,
558 GetImplementation,
559 GetDocumentHighlights,
560 GetHover,
561 GetProjectSymbols,
562 GetReferences,
563 GetSignatureHelp,
564 GetTypeDefinition,
565 InlayHints,
566 JoinProject,
567 LeaveProject,
568 LinkedEditingRange,
569 MultiLspQuery,
570 RestartLanguageServers,
571 OnTypeFormatting,
572 OpenNewBuffer,
573 OpenBufferById,
574 OpenBufferByPath,
575 OpenBufferForSymbol,
576 PerformRename,
577 PrepareRename,
578 RefreshInlayHints,
579 ReloadBuffers,
580 RemoveProjectCollaborator,
581 RenameProjectEntry,
582 ResolveCompletionDocumentation,
583 ResolveInlayHint,
584 SaveBuffer,
585 SearchProject,
586 StartLanguageServer,
587 SynchronizeBuffers,
588 TaskContextForLocation,
589 TaskTemplates,
590 UnshareProject,
591 UpdateBuffer,
592 UpdateBufferFile,
593 UpdateDiagnosticSummary,
594 UpdateDiffBase,
595 UpdateLanguageServer,
596 UpdateProject,
597 UpdateProjectCollaborator,
598 UpdateWorktree,
599 UpdateWorktreeSettings,
600 LspExtExpandMacro,
601 AdvertiseContexts,
602 OpenContext,
603 CreateContext,
604 UpdateContext,
605 SynchronizeContexts,
606);
607
608entity_messages!(
609 {channel_id, Channel},
610 ChannelMessageSent,
611 ChannelMessageUpdate,
612 RemoveChannelMessage,
613 UpdateChannelMessage,
614 UpdateChannelBuffer,
615 UpdateChannelBufferCollaborators,
616);
617
618impl From<Timestamp> for SystemTime {
619 fn from(val: Timestamp) -> Self {
620 UNIX_EPOCH
621 .checked_add(Duration::new(val.seconds, val.nanos))
622 .unwrap()
623 }
624}
625
626impl From<SystemTime> for Timestamp {
627 fn from(time: SystemTime) -> Self {
628 let duration = time.duration_since(UNIX_EPOCH).unwrap();
629 Self {
630 seconds: duration.as_secs(),
631 nanos: duration.subsec_nanos(),
632 }
633 }
634}
635
636impl From<u128> for Nonce {
637 fn from(nonce: u128) -> Self {
638 let upper_half = (nonce >> 64) as u64;
639 let lower_half = nonce as u64;
640 Self {
641 upper_half,
642 lower_half,
643 }
644 }
645}
646
647impl From<Nonce> for u128 {
648 fn from(nonce: Nonce) -> Self {
649 let upper_half = (nonce.upper_half as u128) << 64;
650 let lower_half = nonce.lower_half as u128;
651 upper_half | lower_half
652 }
653}
654
655pub fn split_worktree_update(
656 mut message: UpdateWorktree,
657 max_chunk_size: usize,
658) -> impl Iterator<Item = UpdateWorktree> {
659 let mut done_files = false;
660
661 let mut repository_map = message
662 .updated_repositories
663 .into_iter()
664 .map(|repo| (repo.work_directory_id, repo))
665 .collect::<HashMap<_, _>>();
666
667 iter::from_fn(move || {
668 if done_files {
669 return None;
670 }
671
672 let updated_entries_chunk_size = cmp::min(message.updated_entries.len(), max_chunk_size);
673 let updated_entries: Vec<_> = message
674 .updated_entries
675 .drain(..updated_entries_chunk_size)
676 .collect();
677
678 let removed_entries_chunk_size = cmp::min(message.removed_entries.len(), max_chunk_size);
679 let removed_entries = message
680 .removed_entries
681 .drain(..removed_entries_chunk_size)
682 .collect();
683
684 done_files = message.updated_entries.is_empty() && message.removed_entries.is_empty();
685
686 let mut updated_repositories = Vec::new();
687
688 if !repository_map.is_empty() {
689 for entry in &updated_entries {
690 if let Some(repo) = repository_map.remove(&entry.id) {
691 updated_repositories.push(repo)
692 }
693 }
694 }
695
696 let removed_repositories = if done_files {
697 mem::take(&mut message.removed_repositories)
698 } else {
699 Default::default()
700 };
701
702 if done_files {
703 updated_repositories.extend(mem::take(&mut repository_map).into_values());
704 }
705
706 Some(UpdateWorktree {
707 project_id: message.project_id,
708 worktree_id: message.worktree_id,
709 root_name: message.root_name.clone(),
710 abs_path: message.abs_path.clone(),
711 updated_entries,
712 removed_entries,
713 scan_id: message.scan_id,
714 is_last_update: done_files && message.is_last_update,
715 updated_repositories,
716 removed_repositories,
717 })
718 })
719}
720
721#[cfg(test)]
722mod tests {
723 use super::*;
724
725 #[test]
726 fn test_converting_peer_id_from_and_to_u64() {
727 let peer_id = PeerId {
728 owner_id: 10,
729 id: 3,
730 };
731 assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
732 let peer_id = PeerId {
733 owner_id: u32::MAX,
734 id: 3,
735 };
736 assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
737 let peer_id = PeerId {
738 owner_id: 10,
739 id: u32::MAX,
740 };
741 assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
742 let peer_id = PeerId {
743 owner_id: u32::MAX,
744 id: u32::MAX,
745 };
746 assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
747 }
748}