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