1use crate::{Envelope, PeerId};
2use anyhow::{Context as _, Result};
3use serde::Serialize;
4use std::{
5 any::{Any, TypeId},
6 cmp,
7 fmt::{self, Debug},
8 path::{Path, PathBuf},
9 sync::Arc,
10};
11use std::{marker::PhantomData, time::Instant};
12
13pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static {
14 const NAME: &'static str;
15 const PRIORITY: MessagePriority;
16 fn into_envelope(
17 self,
18 id: u32,
19 responding_to: Option<u32>,
20 original_sender_id: Option<PeerId>,
21 ) -> Envelope;
22 fn from_envelope(envelope: Envelope) -> Option<Self>;
23}
24
25pub trait EntityMessage: EnvelopedMessage {
26 type Entity;
27 fn remote_entity_id(&self) -> u64;
28}
29
30pub trait RequestMessage: EnvelopedMessage {
31 type Response: EnvelopedMessage;
32}
33
34pub trait AnyTypedEnvelope: Any + Send + Sync {
35 fn payload_type_id(&self) -> TypeId;
36 fn payload_type_name(&self) -> &'static str;
37 fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
38 fn is_background(&self) -> bool;
39 fn original_sender_id(&self) -> Option<PeerId>;
40 fn sender_id(&self) -> PeerId;
41 fn message_id(&self) -> u32;
42}
43
44pub enum MessagePriority {
45 Foreground,
46 Background,
47}
48
49impl<T: EnvelopedMessage> AnyTypedEnvelope for TypedEnvelope<T> {
50 fn payload_type_id(&self) -> TypeId {
51 TypeId::of::<T>()
52 }
53
54 fn payload_type_name(&self) -> &'static str {
55 T::NAME
56 }
57
58 fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
59 self
60 }
61
62 fn is_background(&self) -> bool {
63 matches!(T::PRIORITY, MessagePriority::Background)
64 }
65
66 fn original_sender_id(&self) -> Option<PeerId> {
67 self.original_sender_id
68 }
69
70 fn sender_id(&self) -> PeerId {
71 self.sender_id
72 }
73
74 fn message_id(&self) -> u32 {
75 self.message_id
76 }
77}
78
79impl PeerId {
80 pub fn from_u64(peer_id: u64) -> Self {
81 let owner_id = (peer_id >> 32) as u32;
82 let id = peer_id as u32;
83 Self { owner_id, id }
84 }
85
86 pub fn as_u64(self) -> u64 {
87 ((self.owner_id as u64) << 32) | (self.id as u64)
88 }
89}
90
91impl Copy for PeerId {}
92
93impl Eq for PeerId {}
94
95impl Ord for PeerId {
96 fn cmp(&self, other: &Self) -> cmp::Ordering {
97 self.owner_id
98 .cmp(&other.owner_id)
99 .then_with(|| self.id.cmp(&other.id))
100 }
101}
102
103impl PartialOrd for PeerId {
104 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
105 Some(self.cmp(other))
106 }
107}
108
109impl std::hash::Hash for PeerId {
110 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
111 self.owner_id.hash(state);
112 self.id.hash(state);
113 }
114}
115
116impl fmt::Display for PeerId {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 write!(f, "{}/{}", self.owner_id, self.id)
119 }
120}
121
122pub trait FromProto {
123 fn from_proto(proto: String) -> Self;
124}
125
126pub trait ToProto {
127 fn to_proto(self) -> String;
128}
129
130impl FromProto for PathBuf {
131 #[cfg(target_os = "windows")]
132 fn from_proto(proto: String) -> Self {
133 proto.split("/").collect()
134 }
135
136 #[cfg(not(target_os = "windows"))]
137 fn from_proto(proto: String) -> Self {
138 PathBuf::from(proto)
139 }
140}
141
142impl FromProto for Arc<Path> {
143 fn from_proto(proto: String) -> Self {
144 PathBuf::from_proto(proto).into()
145 }
146}
147
148impl ToProto for PathBuf {
149 #[cfg(target_os = "windows")]
150 fn to_proto(self) -> String {
151 self.components()
152 .map(|comp| comp.as_os_str().to_string_lossy().to_string())
153 .collect::<Vec<_>>()
154 .join("/")
155 }
156
157 #[cfg(not(target_os = "windows"))]
158 fn to_proto(self) -> String {
159 self.to_string_lossy().to_string()
160 }
161}
162
163impl ToProto for &Path {
164 #[cfg(target_os = "windows")]
165 fn to_proto(self) -> String {
166 self.components()
167 .map(|comp| comp.as_os_str().to_string_lossy().to_string())
168 .collect::<Vec<_>>()
169 .join("/")
170 }
171
172 #[cfg(not(target_os = "windows"))]
173 fn to_proto(self) -> String {
174 self.to_string_lossy().to_string()
175 }
176}
177
178pub struct Receipt<T> {
179 pub sender_id: PeerId,
180 pub message_id: u32,
181 payload_type: PhantomData<T>,
182}
183
184impl<T> Clone for Receipt<T> {
185 fn clone(&self) -> Self {
186 *self
187 }
188}
189
190impl<T> Copy for Receipt<T> {}
191
192#[derive(Clone, Debug)]
193pub struct TypedEnvelope<T> {
194 pub sender_id: PeerId,
195 pub original_sender_id: Option<PeerId>,
196 pub message_id: u32,
197 pub payload: T,
198 pub received_at: Instant,
199}
200
201impl<T> TypedEnvelope<T> {
202 pub fn original_sender_id(&self) -> Result<PeerId> {
203 self.original_sender_id
204 .context("missing original_sender_id")
205 }
206}
207
208impl<T: RequestMessage> TypedEnvelope<T> {
209 pub fn receipt(&self) -> Receipt<T> {
210 Receipt {
211 sender_id: self.sender_id,
212 message_id: self.message_id,
213 payload_type: PhantomData,
214 }
215 }
216}