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 fn json_cast<N, M>(params: N) -> Result<M, crate::Error>
13where
14 N: serde::Serialize,
15 M: serde::de::DeserializeOwned,
16{
17 let json = serde_json::to_value(params).map_err(|e| {
18 crate::Error::parse_error().data(serde_json::json!({
19 "error": e.to_string(),
20 "phase": "serialization"
21 }))
22 })?;
23 let m = serde_json::from_value(json.clone()).map_err(|e| {
24 crate::Error::parse_error().data(serde_json::json!({
25 "error": e.to_string(),
26 "json": json,
27 "phase": "deserialization"
28 }))
29 })?;
30 Ok(m)
31}
32
33pub fn json_cast_params<N, M>(params: N) -> Result<M, crate::Error>
40where
41 N: serde::Serialize,
42 M: serde::de::DeserializeOwned,
43{
44 let json = serde_json::to_value(params).map_err(|e| {
45 crate::Error::internal_error().data(serde_json::json!({
46 "error": e.to_string(),
47 "phase": "serialization"
48 }))
49 })?;
50 let m = serde_json::from_value(json.clone()).map_err(|e| {
51 crate::Error::invalid_params().data(serde_json::json!({
52 "error": e.to_string(),
53 "json": json,
54 "phase": "deserialization"
55 }))
56 })?;
57 Ok(m)
58}
59
60pub fn internal_error(message: impl ToString) -> crate::Error {
62 crate::Error::internal_error().data(message.to_string())
63}
64
65pub fn parse_error(message: impl ToString) -> crate::Error {
67 crate::Error::parse_error().data(message.to_string())
68}
69
70pub(crate) fn instrumented_with_connection_name<F>(
71 name: String,
72 task: F,
73) -> tracing::instrument::Instrumented<F> {
74 use tracing::Instrument;
75
76 task.instrument(tracing::info_span!("connection", name = name))
77}
78
79pub(crate) async fn instrument_with_connection_name<R>(
80 name: Option<String>,
81 task: impl Future<Output = R>,
82) -> R {
83 if let Some(name) = name {
84 instrumented_with_connection_name(name.clone(), task).await
85 } else {
86 task.await
87 }
88}
89
90pub fn run_until<T, E>(
96 background: impl Future<Output = Result<(), E>>,
97 foreground: impl Future<Output = Result<T, E>>,
98) -> impl Future<Output = Result<T, E>> {
99 use futures::future::{Either, select};
100 use std::pin::pin;
101
102 Box::pin(async move {
103 match select(pin!(background), pin!(foreground)).await {
104 Either::Left((bg_result, fg_future)) => {
105 bg_result?; fg_future.await
108 }
109 Either::Right((fg_result, _bg_future)) => {
110 fg_result
112 }
113 }
114 })
115}
116
117pub(crate) async fn process_stream_concurrently<T, F>(
126 stream: impl Stream<Item = T>,
127 process_fn: F,
128 process_fn_hack: impl for<'a> Fn(&'a F, T) -> BoxFuture<'a, Result<(), crate::Error>>,
129) -> Result<(), crate::Error>
130where
131 F: AsyncFn(T) -> Result<(), crate::Error>,
132{
133 use std::pin::pin;
134
135 use futures::stream::{FusedStream, FuturesUnordered};
136 use futures_concurrency::future::Race;
137
138 enum Event<T> {
139 NewItem(Option<T>),
140 FutureCompleted(Option<Result<(), crate::Error>>),
141 }
142
143 let mut stream = pin!(stream.fuse());
144 let mut futures: FuturesUnordered<_> = FuturesUnordered::new();
145
146 loop {
147 if futures.is_empty() {
149 match stream.next().await {
150 Some(item) => futures.push(process_fn_hack(&process_fn, item)),
151 None => return Ok(()),
152 }
153 continue;
154 }
155
156 if stream.is_terminated() {
158 while let Some(result) = futures.next().await {
159 result?;
160 }
161 return Ok(());
162 }
163
164 let event = (async { Event::NewItem(stream.next().await) }, async {
166 Event::FutureCompleted(futures.next().await)
167 })
168 .race()
169 .await;
170
171 match event {
172 Event::NewItem(Some(item)) => {
173 futures.push(process_fn_hack(&process_fn, item));
174 }
175 Event::FutureCompleted(Some(result)) => {
176 result?;
177 }
178 Event::NewItem(None) | Event::FutureCompleted(None) => {
179 }
182 }
183 }
184}