agent_client_protocol/
util.rs1use futures::{
4 future::BoxFuture,
5 stream::{Stream, StreamExt},
6};
7
8mod typed;
9pub use typed::{MatchDispatch, MatchDispatchFrom, TypeNotification};
10
11pub(crate) fn redacted_error(code: impl Into<i32>) -> impl std::fmt::Debug {
17 struct RedactedError {
18 code: i32,
19 reason: &'static str,
20 }
21
22 impl std::fmt::Debug for RedactedError {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 f.debug_struct("Error")
25 .field("code", &self.code)
26 .field("reason", &self.reason)
27 .finish()
28 }
29 }
30
31 let code = code.into();
32 let reason = match code {
33 -32700 => "Parse error",
34 -32600 => "Invalid request",
35 -32601 => "Method not found",
36 -32602 => "Invalid params",
37 -32603 => "Internal error",
38 _ => "Protocol or application error",
39 };
40 RedactedError { code, reason }
41}
42
43pub fn json_cast<N, M>(params: N) -> Result<M, crate::Error>
48where
49 N: serde::Serialize,
50 M: serde::de::DeserializeOwned,
51{
52 let json = serde_json::to_value(params).map_err(|e| {
53 crate::Error::parse_error().data(serde_json::json!({
54 "error": e.to_string(),
55 "phase": "serialization"
56 }))
57 })?;
58 let m = serde_json::from_value(json.clone()).map_err(|e| {
59 crate::Error::parse_error().data(serde_json::json!({
60 "error": e.to_string(),
61 "json": json,
62 "phase": "deserialization"
63 }))
64 })?;
65 Ok(m)
66}
67
68pub fn json_cast_params<N, M>(params: N) -> Result<M, crate::Error>
78where
79 N: serde::Serialize,
80 M: serde::de::DeserializeOwned,
81{
82 let json = serde_json::to_value(params).map_err(|e| {
83 crate::Error::internal_error().data(serde_json::json!({
84 "error": e.to_string(),
85 "phase": "serialization"
86 }))
87 })?;
88 let m = serde_json::from_value(json.clone()).map_err(|e| {
89 crate::Error::invalid_params().data(serde_json::json!({
90 "error": e.to_string(),
91 "json": json,
92 "phase": "deserialization"
93 }))
94 })?;
95 Ok(m)
96}
97
98pub fn internal_error(message: impl ToString) -> crate::Error {
100 crate::Error::internal_error().data(message.to_string())
101}
102
103pub fn parse_error(message: impl ToString) -> crate::Error {
105 crate::Error::parse_error().data(message.to_string())
106}
107
108#[must_use]
113pub fn unsupported_protocol_version(
114 requested: crate::schema::ProtocolVersion,
115 supported: &[crate::schema::ProtocolVersion],
116) -> crate::Error {
117 crate::Error::new(-32022, "Unsupported protocol version")
118 .data(serde_json::json!({ "requested": requested, "supported": supported }))
119}
120
121pub(crate) fn instrumented_with_connection_name<F>(
122 name: String,
123 task: F,
124) -> tracing::instrument::Instrumented<F> {
125 use tracing::Instrument;
126
127 task.instrument(tracing::info_span!("connection", name = name))
128}
129
130pub(crate) async fn instrument_with_connection_name<R>(
131 name: Option<String>,
132 task: impl Future<Output = R>,
133) -> R {
134 if let Some(name) = name {
135 instrumented_with_connection_name(name.clone(), task).await
136 } else {
137 task.await
138 }
139}
140
141pub fn run_until<T, E>(
147 background: impl Future<Output = Result<(), E>>,
148 foreground: impl Future<Output = Result<T, E>>,
149) -> impl Future<Output = Result<T, E>> {
150 use futures::future::{Either, select};
151 use std::pin::pin;
152
153 Box::pin(async move {
154 match select(pin!(background), pin!(foreground)).await {
155 Either::Left((bg_result, fg_future)) => {
156 bg_result?; fg_future.await
159 }
160 Either::Right((fg_result, _bg_future)) => {
161 fg_result
163 }
164 }
165 })
166}
167
168pub(crate) async fn process_stream_concurrently<T, F>(
177 stream: impl Stream<Item = T>,
178 process_fn: F,
179 process_fn_hack: impl for<'a> Fn(&'a F, T) -> BoxFuture<'a, Result<(), crate::Error>>,
180) -> Result<(), crate::Error>
181where
182 F: AsyncFn(T) -> Result<(), crate::Error>,
183{
184 use std::pin::pin;
185
186 use futures::stream::{FusedStream, FuturesUnordered};
187 use futures_concurrency::future::Race;
188
189 enum Event<T> {
190 NewItem(Option<T>),
191 FutureCompleted(Option<Result<(), crate::Error>>),
192 }
193
194 let mut stream = pin!(stream.fuse());
195 let mut futures: FuturesUnordered<_> = FuturesUnordered::new();
196
197 loop {
198 if futures.is_empty() {
200 match stream.next().await {
201 Some(item) => futures.push(process_fn_hack(&process_fn, item)),
202 None => return Ok(()),
203 }
204 continue;
205 }
206
207 if stream.is_terminated() {
209 while let Some(result) = futures.next().await {
210 result?;
211 }
212 return Ok(());
213 }
214
215 let event = (async { Event::NewItem(stream.next().await) }, async {
217 Event::FutureCompleted(futures.next().await)
218 })
219 .race()
220 .await;
221
222 match event {
223 Event::NewItem(Some(item)) => {
224 futures.push(process_fn_hack(&process_fn, item));
225 }
226 Event::FutureCompleted(Some(result)) => {
227 result?;
228 }
229 Event::NewItem(None) | Event::FutureCompleted(None) => {
230 }
233 }
234 }
235}