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