1use std::fmt;
14use std::sync::atomic::{AtomicU64, Ordering};
15
16use tokio::sync::oneshot;
17
18use crate::error::{LspError, LspResult};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub struct InvocationId(pub u64);
26
27impl InvocationId {
28 pub fn next() -> Self {
32 static SEQ: AtomicU64 = AtomicU64::new(1);
33 Self(SEQ.fetch_add(1, Ordering::Relaxed))
34 }
35}
36
37impl fmt::Display for InvocationId {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "lsp#{}", self.0)
40 }
41}
42
43#[must_use = "the LSP response is dropped if the Pending is not awaited or block_on'd"]
52pub struct Pending<T> {
53 pub id: InvocationId,
54 rx: oneshot::Receiver<LspResult<T>>,
55}
56
57impl<T> Pending<T> {
58 pub(crate) fn new(id: InvocationId, rx: oneshot::Receiver<LspResult<T>>) -> Self {
59 Self { id, rx }
60 }
61
62 pub(crate) fn ready_err(err: LspError) -> Self {
65 let (tx, rx) = oneshot::channel();
66 let _ = tx.send(Err(err));
69 Self {
70 id: InvocationId::next(),
71 rx,
72 }
73 }
74
75 pub fn blocking_recv(self) -> LspResult<T> {
78 match self.rx.blocking_recv() {
79 Ok(res) => res,
80 Err(_) => Err(LspError::ResponseDropped),
81 }
82 }
83}
84
85impl<T> std::future::Future for Pending<T> {
86 type Output = LspResult<T>;
87
88 fn poll(
89 mut self: std::pin::Pin<&mut Self>,
90 cx: &mut std::task::Context<'_>,
91 ) -> std::task::Poll<Self::Output> {
92 use std::task::Poll;
93 match std::pin::Pin::new(&mut self.rx).poll(cx) {
94 Poll::Ready(Ok(res)) => Poll::Ready(res),
95 Poll::Ready(Err(_)) => Poll::Ready(Err(LspError::ResponseDropped)),
96 Poll::Pending => Poll::Pending,
97 }
98 }
99}
100
101impl<T> fmt::Debug for Pending<T> {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 f.debug_struct("Pending").field("id", &self.id).finish()
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[tokio::test]
112 async fn pending_resolves_with_value() {
113 let (tx, rx) = oneshot::channel();
114 let p: Pending<i32> = Pending::new(InvocationId::next(), rx);
115 tx.send(Ok(42)).unwrap();
116 assert_eq!(p.await.unwrap(), 42);
117 }
118
119 #[tokio::test]
120 async fn pending_yields_response_dropped_when_sender_dies() {
121 let (tx, rx) = oneshot::channel::<LspResult<i32>>();
122 let p = Pending::new(InvocationId::next(), rx);
123 drop(tx);
124 match p.await {
125 Err(LspError::ResponseDropped) => {}
126 other => panic!("expected ResponseDropped, got {other:?}"),
127 }
128 }
129
130 #[tokio::test]
131 async fn ready_err_short_circuits() {
132 let p: Pending<i32> = Pending::ready_err(LspError::NotInitialized);
133 match p.await {
134 Err(LspError::NotInitialized) => {}
135 other => panic!("expected NotInitialized, got {other:?}"),
136 }
137 }
138
139 #[test]
140 fn invocation_ids_are_monotonic() {
141 let a = InvocationId::next().0;
142 let b = InvocationId::next().0;
143 assert!(b > a);
144 }
145}