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};
9use std::{marker::PhantomData, time::Instant};
10
11pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static {
12 const NAME: &'static str;
13 const PRIORITY: MessagePriority;
14 fn into_envelope(
15 self,
16 id: u32,
17 responding_to: Option<u32>,
18 original_sender_id: Option<PeerId>,
19 ) -> Envelope;
20 fn from_envelope(envelope: Envelope) -> Option<Self>;
21}
22
23pub trait EntityMessage: EnvelopedMessage {
24 type Entity;
25 fn remote_entity_id(&self) -> u64;
26}
27
28pub trait RequestMessage: EnvelopedMessage {
29 type Response: EnvelopedMessage;
30}
31
32/// A trait to bind LSP request and responses for the proto layer.
33/// Should be used for every LSP request that has to traverse through the proto layer.
34///
35/// `lsp_messages` macro in the same crate provides a convenient way to implement this.
36pub trait LspRequestMessage: EnvelopedMessage {
37 type Response: EnvelopedMessage;
38
39 fn to_proto_query(self) -> crate::lsp_query::Request;
40
41 fn response_to_proto_query(response: Self::Response) -> crate::lsp_response::Response;
42
43 fn buffer_id(&self) -> u64;
44
45 fn buffer_version(&self) -> &[crate::VectorClockEntry];
46
47 /// Whether to deduplicate the requests, or keep the previous ones running when another
48 /// request of the same kind is processed.
49 fn stop_previous_requests() -> bool;
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub struct LspRequestId(pub u64);
54
55/// A response from a single language server.
56/// There could be multiple responses for a single LSP request,
57/// from different servers.
58pub struct ProtoLspResponse<R> {
59 pub server_id: u64,
60 pub response: R,
61}
62
63impl ProtoLspResponse<Box<dyn AnyTypedEnvelope>> {
64 pub fn into_response<T: LspRequestMessage>(self) -> Result<ProtoLspResponse<T::Response>> {
65 let envelope = self
66 .response
67 .into_any()
68 .downcast::<TypedEnvelope<T::Response>>()
69 .map_err(|_| {
70 anyhow::anyhow!(
71 "cannot downcast LspResponse to {} for message {}",
72 T::Response::NAME,
73 T::NAME,
74 )
75 })?;
76
77 Ok(ProtoLspResponse {
78 server_id: self.server_id,
79 response: envelope.payload,
80 })
81 }
82}
83
84pub trait AnyTypedEnvelope: Any + Send + Sync {
85 fn payload_type_id(&self) -> TypeId;
86 fn payload_type_name(&self) -> &'static str;
87 fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
88 fn is_background(&self) -> bool;
89 fn original_sender_id(&self) -> Option<PeerId>;
90 fn sender_id(&self) -> PeerId;
91 fn message_id(&self) -> u32;
92}
93
94pub enum MessagePriority {
95 Foreground,
96 Background,
97}
98
99impl<T: EnvelopedMessage> AnyTypedEnvelope for TypedEnvelope<T> {
100 fn payload_type_id(&self) -> TypeId {
101 TypeId::of::<T>()
102 }
103
104 fn payload_type_name(&self) -> &'static str {
105 T::NAME
106 }
107
108 fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
109 self
110 }
111
112 fn is_background(&self) -> bool {
113 matches!(T::PRIORITY, MessagePriority::Background)
114 }
115
116 fn original_sender_id(&self) -> Option<PeerId> {
117 self.original_sender_id
118 }
119
120 fn sender_id(&self) -> PeerId {
121 self.sender_id
122 }
123
124 fn message_id(&self) -> u32 {
125 self.message_id
126 }
127}
128
129impl PeerId {
130 pub const fn from_u64(peer_id: u64) -> Self {
131 let owner_id = (peer_id >> 32) as u32;
132 let id = peer_id as u32;
133 Self { owner_id, id }
134 }
135
136 pub const fn as_u64(self) -> u64 {
137 ((self.owner_id as u64) << 32) | (self.id as u64)
138 }
139}
140
141impl Copy for PeerId {}
142
143impl Eq for PeerId {}
144
145impl Ord for PeerId {
146 fn cmp(&self, other: &Self) -> cmp::Ordering {
147 self.owner_id
148 .cmp(&other.owner_id)
149 .then_with(|| self.id.cmp(&other.id))
150 }
151}
152
153impl PartialOrd for PeerId {
154 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
155 Some(self.cmp(other))
156 }
157}
158
159impl std::hash::Hash for PeerId {
160 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
161 self.owner_id.hash(state);
162 self.id.hash(state);
163 }
164}
165
166impl fmt::Display for PeerId {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 write!(f, "{}/{}", self.owner_id, self.id)
169 }
170}
171
172pub struct Receipt<T> {
173 pub sender_id: PeerId,
174 pub message_id: u32,
175 payload_type: PhantomData<T>,
176}
177
178impl<T> Clone for Receipt<T> {
179 fn clone(&self) -> Self {
180 *self
181 }
182}
183
184impl<T> Copy for Receipt<T> {}
185
186#[derive(Clone, Debug)]
187pub struct TypedEnvelope<T> {
188 pub sender_id: PeerId,
189 pub original_sender_id: Option<PeerId>,
190 pub message_id: u32,
191 pub payload: T,
192 pub received_at: Instant,
193}
194
195impl<T> TypedEnvelope<T> {
196 pub fn original_sender_id(&self) -> Result<PeerId> {
197 self.original_sender_id
198 .context("missing original_sender_id")
199 }
200}
201
202impl<T: RequestMessage> TypedEnvelope<T> {
203 pub const fn receipt(&self) -> Receipt<T> {
204 Receipt {
205 sender_id: self.sender_id,
206 message_id: self.message_id,
207 payload_type: PhantomData,
208 }
209 }
210}