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