1#![warn(missing_docs)]
2
3#[cfg(feature = "logging")]
6pub mod logging;
7#[cfg(feature = "logging")]
8pub use logging::{Logger, Logging};
9
10use std::{
11 fmt::Display,
12 io::{Read, Write},
13 pin::Pin,
14 task::{Context, Poll},
15};
16
17use futures::{
18 future::FusedFuture,
19 ready,
20 stream::{FusedStream, Next},
21 Future, FutureExt, Sink, Stream, StreamExt,
22};
23use pin_project::pin_project;
24use serde::{Deserialize, Serialize};
25
26pub trait Encode {
28 type Error: std::error::Error;
30
31 fn encode<W, T>(&mut self, writer: W, message: &T) -> Result<(), Self::Error>
33 where
34 W: Write,
35 T: Serialize;
36}
37
38pub trait Decode {
40 type Error: std::error::Error;
42
43 fn decode<R, T>(&mut self, data: R) -> Result<T, Self::Error>
45 where
46 R: Read,
47 for<'de> T: Deserialize<'de>;
48}
49
50pub trait Codec: Encode + Decode {}
52
53impl<T> Codec for T where T: Encode + Decode {}
54
55#[derive(Debug, PartialEq, Eq)]
57pub enum Error<Other> {
58 Closed,
60
61 Other(Other),
63}
64
65impl<Other> Error<Other> {
66 pub fn closed(&self) -> bool {
68 matches!(self, Error::Closed)
69 }
70}
71
72impl<Other> Display for Error<Other>
73where
74 Other: Display,
75{
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 match self {
78 Self::Closed => write!(f, "transport closed"),
79 Self::Other(other) => write!(f, "{other}"),
80 }
81 }
82}
83
84impl<Other> std::error::Error for Error<Other> where Other: std::error::Error {}
85
86pub trait Receive<Message, Error> {
88 fn receive(&mut self) -> Recv<'_, Self>;
90}
91
92impl<T, Message, Error> Receive<Message, Error> for T
93where
94 T: Stream<Item = Result<Message, Error>> + Unpin,
95{
96 fn receive(&mut self) -> Recv<'_, Self> {
98 let next = self.next();
99 Recv {
100 next,
101 terminated: false,
102 }
103 }
104}
105
106pub struct Recv<'a, T>
110where
111 T: ?Sized,
112{
113 next: Next<'a, T>,
114 terminated: bool,
115}
116
117impl<T, Message, Error> Future for Recv<'_, T>
118where
119 T: Stream<Item = Result<Message, Error>> + Unpin,
120{
121 type Output = Result<Message, self::Error<Error>>;
122
123 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
124 match self.next.poll_unpin(cx) {
125 Poll::Ready(item) => {
126 self.terminated = true;
127 if let Some(item) = item {
128 Poll::Ready(item.map_err(|error| self::Error::Other(error)))
129 } else {
130 Poll::Ready(Err(self::Error::Closed))
131 }
132 }
133 Poll::Pending => Poll::Pending,
134 }
135 }
136}
137
138impl<T, Message, Error> FusedFuture for Recv<'_, T>
139where
140 T: Stream<Item = Result<Message, Error>> + Unpin,
141{
142 fn is_terminated(&self) -> bool {
143 self.terminated
144 }
145}
146
147pub trait Messages<T, Message, Error>
149where
150 Self: Sized,
151{
152 fn messages_with_error_callback<F>(self, error_callback: F) -> MessageStream<Self, F>
156 where
157 F: FnMut(Error);
158
159 fn messages(self) -> MessageStream<Self, fn(Error) -> ()> {
161 self.messages_with_error_callback(|_| {})
162 }
163}
164
165impl<T, Message, Error> Messages<T, Message, Error> for T
166where
167 T: Stream<Item = Result<Message, Error>> + Unpin,
168{
169 fn messages_with_error_callback<F>(self, error_callback: F) -> MessageStream<Self, F>
170 where
171 F: FnMut(Error),
172 {
173 MessageStream {
174 stream: self,
175 error_callback,
176 terminated: false,
177 }
178 }
179}
180
181#[pin_project]
187pub struct MessageStream<T, F> {
188 #[pin]
189 stream: T,
190 error_callback: F,
191 terminated: bool,
192}
193
194impl<T, F, Message, Error> Stream for MessageStream<T, F>
195where
196 T: Stream<Item = Result<Message, Error>> + Unpin,
197 F: FnMut(Error),
198{
199 type Item = Message;
200
201 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
202 loop {
203 if let Some(result) = ready!(self.stream.poll_next_unpin(cx)) {
204 match result {
205 Ok(message) => return Poll::Ready(Some(message)),
206 Err(error) => {
207 (self.error_callback)(error);
208 continue;
209 }
210 }
211 } else {
212 self.terminated = true;
213 return Poll::Ready(None);
214 }
215 }
216 }
217}
218
219impl<T, F, Message, Error> FusedStream for MessageStream<T, F>
220where
221 T: Stream<Item = Result<Message, Error>> + Unpin,
222 F: FnMut(Error),
223{
224 fn is_terminated(&self) -> bool {
225 self.terminated
226 }
227}
228
229#[cfg(not(feature = "logging"))]
230pub trait Transport<Incoming, Outgoing, Error>:
232 Sink<Outgoing, Error = crate::Error<Error>> + Stream<Item = Result<Incoming, Error>>
233{
234}
235
236#[cfg(not(feature = "logging"))]
237impl<T, Incoming, Outgoing, Error> Transport<Incoming, Outgoing, Error> for T where
238 T: Sink<Outgoing, Error = crate::Error<Error>> + Stream<Item = Result<Incoming, Error>>
239{
240}
241
242#[cfg(feature = "logging")]
243pub trait Transport<Incoming, Outgoing, Error>:
245 Sink<Outgoing, Error = crate::Error<Error>>
246 + Stream<Item = Result<Incoming, Error>>
247 + logging::Logging
248{
249}
250
251#[cfg(feature = "logging")]
252impl<T, Incoming, Outgoing, Error> Transport<Incoming, Outgoing, Error> for T where
253 T: Sink<Outgoing, Error = crate::Error<Error>>
254 + Stream<Item = Result<Incoming, Error>>
255 + logging::Logging
256{
257}
258
259pub trait SymmetricTransport<Message, Error>: Transport<Message, Message, Error> {}
261
262impl<T, Message, Error> SymmetricTransport<Message, Error> for T where
263 T: Transport<Message, Message, Error>
264{
265}