From 978e555dd7430cadc83808ad5147ff81a45fb76a Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 1 Nov 2024 15:59:22 +0200 Subject: [PATCH 01/32] Relax type constraints in lots of places --- Cargo.lock | 7 + Cargo.toml | 1 + src/pattern/bidi_streaming.rs | 4 +- src/pattern/client_streaming.rs | 4 +- src/pattern/rpc.rs | 4 +- src/pattern/server_streaming.rs | 4 +- src/pattern/try_server_streaming.rs | 4 +- src/server.rs | 19 +- src/transport/mapped.rs | 374 ++++++++++++++++++++++++++++ src/transport/mod.rs | 2 + 10 files changed, 405 insertions(+), 18 deletions(-) create mode 100644 src/transport/mapped.rs diff --git a/Cargo.lock b/Cargo.lock index bebeed4..87f17ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -904,6 +904,7 @@ dependencies = [ "serde", "slab", "tempfile", + "testresult", "thousands", "tokio", "tokio-serde", @@ -1382,6 +1383,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "testresult" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614b328ff036a4ef882c61570f72918f7e9c5bee1da33f8e7f91e01daee7e56c" + [[package]] name = "thiserror" version = "1.0.63" diff --git a/Cargo.toml b/Cargo.toml index 1041fe8..39da37e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ tracing-subscriber = "0.3.16" tempfile = "3.5.0" proc-macro2 = "1.0.66" futures-buffered = "0.2.4" +testresult = "0.4.1" [features] hyper-transport = ["dep:flume", "dep:hyper", "dep:bincode", "dep:bytes", "dep:tokio-serde", "dep:tokio-util"] diff --git a/src/pattern/bidi_streaming.rs b/src/pattern/bidi_streaming.rs index d7ec853..0c7ecd9 100644 --- a/src/pattern/bidi_streaming.rs +++ b/src/pattern/bidi_streaming.rs @@ -7,7 +7,7 @@ use crate::{ client::{BoxStreamSync, UpdateSink}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, - transport::ConnectionErrors, + transport::{ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, ServiceEndpoint, }; @@ -116,7 +116,7 @@ where impl RpcChannel where SC: Service, - C: ServiceEndpoint, + C: ConnectionCommon, S: Service, { /// handle the message M using the given function on the target object diff --git a/src/pattern/client_streaming.rs b/src/pattern/client_streaming.rs index 074023c..e329bb9 100644 --- a/src/pattern/client_streaming.rs +++ b/src/pattern/client_streaming.rs @@ -7,7 +7,7 @@ use crate::{ client::UpdateSink, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, - transport::ConnectionErrors, + transport::{ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, ServiceEndpoint, }; @@ -123,8 +123,8 @@ where impl RpcChannel where S: Service, + C: ConnectionCommon, SC: Service, - C: ServiceEndpoint, { /// handle the message M using the given function on the target object /// diff --git a/src/pattern/rpc.rs b/src/pattern/rpc.rs index 8782c25..a4a498b 100644 --- a/src/pattern/rpc.rs +++ b/src/pattern/rpc.rs @@ -6,7 +6,7 @@ use futures_util::{FutureExt, SinkExt}; use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::ConnectionErrors, + transport::{ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, ServiceEndpoint, }; @@ -94,8 +94,8 @@ where impl RpcChannel where S: Service, + C: ConnectionCommon, SC: Service, - C: ServiceEndpoint, { /// handle the message of type `M` using the given function on the target object /// diff --git a/src/pattern/server_streaming.rs b/src/pattern/server_streaming.rs index 679d033..0a0938f 100644 --- a/src/pattern/server_streaming.rs +++ b/src/pattern/server_streaming.rs @@ -7,7 +7,7 @@ use crate::{ client::{BoxStreamSync, DeferDrop}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::ConnectionErrors, + transport::{ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, ServiceEndpoint, }; @@ -103,8 +103,8 @@ where impl RpcChannel where S: Service, + C: ConnectionCommon, SC: Service, - C: ServiceEndpoint, { /// handle the message M using the given function on the target object /// diff --git a/src/pattern/try_server_streaming.rs b/src/pattern/try_server_streaming.rs index 3b2950c..85bdae4 100644 --- a/src/pattern/try_server_streaming.rs +++ b/src/pattern/try_server_streaming.rs @@ -8,7 +8,7 @@ use crate::{ client::{BoxStreamSync, DeferDrop}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::ConnectionErrors, + transport::{ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, ServiceEndpoint, }; @@ -101,7 +101,7 @@ impl error::Error for ItemError {} impl RpcChannel where SC: Service, - C: ServiceEndpoint, + C: ConnectionCommon, S: Service, { /// handle the message M using the given function on the target object diff --git a/src/server.rs b/src/server.rs index 0185584..5f2f5e6 100644 --- a/src/server.rs +++ b/src/server.rs @@ -3,7 +3,7 @@ //! The main entry point is [RpcServer] use crate::{ map::{ChainedMapper, MapService, Mapper}, - transport::ConnectionErrors, + transport::{ConnectionCommon, ConnectionErrors}, Service, ServiceEndpoint, }; use futures_lite::{Future, Stream, StreamExt}; @@ -77,8 +77,11 @@ impl> RpcServer { /// `SC` is the service type that is compatible with the connection. /// `C` is the service endpoint from which the channel was created. #[derive(Debug)] -pub struct RpcChannel = BoxedServiceEndpoint, SC: Service = S> -{ +pub struct RpcChannel< + S: Service, + C: ConnectionCommon = BoxedServiceEndpoint, + SC: Service = S, +> { /// Sink to send responses to the client. pub send: C::SendSink, /// Stream to receive requests from the client. @@ -90,7 +93,7 @@ pub struct RpcChannel = BoxedServiceEndpoint< impl RpcChannel where S: Service, - C: ServiceEndpoint, + C: ConnectionCommon, { /// Create a new RPC channel. pub fn new(send: C::SendSink, recv: C::RecvStream) -> Self { @@ -106,7 +109,7 @@ impl RpcChannel where S: Service, SC: Service, - C: ServiceEndpoint, + C: ConnectionCommon, { /// Map this channel's service into an inner service. /// @@ -199,13 +202,13 @@ pub struct UpdateStream( where SC: Service, S: Service, - C: ServiceEndpoint; + C: ConnectionCommon; impl UpdateStream where SC: Service, S: Service, - C: ServiceEndpoint, + C: ConnectionCommon, T: TryFrom, { pub(crate) fn new( @@ -222,7 +225,7 @@ impl Stream for UpdateStream where SC: Service, S: Service, - C: ServiceEndpoint, + C: ConnectionCommon, T: TryFrom, { type Item = T; diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs new file mode 100644 index 0000000..8f1c5fd --- /dev/null +++ b/src/transport/mapped.rs @@ -0,0 +1,374 @@ +//! Transport with mapped input and output types. +use std::{ + fmt::{Debug, Display}, + iter::Rev, + marker::PhantomData, + task::{Context, Poll}, +}; + +use futures_lite::{Stream, StreamExt}; +use futures_util::SinkExt; +use pin_project::pin_project; + +use crate::{server::RpcChannel, RpcError, RpcMessage, Service, ServiceEndpoint}; + +use super::{Connection, ConnectionCommon, ConnectionErrors}; + +/// A connection that maps input and output types +#[derive(Debug)] +pub struct MappedConnection { + inner: T, + _phantom: std::marker::PhantomData<(In, Out, In0, Out0)>, +} + +impl MappedConnection +where + T: Connection, + In: TryFrom, + OutT: From, +{ + /// Create a new mapped connection + pub fn new(inner: T) -> Self { + Self { + inner, + _phantom: std::marker::PhantomData, + } + } +} + +impl Clone for MappedConnection +where + T: Clone, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + _phantom: std::marker::PhantomData, + } + } +} + +impl ConnectionErrors for MappedConnection +where + In: RpcMessage, + Out: RpcMessage, + InT: RpcMessage, + OutT: RpcMessage, + T: ConnectionErrors, +{ + type OpenError = T::OpenError; + type RecvError = ErrorOrMapError; + type SendError = T::SendError; +} + +impl ConnectionCommon for MappedConnection +where + T: ConnectionCommon, + In: RpcMessage, + Out: RpcMessage, + InT: RpcMessage, + OutT: RpcMessage, + In: TryFrom, + OutT: From, +{ + type RecvStream = MappedRecvStream; + type SendSink = MappedSendSink; +} + +impl Connection for MappedConnection +where + T: Connection, + In: RpcMessage, + Out: RpcMessage, + InT: RpcMessage, + OutT: RpcMessage, + In: TryFrom, + OutT: From, +{ + fn open( + &self, + ) -> impl std::future::Future> + + Send { + let inner = self.inner.open(); + async move { + let (send, recv) = inner.await?; + Ok((MappedSendSink::new(send), MappedRecvStream::new(recv))) + } + } +} + +/// A combinator that maps a stream of incoming messages to a different type +#[pin_project] +pub struct MappedRecvStream { + inner: S, + _phantom: std::marker::PhantomData, +} + +impl MappedRecvStream { + /// Create a new mapped receive stream + pub fn new(inner: S) -> Self { + Self { + inner, + _phantom: std::marker::PhantomData, + } + } +} + +/// Error mapping an incoming message to the inner type +#[derive(Debug)] +pub enum ErrorOrMapError { + /// Error from the inner stream + Inner(E), + /// Conversion error + Conversion, +} + +impl Display for ErrorOrMapError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ErrorOrMapError::Inner(e) => write!(f, "Inner error: {}", e), + ErrorOrMapError::Conversion => write!(f, "Conversion error"), + } + } +} + +impl Stream for MappedRecvStream +where + S: Stream> + Unpin, + In: TryFrom, + E: RpcError, +{ + type Item = Result>; + + fn poll_next(self: std::pin::Pin<&mut Self>, cx: &mut Context) -> Poll> { + match self.project().inner.poll_next(cx) { + Poll::Ready(Some(Ok(item))) => { + let item = item.try_into().map_err(|_| ErrorOrMapError::Conversion); + Poll::Ready(Some(item)) + } + Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(ErrorOrMapError::Inner(e)))), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } +} + +/// A sink that maps outgoing messages to a different type +/// +/// The conversion to the underlying message type always succeeds, so this +/// is relatively simple. +#[pin_project] +pub struct MappedSendSink { + inner: S, + _phantom: std::marker::PhantomData<(Out, OutS)>, +} + +impl MappedSendSink { + /// Create a new mapped send sink + pub fn new(inner: S) -> Self { + Self { + inner, + _phantom: std::marker::PhantomData, + } + } +} + +impl futures_sink::Sink for MappedSendSink +where + S: futures_sink::Sink + Unpin, + Out: Into, +{ + type Error = S::Error; + + fn poll_ready( + self: std::pin::Pin<&mut Self>, + cx: &mut Context, + ) -> Poll> { + self.project().inner.poll_ready_unpin(cx) + } + + fn start_send(self: std::pin::Pin<&mut Self>, item: Out) -> Result<(), Self::Error> { + self.project().inner.start_send_unpin(item.into()) + } + + fn poll_flush( + self: std::pin::Pin<&mut Self>, + cx: &mut Context, + ) -> Poll> { + self.project().inner.poll_flush_unpin(cx) + } + + fn poll_close( + self: std::pin::Pin<&mut Self>, + cx: &mut Context, + ) -> Poll> { + self.project().inner.poll_close_unpin(cx) + } +} + +/// Extension trait for mapping connections +pub trait ConnectionMapExt: Connection { + /// Map the input and output types of this connection + fn map(self) -> MappedConnection + where + In1: TryFrom, + Out: From, + { + MappedConnection::new(self) + } + + /// Map this connection to a service + fn map_to_service(self) -> MappedConnection + where + S::Res: TryFrom, + Out: From, + { + MappedConnection::new(self) + } +} + +impl, In, Out> ConnectionMapExt for T {} + +struct MappedStreamTypes { + p: PhantomData<(Send, Recv, OE)>, +} + +impl std::fmt::Debug for MappedStreamTypes { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MappedStreamTypes").finish() + } +} + +impl Clone for MappedStreamTypes { + fn clone(&self) -> Self { + Self { p: PhantomData } + } +} + +struct MappedCC(PhantomData<(In, Out, C)>); + +impl Debug for MappedCC { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MappedCC").finish() + } +} + +impl Clone for MappedCC { + fn clone(&self) -> Self { + Self(PhantomData) + } +} + +impl ConnectionErrors for MappedCC +where + In: RpcMessage, + Out: RpcMessage, + C: ConnectionErrors, +{ + type OpenError = C::OpenError; + type RecvError = ErrorOrMapError; + type SendError = C::SendError; +} + +impl ConnectionCommon for MappedCC +where + C: ConnectionCommon, + In: RpcMessage, + Out: RpcMessage, +{ + type RecvStream = MappedRecvStream; + type SendSink = MappedSendSink; +} + +struct StreamPair { + pub send: Send, + pub recv: Recv, +} + +impl StreamPair { + pub fn new(send: Send, recv: Recv) -> Self { + Self { send, recv } + } + + pub fn map( + self, + ) -> StreamPair, MappedRecvStream> + where + Send: futures_sink::Sink + Unpin, + Recv: Stream> + Unpin, + Out0: From, + In: TryFrom, + { + StreamPair::new( + MappedSendSink::new(self.send), + MappedRecvStream::new(self.recv), + ) + } +} + +#[cfg(test)] +mod tests { + + use crate::{ + server::RpcChannel, + transport::{flume::FlumeConnection, ServerEndpoint}, + RpcClient, RpcServer, ServiceConnection, ServiceEndpoint, + }; + use serde::{Deserialize, Serialize}; + use testresult::TestResult; + + use super::*; + + #[derive(Debug, Clone, Serialize, Deserialize, derive_more::From, derive_more::TryInto)] + enum Request { + A(u64), + B(String), + } + + #[derive(Debug, Clone, Serialize, Deserialize, derive_more::From, derive_more::TryInto)] + enum Response { + A(u64), + B(String), + } + + #[derive(Debug, Clone)] + struct FullService; + + impl crate::Service for FullService { + type Req = Request; + type Res = Response; + } + + #[derive(Debug, Clone)] + struct SubService; + + impl crate::Service for SubService { + type Req = String; + type Res = String; + } + + #[tokio::test] + async fn smoke() -> TestResult<()> { + async fn handle_sub_request( + req: String, + chan: RpcChannel>, + ) -> anyhow::Result<()> { + Ok(()) + } + let (s, c): (_, FlumeConnection) = + crate::transport::flume::connection::(32); + let _x = c.clone().map::(); + let _y = c.clone().map_to_service::(); + let _z = RpcClient::::new(c.map_to_service::()); + let s = RpcServer::::new(s); + + while let Ok(accepting) = s.accept().await { + let (msg, chan) = accepting.read_first().await?; + match msg { + Request::A(x) => todo!(), + Request::B(x) => todo!(), // handle_sub_request(x, chan).await?, + } + } + Ok(()) + } +} diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 79ae4b0..3fa7f45 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -41,6 +41,8 @@ pub mod misc; #[cfg(any(feature = "quinn-transport", feature = "hyper-transport"))] mod util; +pub mod mapped; + /// Errors that can happen when creating and using a [`Connection`] or [`ServerEndpoint`]. pub trait ConnectionErrors: Debug + Clone + Send + Sync + 'static { /// Error when opening or accepting a channel From 80b5f6324d35f53787e584e8b7b05c8330ac7616 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 1 Nov 2024 16:34:42 +0200 Subject: [PATCH 02/32] map the channel wip --- src/transport/mapped.rs | 71 +++++++++++++++++++++++++++-------------- src/transport/mod.rs | 2 +- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index 8f1c5fd..f6295ae 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -7,6 +7,7 @@ use std::{ }; use futures_lite::{Stream, StreamExt}; +use futures_sink::Sink; use futures_util::SinkExt; use pin_project::pin_project; @@ -229,40 +230,27 @@ pub trait ConnectionMapExt: Connection { impl, In, Out> ConnectionMapExt for T {} -struct MappedStreamTypes { - p: PhantomData<(Send, Recv, OE)>, -} +/// Connection types for a mapped connection +pub struct MappedConnectionTypes(PhantomData<(In, Out, In0, Out0, C)>); -impl std::fmt::Debug for MappedStreamTypes { +impl Debug for MappedConnectionTypes { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("MappedStreamTypes").finish() + f.debug_struct("MappedConnectionTypes").finish() } } -impl Clone for MappedStreamTypes { - fn clone(&self) -> Self { - Self { p: PhantomData } - } -} - -struct MappedCC(PhantomData<(In, Out, C)>); - -impl Debug for MappedCC { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("MappedCC").finish() - } -} - -impl Clone for MappedCC { +impl Clone for MappedConnectionTypes { fn clone(&self) -> Self { Self(PhantomData) } } -impl ConnectionErrors for MappedCC +impl ConnectionErrors for MappedConnectionTypes where In: RpcMessage, Out: RpcMessage, + In0: RpcMessage, + Out0: RpcMessage, C: ConnectionErrors, { type OpenError = C::OpenError; @@ -270,14 +258,49 @@ where type SendError = C::SendError; } -impl ConnectionCommon for MappedCC +impl ConnectionCommon + for MappedConnectionTypes where - C: ConnectionCommon, + C: ConnectionCommon, In: RpcMessage, Out: RpcMessage, + In0: RpcMessage, + Out0: RpcMessage, + In: TryFrom, + Out0: From, { type RecvStream = MappedRecvStream; - type SendSink = MappedSendSink; + type SendSink = MappedSendSink; +} + +/// +#[derive(Debug)] +pub struct RpcChannel2> { + /// Sink to send responses to the client. + pub send: C::SendSink, + /// Stream to receive requests from the client. + pub recv: C::RecvStream, +} + +impl RpcChannel2 +where + S: Service, + C: ConnectionCommon, +{ + /// Map the input and output types of this connection + pub fn map2( + self, + ) -> RpcChannel2> + where + S1: Service, + S1::Req: TryFrom, + S::Res: From, + { + RpcChannel2 { + send: MappedSendSink::new(self.send), + recv: MappedRecvStream::new(self.recv), + } + } } struct StreamPair { diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 3fa7f45..8385a7e 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -20,7 +20,7 @@ use futures_lite::{Future, Stream}; use futures_sink::Sink; -use crate::RpcError; +use crate::{RpcError, RpcMessage}; use std::{ fmt::{self, Debug, Display}, net::SocketAddr, From 6c83e441acec585a769fd3de55232a6673988367 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 1 Nov 2024 21:03:55 +0200 Subject: [PATCH 03/32] associated types everywhere --- Cargo.toml | 2 +- src/lib.rs | 8 +- src/pattern/bidi_streaming.rs | 4 +- src/pattern/client_streaming.rs | 4 +- src/pattern/rpc.rs | 4 +- src/pattern/server_streaming.rs | 4 +- src/pattern/try_server_streaming.rs | 4 +- src/server.rs | 21 +-- src/transport/boxed.rs | 12 +- src/transport/combined.rs | 117 ++++++----------- src/transport/flume.rs | 12 +- src/transport/hyper.rs | 13 +- src/transport/mapped.rs | 190 +++++++++++++--------------- src/transport/misc/mod.rs | 78 ++++++------ src/transport/mod.rs | 18 ++- src/transport/quinn.rs | 12 +- tests/util.rs | 2 +- 17 files changed, 239 insertions(+), 266 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 39da37e..ba87bb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ quinn-transport = ["dep:flume", "dep:quinn", "dep:bincode", "dep:tokio-serde", " flume-transport = ["dep:flume"] combined-transport = [] macros = [] -default = ["flume-transport"] +default = ["flume-transport", "quinn-transport", "combined-transport"] [package.metadata.docs.rs] all-features = true diff --git a/src/lib.rs b/src/lib.rs index 71d09f9..320b6b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,9 +162,9 @@ pub trait Service: Send + Sync + Debug + Clone + 'static { /// This is just a trait alias for a [Connection] with the right types. /// /// This can be used to create a [RpcClient] that can be used to send requests. -pub trait ServiceConnection: Connection {} +pub trait ServiceConnection: Connection {} -impl, S: Service> ServiceConnection for T {} +impl, S: Service> ServiceConnection for T {} /// A server endpoint for a specific service /// @@ -172,6 +172,6 @@ impl, S: Service> ServiceConnection for T {} /// /// This can be used to create a [RpcServer] that can be used to handle /// requests. -pub trait ServiceEndpoint: ServerEndpoint {} +pub trait ServiceEndpoint: ServerEndpoint {} -impl, S: Service> ServiceEndpoint for T {} +impl, S: Service> ServiceEndpoint for T {} diff --git a/src/pattern/bidi_streaming.rs b/src/pattern/bidi_streaming.rs index 0c7ecd9..c571c51 100644 --- a/src/pattern/bidi_streaming.rs +++ b/src/pattern/bidi_streaming.rs @@ -8,7 +8,7 @@ use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, transport::{ConnectionCommon, ConnectionErrors}, - RpcClient, Service, ServiceConnection, ServiceEndpoint, + RpcClient, Service, ServiceConnection, }; use std::{ @@ -116,7 +116,7 @@ where impl RpcChannel where SC: Service, - C: ConnectionCommon, + C: ConnectionCommon, S: Service, { /// handle the message M using the given function on the target object diff --git a/src/pattern/client_streaming.rs b/src/pattern/client_streaming.rs index e329bb9..3775fd0 100644 --- a/src/pattern/client_streaming.rs +++ b/src/pattern/client_streaming.rs @@ -8,7 +8,7 @@ use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, transport::{ConnectionCommon, ConnectionErrors}, - RpcClient, Service, ServiceConnection, ServiceEndpoint, + RpcClient, Service, ServiceConnection, }; use std::{ @@ -123,7 +123,7 @@ where impl RpcChannel where S: Service, - C: ConnectionCommon, + C: ConnectionCommon, SC: Service, { /// handle the message M using the given function on the target object diff --git a/src/pattern/rpc.rs b/src/pattern/rpc.rs index a4a498b..4545dca 100644 --- a/src/pattern/rpc.rs +++ b/src/pattern/rpc.rs @@ -7,7 +7,7 @@ use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, transport::{ConnectionCommon, ConnectionErrors}, - RpcClient, Service, ServiceConnection, ServiceEndpoint, + RpcClient, Service, ServiceConnection, }; use std::{ @@ -94,7 +94,7 @@ where impl RpcChannel where S: Service, - C: ConnectionCommon, + C: ConnectionCommon, SC: Service, { /// handle the message of type `M` using the given function on the target object diff --git a/src/pattern/server_streaming.rs b/src/pattern/server_streaming.rs index 0a0938f..d744bec 100644 --- a/src/pattern/server_streaming.rs +++ b/src/pattern/server_streaming.rs @@ -8,7 +8,7 @@ use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, transport::{ConnectionCommon, ConnectionErrors}, - RpcClient, Service, ServiceConnection, ServiceEndpoint, + RpcClient, Service, ServiceConnection, }; use std::{ @@ -103,7 +103,7 @@ where impl RpcChannel where S: Service, - C: ConnectionCommon, + C: ConnectionCommon, SC: Service, { /// handle the message M using the given function on the target object diff --git a/src/pattern/try_server_streaming.rs b/src/pattern/try_server_streaming.rs index 85bdae4..98ba89b 100644 --- a/src/pattern/try_server_streaming.rs +++ b/src/pattern/try_server_streaming.rs @@ -9,7 +9,7 @@ use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, transport::{ConnectionCommon, ConnectionErrors}, - RpcClient, Service, ServiceConnection, ServiceEndpoint, + RpcClient, Service, ServiceConnection, }; use std::{ @@ -101,7 +101,7 @@ impl error::Error for ItemError {} impl RpcChannel where SC: Service, - C: ConnectionCommon, + C: ConnectionCommon, S: Service, { /// handle the message M using the given function on the target object diff --git a/src/server.rs b/src/server.rs index 5f2f5e6..dfb691e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -79,7 +79,7 @@ impl> RpcServer { #[derive(Debug)] pub struct RpcChannel< S: Service, - C: ConnectionCommon = BoxedServiceEndpoint, + C: ConnectionCommon = BoxedServiceEndpoint, SC: Service = S, > { /// Sink to send responses to the client. @@ -93,7 +93,7 @@ pub struct RpcChannel< impl RpcChannel where S: Service, - C: ConnectionCommon, + C: ConnectionCommon, { /// Create a new RPC channel. pub fn new(send: C::SendSink, recv: C::RecvStream) -> Self { @@ -109,7 +109,7 @@ impl RpcChannel where S: Service, SC: Service, - C: ConnectionCommon, + C: ConnectionCommon, { /// Map this channel's service into an inner service. /// @@ -139,6 +139,7 @@ where pub struct Accepting> { send: C::SendSink, recv: C::RecvStream, + p: PhantomData, } impl> Accepting { @@ -154,7 +155,7 @@ impl> Accepting { pub async fn read_first( self, ) -> result::Result<(S::Req, RpcChannel), RpcServerError> { - let Accepting { send, mut recv } = self; + let Accepting { send, mut recv, .. } = self; // get the first message from the client. This will tell us what it wants to do. let request: S::Req = recv .next() @@ -172,7 +173,11 @@ impl> RpcServer { /// can be used to read the first request. pub async fn accept(&self) -> result::Result, RpcServerError> { let (send, recv) = self.source.accept().await.map_err(RpcServerError::Accept)?; - Ok(Accepting { send, recv }) + Ok(Accepting { + send, + recv, + p: PhantomData, + }) } /// Get the underlying service endpoint @@ -202,13 +207,13 @@ pub struct UpdateStream( where SC: Service, S: Service, - C: ConnectionCommon; + C: ConnectionCommon; impl UpdateStream where SC: Service, S: Service, - C: ConnectionCommon, + C: ConnectionCommon, T: TryFrom, { pub(crate) fn new( @@ -225,7 +230,7 @@ impl Stream for UpdateStream where SC: Service, S: Service, - C: ConnectionCommon, + C: ConnectionCommon, T: TryFrom, { type Item = T; diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index ced3829..17cea21 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -230,7 +230,9 @@ impl Clone for Connection { } } -impl ConnectionCommon for Connection { +impl ConnectionCommon for Connection { + type In = In; + type Out = Out; type RecvStream = RecvStream; type SendSink = SendSink; } @@ -241,7 +243,7 @@ impl ConnectionErrors for Connection { type RecvError = anyhow::Error; } -impl super::Connection for Connection { +impl super::Connection for Connection { async fn open(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { self.0.open_boxed().await } @@ -278,7 +280,9 @@ impl Clone for ServerEndpoint { } } -impl ConnectionCommon for ServerEndpoint { +impl ConnectionCommon for ServerEndpoint { + type In = In; + type Out = Out; type RecvStream = RecvStream; type SendSink = SendSink; } @@ -289,7 +293,7 @@ impl ConnectionErrors for ServerEndpoint super::ServerEndpoint for ServerEndpoint { +impl super::ServerEndpoint for ServerEndpoint { fn accept( &self, ) -> impl Future> + Send diff --git a/src/transport/combined.rs b/src/transport/combined.rs index 8c27805..9628dd6 100644 --- a/src/transport/combined.rs +++ b/src/transport/combined.rs @@ -13,42 +13,31 @@ use std::{ }; /// A connection that combines two other connections -pub struct CombinedConnection { +pub struct CombinedConnection { /// First connection pub a: Option, /// Second connection pub b: Option, - /// Phantom data so we can have `S` as type parameters - _p: PhantomData<(In, Out)>, } -impl, B: Connection, In, Out> CombinedConnection { +impl> CombinedConnection { /// Create a combined connection from two other connections /// /// It will always use the first connection that is not `None`. pub fn new(a: Option, b: Option) -> Self { - Self { - a, - b, - _p: PhantomData, - } + Self { a, b } } } -impl Clone - for CombinedConnection -{ +impl Clone for CombinedConnection { fn clone(&self) -> Self { Self { a: self.a.clone(), b: self.b.clone(), - _p: PhantomData, } } } -impl Debug - for CombinedConnection -{ +impl Debug for CombinedConnection { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CombinedConnection") .field("a", &self.a) @@ -58,20 +47,16 @@ impl Debug } /// An endpoint that combines two other endpoints -pub struct CombinedServerEndpoint { +pub struct CombinedServerEndpoint { /// First endpoint pub a: Option, /// Second endpoint pub b: Option, /// Local addresses from all endpoints local_addr: Vec, - /// Phantom data so we can have `S` as type parameters - _p: PhantomData<(In, Out)>, } -impl, B: ServerEndpoint, In: RpcMessage, Out: RpcMessage> - CombinedServerEndpoint -{ +impl> CombinedServerEndpoint { /// Create a combined server endpoint from two other server endpoints /// /// When listening for incoming connections with @@ -86,12 +71,7 @@ impl, B: ServerEndpoint, In: RpcMessage, Out if let Some(b) = &b { local_addr.extend(b.local_addr().iter().cloned()) }; - Self { - a, - b, - local_addr, - _p: PhantomData, - } + Self { a, b, local_addr } } /// Get back the inner endpoints @@ -100,22 +80,17 @@ impl, B: ServerEndpoint, In: RpcMessage, Out } } -impl Clone - for CombinedServerEndpoint -{ +impl Clone for CombinedServerEndpoint { fn clone(&self) -> Self { Self { a: self.a.clone(), b: self.b.clone(), local_addr: self.local_addr.clone(), - _p: PhantomData, } } } -impl Debug - for CombinedServerEndpoint -{ +impl Debug for CombinedServerEndpoint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CombinedServerEndpoint") .field("a", &self.a) @@ -126,24 +101,15 @@ impl Debug /// Send sink for combined channels #[pin_project(project = SendSinkProj)] -pub enum SendSink< - A: ConnectionCommon, - B: ConnectionCommon, - In: RpcMessage, - Out: RpcMessage, -> { +pub enum SendSink { /// A variant A(#[pin] A::SendSink), /// B variant B(#[pin] B::SendSink), } -impl< - A: ConnectionCommon, - B: ConnectionCommon, - In: RpcMessage, - Out: RpcMessage, - > Sink for SendSink +impl> Sink + for SendSink { type Error = self::SendError; @@ -154,7 +120,7 @@ impl< } } - fn start_send(self: Pin<&mut Self>, item: Out) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, item: A::Out) -> Result<(), Self::Error> { match self.project() { SendSinkProj::A(sink) => sink.start_send(item).map_err(Self::Error::A), SendSinkProj::B(sink) => sink.start_send(item).map_err(Self::Error::B), @@ -178,26 +144,17 @@ impl< /// RecvStream for combined channels #[pin_project(project = ResStreamProj)] -pub enum RecvStream< - A: ConnectionCommon, - B: ConnectionCommon, - In: RpcMessage, - Out: RpcMessage, -> { +pub enum RecvStream { /// A variant A(#[pin] A::RecvStream), /// B variant B(#[pin] B::RecvStream), } -impl< - A: ConnectionCommon, - B: ConnectionCommon, - In: RpcMessage, - Out: RpcMessage, - > Stream for RecvStream +impl> Stream + for RecvStream { - type Item = Result>; + type Item = Result>; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { match self.project() { @@ -277,23 +234,23 @@ impl fmt::Display for AcceptBiError error::Error for AcceptBiError {} -impl ConnectionErrors - for CombinedConnection -{ +impl ConnectionErrors for CombinedConnection { type SendError = self::SendError; type RecvError = self::RecvError; type OpenError = self::OpenBiError; } -impl, B: Connection, In: RpcMessage, Out: RpcMessage> - ConnectionCommon for CombinedConnection +impl> ConnectionCommon + for CombinedConnection { - type RecvStream = self::RecvStream; - type SendSink = self::SendSink; + type In = A::In; + type Out = A::Out; + type RecvStream = self::RecvStream; + type SendSink = self::SendSink; } -impl, B: Connection, In: RpcMessage, Out: RpcMessage> - Connection for CombinedConnection +impl> Connection + for CombinedConnection { async fn open(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { let this = self.clone(); @@ -310,23 +267,23 @@ impl, B: Connection, In: RpcMessage, Out: RpcMes } } -impl ConnectionErrors - for CombinedServerEndpoint -{ +impl ConnectionErrors for CombinedServerEndpoint { type SendError = self::SendError; type RecvError = self::RecvError; type OpenError = self::AcceptBiError; } -impl, B: ServerEndpoint, In: RpcMessage, Out: RpcMessage> - ConnectionCommon for CombinedServerEndpoint +impl> ConnectionCommon + for CombinedServerEndpoint { - type RecvStream = self::RecvStream; - type SendSink = self::SendSink; + type In = A::In; + type Out = A::Out; + type RecvStream = self::RecvStream; + type SendSink = self::SendSink; } -impl, B: ServerEndpoint, In: RpcMessage, Out: RpcMessage> - ServerEndpoint for CombinedServerEndpoint +impl> ServerEndpoint + for CombinedServerEndpoint { async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { let a_fut = async { @@ -374,8 +331,6 @@ mod tests { let channel = combined::CombinedConnection::< flume::FlumeConnection<(), ()>, flume::FlumeConnection<(), ()>, - (), - (), >::new(None, None); let res = channel.open().await; assert!(matches!(res, Err(OpenBiError::NoChannel))); diff --git a/src/transport/flume.rs b/src/transport/flume.rs index f12e0f6..78b0dff 100644 --- a/src/transport/flume.rs +++ b/src/transport/flume.rs @@ -195,12 +195,14 @@ impl Future for AcceptBiFuture { } } -impl ConnectionCommon for FlumeServerEndpoint { +impl ConnectionCommon for FlumeServerEndpoint { + type In = In; + type Out = Out; type SendSink = SendSink; type RecvStream = RecvStream; } -impl ServerEndpoint for FlumeServerEndpoint { +impl ServerEndpoint for FlumeServerEndpoint { #[allow(refining_impl_trait)] fn accept(&self) -> AcceptBiFuture { AcceptBiFuture { @@ -222,12 +224,14 @@ impl ConnectionErrors for FlumeConnection ConnectionCommon for FlumeConnection { +impl ConnectionCommon for FlumeConnection { + type In = In; + type Out = Out; type SendSink = SendSink; type RecvStream = RecvStream; } -impl Connection for FlumeConnection { +impl Connection for FlumeConnection { #[allow(refining_impl_trait)] fn open(&self) -> OpenBiFuture { let (local_send, remote_recv) = flume::bounded::(128); diff --git a/src/transport/hyper.rs b/src/transport/hyper.rs index 42be44b..ee21f6c 100644 --- a/src/transport/hyper.rs +++ b/src/transport/hyper.rs @@ -582,13 +582,14 @@ impl ConnectionErrors for HyperConnection ConnectionCommon for HyperConnection { +impl ConnectionCommon for HyperConnection { + type In = In; + type Out = Out; type RecvStream = self::RecvStream; - type SendSink = self::SendSink; } -impl Connection for HyperConnection { +impl Connection for HyperConnection { async fn open(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { let (out_tx, out_rx) = flume::bounded::>(32); let req: Request = Request::post(&self.inner.uri) @@ -617,12 +618,14 @@ impl ConnectionErrors for HyperServerEndpoint ConnectionCommon for HyperServerEndpoint { +impl ConnectionCommon for HyperServerEndpoint { + type In = In; + type Out = Out; type RecvStream = self::RecvStream; type SendSink = self::SendSink; } -impl ServerEndpoint for HyperServerEndpoint { +impl ServerEndpoint for HyperServerEndpoint { fn local_addr(&self) -> &[LocalAddr] { &self.local_addr } diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index f6295ae..2a8b6c4 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -1,35 +1,33 @@ //! Transport with mapped input and output types. use std::{ fmt::{Debug, Display}, - iter::Rev, marker::PhantomData, task::{Context, Poll}, }; use futures_lite::{Stream, StreamExt}; -use futures_sink::Sink; use futures_util::SinkExt; use pin_project::pin_project; -use crate::{server::RpcChannel, RpcError, RpcMessage, Service, ServiceEndpoint}; +use crate::{server::RpcChannel, RpcError, RpcMessage, Service}; use super::{Connection, ConnectionCommon, ConnectionErrors}; /// A connection that maps input and output types #[derive(Debug)] -pub struct MappedConnection { +pub struct MappedConnection { inner: T, - _phantom: std::marker::PhantomData<(In, Out, In0, Out0)>, + _phantom: std::marker::PhantomData<(In, Out)>, } -impl MappedConnection +impl MappedConnection where - T: Connection, - In: TryFrom, - OutT: From, + C: Connection, + In: TryFrom, + C::Out: From, { /// Create a new mapped connection - pub fn new(inner: T) -> Self { + pub fn new(inner: C) -> Self { Self { inner, _phantom: std::marker::PhantomData, @@ -37,9 +35,9 @@ where } } -impl Clone for MappedConnection +impl Clone for MappedConnection where - T: Clone, + C: Clone, { fn clone(&self) -> Self { Self { @@ -49,54 +47,52 @@ where } } -impl ConnectionErrors for MappedConnection +impl ConnectionErrors for MappedConnection where In: RpcMessage, Out: RpcMessage, - InT: RpcMessage, - OutT: RpcMessage, - T: ConnectionErrors, -{ - type OpenError = T::OpenError; - type RecvError = ErrorOrMapError; - type SendError = T::SendError; -} - -impl ConnectionCommon for MappedConnection -where - T: ConnectionCommon, - In: RpcMessage, - Out: RpcMessage, - InT: RpcMessage, - OutT: RpcMessage, - In: TryFrom, - OutT: From, + C: ConnectionErrors, { - type RecvStream = MappedRecvStream; - type SendSink = MappedSendSink; + type OpenError = C::OpenError; + type RecvError = ErrorOrMapError; + type SendError = C::SendError; } -impl Connection for MappedConnection -where - T: Connection, - In: RpcMessage, - Out: RpcMessage, - InT: RpcMessage, - OutT: RpcMessage, - In: TryFrom, - OutT: From, -{ - fn open( - &self, - ) -> impl std::future::Future> - + Send { - let inner = self.inner.open(); - async move { - let (send, recv) = inner.await?; - Ok((MappedSendSink::new(send), MappedRecvStream::new(recv))) - } - } -} +// impl ConnectionCommon for MappedConnection +// where +// T: ConnectionCommon, +// In: RpcMessage, +// Out: RpcMessage, +// InT: RpcMessage, +// OutT: RpcMessage, +// In: TryFrom, +// OutT: From, +// { +// type RecvStream = MappedRecvStream; +// type SendSink = MappedSendSink; +// } + +// impl Connection for MappedConnection +// where +// T: Connection, +// In: RpcMessage, +// Out: RpcMessage, +// InT: RpcMessage, +// OutT: RpcMessage, +// In: TryFrom, +// OutT: From, +// { +// fn open( +// &self, +// ) -> impl std::future::Future> +// + Send { +// let inner = self.inner.open(); +// async move { +// let (send, recv) = inner.await?; +// Ok((MappedSendSink::new(send), MappedRecvStream::new(recv))) +// } +// } +// } /// A combinator that maps a stream of incoming messages to a different type #[pin_project] @@ -208,9 +204,9 @@ where } /// Extension trait for mapping connections -pub trait ConnectionMapExt: Connection { +pub trait ConnectionMapExt: Connection { /// Map the input and output types of this connection - fn map(self) -> MappedConnection + fn map(self) -> MappedConnection where In1: TryFrom, Out: From, @@ -219,7 +215,7 @@ pub trait ConnectionMapExt: Connection { } /// Map this connection to a service - fn map_to_service(self) -> MappedConnection + fn map_to_service(self) -> MappedConnection where S::Res: TryFrom, Out: From, @@ -228,29 +224,27 @@ pub trait ConnectionMapExt: Connection { } } -impl, In, Out> ConnectionMapExt for T {} +impl ConnectionMapExt for C {} /// Connection types for a mapped connection -pub struct MappedConnectionTypes(PhantomData<(In, Out, In0, Out0, C)>); +pub struct MappedConnectionTypes(PhantomData<(In, Out, C)>); -impl Debug for MappedConnectionTypes { +impl Debug for MappedConnectionTypes { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MappedConnectionTypes").finish() } } -impl Clone for MappedConnectionTypes { +impl Clone for MappedConnectionTypes { fn clone(&self) -> Self { Self(PhantomData) } } -impl ConnectionErrors for MappedConnectionTypes +impl ConnectionErrors for MappedConnectionTypes where In: RpcMessage, Out: RpcMessage, - In0: RpcMessage, - Out0: RpcMessage, C: ConnectionErrors, { type OpenError = C::OpenError; @@ -258,39 +252,38 @@ where type SendError = C::SendError; } -impl ConnectionCommon - for MappedConnectionTypes +impl ConnectionCommon for MappedConnectionTypes where - C: ConnectionCommon, + C: ConnectionCommon, In: RpcMessage, Out: RpcMessage, - In0: RpcMessage, - Out0: RpcMessage, - In: TryFrom, - Out0: From, + In: TryFrom, + C::Out: From, { + type In = In; + type Out = Out; type RecvStream = MappedRecvStream; - type SendSink = MappedSendSink; + type SendSink = MappedSendSink; } /// #[derive(Debug)] -pub struct RpcChannel2> { +pub struct RpcChannel2> { /// Sink to send responses to the client. pub send: C::SendSink, /// Stream to receive requests from the client. pub recv: C::RecvStream, + + _phantom: PhantomData, } impl RpcChannel2 where S: Service, - C: ConnectionCommon, + C: ConnectionCommon, { /// Map the input and output types of this connection - pub fn map2( - self, - ) -> RpcChannel2> + pub fn map2(self) -> RpcChannel2> where S1: Service, S1::Req: TryFrom, @@ -299,33 +292,29 @@ where RpcChannel2 { send: MappedSendSink::new(self.send), recv: MappedRecvStream::new(self.recv), + _phantom: PhantomData, } } } -struct StreamPair { - pub send: Send, - pub recv: Recv, -} - -impl StreamPair { - pub fn new(send: Send, recv: Recv) -> Self { - Self { send, recv } - } - - pub fn map( - self, - ) -> StreamPair, MappedRecvStream> +impl RpcChannel +where + S: Service, + SC: Service, + C: ConnectionCommon, +{ + /// Map the input and output types of this connection + pub fn map2(self) -> RpcChannel, S1> where - Send: futures_sink::Sink + Unpin, - Recv: Stream> + Unpin, - Out0: From, - In: TryFrom, + S1: Service, + S1::Req: TryFrom, + SC::Res: From, { - StreamPair::new( - MappedSendSink::new(self.send), - MappedRecvStream::new(self.recv), - ) + RpcChannel { + send: MappedSendSink::new(self.send), + recv: MappedRecvStream::new(self.recv), + map: todo!(), + } } } @@ -374,7 +363,7 @@ mod tests { async fn smoke() -> TestResult<()> { async fn handle_sub_request( req: String, - chan: RpcChannel>, + chan: RpcChannel>, ) -> anyhow::Result<()> { Ok(()) } @@ -382,9 +371,8 @@ mod tests { crate::transport::flume::connection::(32); let _x = c.clone().map::(); let _y = c.clone().map_to_service::(); - let _z = RpcClient::::new(c.map_to_service::()); let s = RpcServer::::new(s); - + return Ok(()); while let Ok(accepting) = s.accept().await { let (msg, chan) = accepting.read_first().await?; match msg { diff --git a/src/transport/misc/mod.rs b/src/transport/misc/mod.rs index 84d6de0..dec902d 100644 --- a/src/transport/misc/mod.rs +++ b/src/transport/misc/mod.rs @@ -1,40 +1,42 @@ //! Miscellaneous transport utilities -use futures_lite::stream; -use futures_sink::Sink; - -use crate::{ - transport::{ConnectionErrors, ServerEndpoint}, - RpcMessage, -}; -use std::convert::Infallible; - -use super::ConnectionCommon; - -/// A dummy server endpoint that does nothing -/// -/// This can be useful as a default if you want to configure -/// an optional server endpoint. -#[derive(Debug, Clone, Default)] -pub struct DummyServerEndpoint; - -impl ConnectionErrors for DummyServerEndpoint { - type OpenError = Infallible; - type RecvError = Infallible; - type SendError = Infallible; -} - -impl ConnectionCommon for DummyServerEndpoint { - type RecvStream = stream::Pending>; - type SendSink = Box + Unpin + Send + Sync>; -} - -impl ServerEndpoint for DummyServerEndpoint { - async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { - futures_lite::future::pending().await - } - - fn local_addr(&self) -> &[super::LocalAddr] { - &[] - } -} +// use futures_lite::stream; +// use futures_sink::Sink; + +// use crate::{ +// transport::{ConnectionErrors, ServerEndpoint}, +// RpcMessage, +// }; +// use std::convert::Infallible; + +// use super::ConnectionCommon; + +// /// A dummy server endpoint that does nothing +// /// +// /// This can be useful as a default if you want to configure +// /// an optional server endpoint. +// #[derive(Debug, Clone, Default)] +// pub struct DummyServerEndpoint; + +// impl ConnectionErrors for DummyServerEndpoint { +// type OpenError = Infallible; +// type RecvError = Infallible; +// type SendError = Infallible; +// } + +// impl ConnectionCommon for DummyServerEndpoint { +// type In = In; +// type Out = Out; +// type RecvStream = stream::Pending>; +// type SendSink = Box + Unpin + Send + Sync>; +// } + +// impl ServerEndpoint for DummyServerEndpoint { +// async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { +// futures_lite::future::pending().await +// } + +// fn local_addr(&self) -> &[super::LocalAddr] { +// &[] +// } +// } diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 8385a7e..e30a337 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -56,17 +56,25 @@ pub trait ConnectionErrors: Debug + Clone + Send + Sync + 'static { /// Types that are common to both [`Connection`] and [`ServerEndpoint`]. /// /// Having this as a separate trait is useful when writing generic code that works with both. -pub trait ConnectionCommon: ConnectionErrors { +pub trait ConnectionCommon: ConnectionErrors { + /// The type of messages that can be received on the channel + type In: RpcMessage; + /// The type of messages that can be sent on the channel + type Out: RpcMessage; /// Receive side of a bidirectional typed channel - type RecvStream: Stream> + Send + Sync + Unpin + 'static; + type RecvStream: Stream> + + Send + + Sync + + Unpin + + 'static; /// Send side of a bidirectional typed channel - type SendSink: Sink + Send + Sync + Unpin + 'static; + type SendSink: Sink + Send + Sync + Unpin + 'static; } /// A connection to a specific remote machine /// /// A connection can be used to open bidirectional typed channels using [`Connection::open`]. -pub trait Connection: ConnectionCommon { +pub trait Connection: ConnectionCommon { /// Open a channel to the remote che fn open( &self, @@ -77,7 +85,7 @@ pub trait Connection: ConnectionCommon { /// /// A server endpoint can be used to accept bidirectional typed channels from any of the /// currently opened connections to clients, using [`ServerEndpoint::accept`]. -pub trait ServerEndpoint: ConnectionCommon { +pub trait ServerEndpoint: ConnectionCommon { /// Accept a new typed bidirectional channel on any of the connections we /// have currently opened. fn accept( diff --git a/src/transport/quinn.rs b/src/transport/quinn.rs index 577551b..9e7fdf9 100644 --- a/src/transport/quinn.rs +++ b/src/transport/quinn.rs @@ -195,12 +195,14 @@ impl ConnectionErrors for QuinnServerEndpoint ConnectionCommon for QuinnServerEndpoint { +impl ConnectionCommon for QuinnServerEndpoint { + type In = In; + type Out = Out; type SendSink = self::SendSink; type RecvStream = self::RecvStream; } -impl ServerEndpoint for QuinnServerEndpoint { +impl ServerEndpoint for QuinnServerEndpoint { async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), AcceptBiError> { let (send, recv) = self .inner @@ -626,12 +628,14 @@ impl ConnectionErrors for QuinnConnection ConnectionCommon for QuinnConnection { +impl ConnectionCommon for QuinnConnection { + type In = In; + type Out = Out; type SendSink = self::SendSink; type RecvStream = self::RecvStream; } -impl Connection for QuinnConnection { +impl Connection for QuinnConnection { async fn open(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { let (sender, receiver) = oneshot::channel(); self.inner diff --git a/tests/util.rs b/tests/util.rs index 428aa76..6565748 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -2,7 +2,7 @@ use anyhow::Context; use quic_rpc::{server::RpcServerError, transport::Connection, RpcMessage}; #[allow(unused)] -pub async fn check_termination_anyhow>( +pub async fn check_termination_anyhow( server_handle: tokio::task::JoinHandle>, ) -> anyhow::Result<()> { // dropping the client will cause the server to terminate From 57b842f2738abd46097bc97bc057ce2e72784bf4 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 1 Nov 2024 22:09:44 +0200 Subject: [PATCH 04/32] It works! --- examples/modularize.rs | 1076 ++++++++++++++------------- src/macros.rs | 2 +- src/pattern/bidi_streaming.rs | 11 +- src/pattern/client_streaming.rs | 11 +- src/pattern/rpc.rs | 7 +- src/pattern/server_streaming.rs | 7 +- src/pattern/try_server_streaming.rs | 11 +- src/server.rs | 74 +- src/transport/combined.rs | 2 - src/transport/mapped.rs | 24 +- tests/flume.rs | 4 +- tests/math.rs | 8 +- 12 files changed, 608 insertions(+), 629 deletions(-) diff --git a/examples/modularize.rs b/examples/modularize.rs index 1b19a2d..c91942e 100644 --- a/examples/modularize.rs +++ b/examples/modularize.rs @@ -1,537 +1,539 @@ -//! This example shows how an RPC service can be modularized, even between different crates. -//! -//! * `app` module is the top level. it composes `iroh` plus one handler of the app itself -//! * `iroh` module composes two other services, `calc` and `clock` -//! -//! The [`calc`] and [`clock`] modules both expose a [`quic_rpc::Service`] in a regular fashion. -//! They do not `use` anything from `super` or `app` so they could live in their own crates -//! unchanged. - -use anyhow::Result; -use futures_lite::StreamExt; -use futures_util::SinkExt; -use quic_rpc::{transport::flume, RpcClient, RpcServer, ServiceConnection, ServiceEndpoint}; -use tracing::warn; - -use app::AppService; - -#[tokio::main] -async fn main() -> Result<()> { - // Spawn an inmemory connection. - // Could use quic equally (all code in this example is generic over the transport) - let (server_conn, client_conn) = flume::service_connection::(1); - - // spawn the server - let handler = app::Handler::default(); - tokio::task::spawn(run_server(server_conn, handler)); - - // run a client demo - client_demo(client_conn).await?; - - Ok(()) -} - -async fn run_server>(server_conn: C, handler: app::Handler) { - let server = RpcServer::::new(server_conn); - loop { - let Ok(accepting) = server.accept().await else { - continue; - }; - match accepting.read_first().await { - Err(err) => warn!(?err, "server accept failed"), - Ok((req, chan)) => { - let handler = handler.clone(); - tokio::task::spawn(async move { - if let Err(err) = handler.handle_rpc_request(req, chan).await { - warn!(?err, "internal rpc error"); - } - }); - } - } - } -} -pub async fn client_demo>(conn: C) -> Result<()> { - let rpc_client = RpcClient::new(conn); - let client = app::Client::new(rpc_client.clone()); - - // call a method from the top-level app client - let res = client.app_version().await?; - println!("app_version: {res:?}"); - - // call a method from the wrapped iroh.calc client - let res = client.iroh.calc.add(40, 2).await?; - println!("iroh.calc.add: {res:?}"); - - // can also do "raw" calls without using the wrapped clients - let res = rpc_client - .clone() - .map::() - .map::() - .rpc(calc::AddRequest(19, 4)) - .await?; - println!("iroh.calc.add (raw): {res:?}"); - - let (mut sink, res) = rpc_client - .map::() - .map::() - .client_streaming(calc::SumRequest) - .await?; - sink.send(calc::SumUpdate(4)).await.unwrap(); - sink.send(calc::SumUpdate(8)).await.unwrap(); - sink.send(calc::SumUpdate(30)).await.unwrap(); - drop(sink); - let res = res.await?; - println!("iroh.calc.sum (raw): {res:?}"); - - // call a server-streaming method from the wrapped iroh.clock client - let mut stream = client.iroh.clock.tick().await?; - while let Some(tick) = stream.try_next().await? { - println!("iroh.clock.tick: {tick}"); - } - Ok(()) -} - -mod app { - //! This is the app-specific code. - //! - //! It composes all of `iroh` (which internally composes two other modules) and adds an - //! application specific RPC. - //! - //! It could also easily compose services from other crates or internal modules. - - use anyhow::Result; - use derive_more::{From, TryInto}; - use quic_rpc::{ - message::RpcMsg, server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint, - }; - use serde::{Deserialize, Serialize}; - - use super::iroh; - - #[derive(Debug, Serialize, Deserialize, From, TryInto)] - pub enum Request { - Iroh(iroh::Request), - AppVersion(AppVersionRequest), - } - - #[derive(Debug, Serialize, Deserialize, From, TryInto)] - pub enum Response { - Iroh(iroh::Response), - AppVersion(AppVersionResponse), - } - - #[derive(Debug, Serialize, Deserialize)] - pub struct AppVersionRequest; - - impl RpcMsg for AppVersionRequest { - type Response = AppVersionResponse; - } - - #[derive(Debug, Serialize, Deserialize)] - pub struct AppVersionResponse(pub String); - - #[derive(Copy, Clone, Debug)] - pub struct AppService; - impl Service for AppService { - type Req = Request; - type Res = Response; - } - - #[derive(Clone)] - pub struct Handler { - iroh: iroh::Handler, - app_version: String, - } - - impl Default for Handler { - fn default() -> Self { - Self { - iroh: iroh::Handler::default(), - app_version: "v0.1-alpha".to_string(), - } - } - } - - impl Handler { - pub async fn handle_rpc_request>( - self, - req: Request, - chan: RpcChannel, - ) -> Result<()> { - match req { - Request::Iroh(req) => self.iroh.handle_rpc_request(req, chan.map()).await?, - Request::AppVersion(req) => chan.rpc(req, self, Self::on_version).await?, - }; - Ok(()) - } - - pub async fn on_version(self, _req: AppVersionRequest) -> AppVersionResponse { - AppVersionResponse(self.app_version.clone()) - } - } - - #[derive(Debug, Clone)] - pub struct Client> { - pub iroh: iroh::Client, - client: RpcClient, - } - - impl Client - where - S: Service, - C: ServiceConnection, - { - pub fn new(client: RpcClient) -> Self { - Self { - iroh: iroh::Client::new(client.clone().map()), - client, - } - } - - pub async fn app_version(&self) -> Result { - let res = self.client.rpc(AppVersionRequest).await?; - Ok(res.0) - } - } -} - -mod iroh { - //! This module composes two sub-services. Think `iroh` crate which exposes services and - //! clients for iroh-bytes and iroh-gossip or so. - //! It uses only the `calc` and `clock` modules and nothing else. - - use anyhow::Result; - use derive_more::{From, TryInto}; - use quic_rpc::{server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint}; - use serde::{Deserialize, Serialize}; - - use super::{calc, clock}; - - #[derive(Debug, Serialize, Deserialize, From, TryInto)] - pub enum Request { - Calc(calc::Request), - Clock(clock::Request), - } - - #[derive(Debug, Serialize, Deserialize, From, TryInto)] - pub enum Response { - Calc(calc::Response), - Clock(clock::Response), - } - - #[derive(Copy, Clone, Debug)] - pub struct IrohService; - impl Service for IrohService { - type Req = Request; - type Res = Response; - } - - #[derive(Clone, Default)] - pub struct Handler { - calc: calc::Handler, - clock: clock::Handler, - } - - impl Handler { - pub async fn handle_rpc_request( - self, - req: Request, - chan: RpcChannel, - ) -> Result<()> - where - S: Service, - E: ServiceEndpoint, - { - match req { - Request::Calc(req) => self.calc.handle_rpc_request(req, chan.map()).await?, - Request::Clock(req) => self.clock.handle_rpc_request(req, chan.map()).await?, - } - Ok(()) - } - } - - #[derive(Debug, Clone)] - pub struct Client { - pub calc: calc::Client, - pub clock: clock::Client, - } - - impl Client - where - S: Service, - C: ServiceConnection, - { - pub fn new(client: RpcClient) -> Self { - Self { - calc: calc::Client::new(client.clone().map()), - clock: clock::Client::new(client.clone().map()), - } - } - } -} - -mod calc { - //! This is a library providing a service, and a client. E.g. iroh-bytes or iroh-hypermerge. - //! It does not use any `super` imports, it is completely decoupled. - - use anyhow::{bail, Result}; - use derive_more::{From, TryInto}; - use futures_lite::{Stream, StreamExt}; - use quic_rpc::{ - message::{ClientStreaming, ClientStreamingMsg, Msg, RpcMsg}, - server::RpcChannel, - RpcClient, Service, ServiceConnection, ServiceEndpoint, - }; - use serde::{Deserialize, Serialize}; - use std::fmt::Debug; - - #[derive(Debug, Serialize, Deserialize)] - pub struct AddRequest(pub i64, pub i64); - - impl RpcMsg for AddRequest { - type Response = AddResponse; - } - - #[derive(Debug, Serialize, Deserialize)] - pub struct AddResponse(pub i64); - - #[derive(Debug, Serialize, Deserialize)] - pub struct SumRequest; - - #[derive(Debug, Serialize, Deserialize)] - pub struct SumUpdate(pub i64); - - impl Msg for SumRequest { - type Pattern = ClientStreaming; - } - - impl ClientStreamingMsg for SumRequest { - type Update = SumUpdate; - type Response = SumResponse; - } - - #[derive(Debug, Serialize, Deserialize)] - pub struct SumResponse(pub i64); - - #[derive(Debug, Serialize, Deserialize, From, TryInto)] - pub enum Request { - Add(AddRequest), - Sum(SumRequest), - SumUpdate(SumUpdate), - } - - #[derive(Debug, Serialize, Deserialize, From, TryInto)] - pub enum Response { - Add(AddResponse), - Sum(SumResponse), - } - - #[derive(Copy, Clone, Debug)] - pub struct CalcService; - impl Service for CalcService { - type Req = Request; - type Res = Response; - } - - #[derive(Clone, Default)] - pub struct Handler; - - impl Handler { - pub async fn handle_rpc_request( - self, - req: Request, - chan: RpcChannel, - ) -> Result<()> - where - S: Service, - E: ServiceEndpoint, - { - match req { - Request::Add(req) => chan.rpc(req, self, Self::on_add).await?, - Request::Sum(req) => chan.client_streaming(req, self, Self::on_sum).await?, - Request::SumUpdate(_) => bail!("Unexpected update message at start of request"), - } - Ok(()) - } - - pub async fn on_add(self, req: AddRequest) -> AddResponse { - AddResponse(req.0 + req.1) - } - - pub async fn on_sum( - self, - _req: SumRequest, - updates: impl Stream, - ) -> SumResponse { - let mut sum = 0i64; - tokio::pin!(updates); - while let Some(SumUpdate(n)) = updates.next().await { - sum += n; - } - SumResponse(sum) - } - } - - #[derive(Debug, Clone)] - pub struct Client { - client: RpcClient, - } - - impl Client - where - C: ServiceConnection, - S: Service, - { - pub fn new(client: RpcClient) -> Self { - Self { client } - } - pub async fn add(&self, a: i64, b: i64) -> anyhow::Result { - let res = self.client.rpc(AddRequest(a, b)).await?; - Ok(res.0) - } - } -} - -mod clock { - //! This is a library providing a service, and a client. E.g. iroh-bytes or iroh-hypermerge. - //! It does not use any `super` imports, it is completely decoupled. - - use anyhow::Result; - use derive_more::{From, TryInto}; - use futures_lite::{stream::Boxed as BoxStream, Stream, StreamExt}; - use futures_util::TryStreamExt; - use quic_rpc::{ - message::{Msg, ServerStreaming, ServerStreamingMsg}, - server::RpcChannel, - RpcClient, Service, ServiceConnection, ServiceEndpoint, - }; - use serde::{Deserialize, Serialize}; - use std::{ - fmt::Debug, - sync::{Arc, RwLock}, - time::Duration, - }; - use tokio::sync::Notify; - - #[derive(Debug, Serialize, Deserialize)] - pub struct TickRequest; - - impl Msg for TickRequest { - type Pattern = ServerStreaming; - } - - impl ServerStreamingMsg for TickRequest { - type Response = TickResponse; - } - - #[derive(Debug, Serialize, Deserialize)] - pub struct TickResponse { - tick: usize, - } - - #[derive(Debug, Serialize, Deserialize, From, TryInto)] - pub enum Request { - Tick(TickRequest), - } - - #[derive(Debug, Serialize, Deserialize, From, TryInto)] - pub enum Response { - Tick(TickResponse), - } - - #[derive(Copy, Clone, Debug)] - pub struct ClockService; - impl Service for ClockService { - type Req = Request; - type Res = Response; - } - - #[derive(Clone)] - pub struct Handler { - tick: Arc>, - ontick: Arc, - } - - impl Default for Handler { - fn default() -> Self { - Self::new(Duration::from_secs(1)) - } - } - - impl Handler { - pub fn new(tick_duration: Duration) -> Self { - let h = Handler { - tick: Default::default(), - ontick: Default::default(), - }; - let h2 = h.clone(); - tokio::task::spawn(async move { - loop { - tokio::time::sleep(tick_duration).await; - *h2.tick.write().unwrap() += 1; - h2.ontick.notify_waiters(); - } - }); - h - } - - pub async fn handle_rpc_request( - self, - req: Request, - chan: RpcChannel, - ) -> Result<()> - where - S: Service, - E: ServiceEndpoint, - { - match req { - Request::Tick(req) => chan.server_streaming(req, self, Self::on_tick).await?, - } - Ok(()) - } - - pub fn on_tick( - self, - req: TickRequest, - ) -> impl Stream + Send + 'static { - let (tx, rx) = flume::bounded(2); - tokio::task::spawn(async move { - if let Err(err) = self.on_tick0(req, tx).await { - tracing::warn!(?err, "on_tick RPC handler failed"); - } - }); - rx.into_stream() - } - - pub async fn on_tick0( - self, - _req: TickRequest, - tx: flume::Sender, - ) -> Result<()> { - loop { - let tick = *self.tick.read().unwrap(); - tx.send_async(TickResponse { tick }).await?; - self.ontick.notified().await; - } - } - } - - #[derive(Debug, Clone)] - pub struct Client { - client: RpcClient, - } - - impl Client - where - C: ServiceConnection, - S: Service, - { - pub fn new(client: RpcClient) -> Self { - Self { client } - } - pub async fn tick(&self) -> Result>> { - let res = self.client.server_streaming(TickRequest).await?; - Ok(res.map_ok(|r| r.tick).map_err(anyhow::Error::from).boxed()) - } - } -} +// //! This example shows how an RPC service can be modularized, even between different crates. +// //! +// //! * `app` module is the top level. it composes `iroh` plus one handler of the app itself +// //! * `iroh` module composes two other services, `calc` and `clock` +// //! +// //! The [`calc`] and [`clock`] modules both expose a [`quic_rpc::Service`] in a regular fashion. +// //! They do not `use` anything from `super` or `app` so they could live in their own crates +// //! unchanged. + +// use anyhow::Result; +// use futures_lite::StreamExt; +// use futures_util::SinkExt; +// use quic_rpc::{transport::flume, RpcClient, RpcServer, ServiceConnection, ServiceEndpoint}; +// use tracing::warn; + +// use app::AppService; + +// #[tokio::main] +// async fn main() -> Result<()> { +// // Spawn an inmemory connection. +// // Could use quic equally (all code in this example is generic over the transport) +// let (server_conn, client_conn) = flume::service_connection::(1); + +// // spawn the server +// let handler = app::Handler::default(); +// tokio::task::spawn(run_server(server_conn, handler)); + +// // run a client demo +// client_demo(client_conn).await?; + +// Ok(()) +// } + +// async fn run_server>(server_conn: C, handler: app::Handler) { +// let server = RpcServer::::new(server_conn); +// loop { +// let Ok(accepting) = server.accept().await else { +// continue; +// }; +// match accepting.read_first().await { +// Err(err) => warn!(?err, "server accept failed"), +// Ok((req, chan)) => { +// let handler = handler.clone(); +// tokio::task::spawn(async move { +// if let Err(err) = handler.handle_rpc_request(req, chan).await { +// warn!(?err, "internal rpc error"); +// } +// }); +// } +// } +// } +// } +// pub async fn client_demo>(conn: C) -> Result<()> { +// let rpc_client = RpcClient::new(conn); +// let client = app::Client::new(rpc_client.clone()); + +// // call a method from the top-level app client +// let res = client.app_version().await?; +// println!("app_version: {res:?}"); + +// // call a method from the wrapped iroh.calc client +// let res = client.iroh.calc.add(40, 2).await?; +// println!("iroh.calc.add: {res:?}"); + +// // can also do "raw" calls without using the wrapped clients +// let res = rpc_client +// .clone() +// .map::() +// .map::() +// .rpc(calc::AddRequest(19, 4)) +// .await?; +// println!("iroh.calc.add (raw): {res:?}"); + +// let (mut sink, res) = rpc_client +// .map::() +// .map::() +// .client_streaming(calc::SumRequest) +// .await?; +// sink.send(calc::SumUpdate(4)).await.unwrap(); +// sink.send(calc::SumUpdate(8)).await.unwrap(); +// sink.send(calc::SumUpdate(30)).await.unwrap(); +// drop(sink); +// let res = res.await?; +// println!("iroh.calc.sum (raw): {res:?}"); + +// // call a server-streaming method from the wrapped iroh.clock client +// let mut stream = client.iroh.clock.tick().await?; +// while let Some(tick) = stream.try_next().await? { +// println!("iroh.clock.tick: {tick}"); +// } +// Ok(()) +// } + +// mod app { +// //! This is the app-specific code. +// //! +// //! It composes all of `iroh` (which internally composes two other modules) and adds an +// //! application specific RPC. +// //! +// //! It could also easily compose services from other crates or internal modules. + +// use anyhow::Result; +// use derive_more::{From, TryInto}; +// use quic_rpc::{ +// message::RpcMsg, server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint, +// }; +// use serde::{Deserialize, Serialize}; + +// use super::iroh; + +// #[derive(Debug, Serialize, Deserialize, From, TryInto)] +// pub enum Request { +// Iroh(iroh::Request), +// AppVersion(AppVersionRequest), +// } + +// #[derive(Debug, Serialize, Deserialize, From, TryInto)] +// pub enum Response { +// Iroh(iroh::Response), +// AppVersion(AppVersionResponse), +// } + +// #[derive(Debug, Serialize, Deserialize)] +// pub struct AppVersionRequest; + +// impl RpcMsg for AppVersionRequest { +// type Response = AppVersionResponse; +// } + +// #[derive(Debug, Serialize, Deserialize)] +// pub struct AppVersionResponse(pub String); + +// #[derive(Copy, Clone, Debug)] +// pub struct AppService; +// impl Service for AppService { +// type Req = Request; +// type Res = Response; +// } + +// #[derive(Clone)] +// pub struct Handler { +// iroh: iroh::Handler, +// app_version: String, +// } + +// impl Default for Handler { +// fn default() -> Self { +// Self { +// iroh: iroh::Handler::default(), +// app_version: "v0.1-alpha".to_string(), +// } +// } +// } + +// impl Handler { +// pub async fn handle_rpc_request>( +// self, +// req: Request, +// chan: RpcChannel, +// ) -> Result<()> { +// match req { +// Request::Iroh(req) => self.iroh.handle_rpc_request(req, chan.map()).await?, +// Request::AppVersion(req) => chan.rpc(req, self, Self::on_version).await?, +// }; +// Ok(()) +// } + +// pub async fn on_version(self, _req: AppVersionRequest) -> AppVersionResponse { +// AppVersionResponse(self.app_version.clone()) +// } +// } + +// #[derive(Debug, Clone)] +// pub struct Client> { +// pub iroh: iroh::Client, +// client: RpcClient, +// } + +// impl Client +// where +// S: Service, +// C: ServiceConnection, +// { +// pub fn new(client: RpcClient) -> Self { +// Self { +// iroh: iroh::Client::new(client.clone().map()), +// client, +// } +// } + +// pub async fn app_version(&self) -> Result { +// let res = self.client.rpc(AppVersionRequest).await?; +// Ok(res.0) +// } +// } +// } + +// mod iroh { +// //! This module composes two sub-services. Think `iroh` crate which exposes services and +// //! clients for iroh-bytes and iroh-gossip or so. +// //! It uses only the `calc` and `clock` modules and nothing else. + +// use anyhow::Result; +// use derive_more::{From, TryInto}; +// use quic_rpc::{server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint}; +// use serde::{Deserialize, Serialize}; + +// use super::{calc, clock}; + +// #[derive(Debug, Serialize, Deserialize, From, TryInto)] +// pub enum Request { +// Calc(calc::Request), +// Clock(clock::Request), +// } + +// #[derive(Debug, Serialize, Deserialize, From, TryInto)] +// pub enum Response { +// Calc(calc::Response), +// Clock(clock::Response), +// } + +// #[derive(Copy, Clone, Debug)] +// pub struct IrohService; +// impl Service for IrohService { +// type Req = Request; +// type Res = Response; +// } + +// #[derive(Clone, Default)] +// pub struct Handler { +// calc: calc::Handler, +// clock: clock::Handler, +// } + +// impl Handler { +// pub async fn handle_rpc_request( +// self, +// req: Request, +// chan: RpcChannel, +// ) -> Result<()> +// where +// S: Service, +// E: ServiceEndpoint, +// { +// match req { +// Request::Calc(req) => self.calc.handle_rpc_request(req, chan.map()).await?, +// Request::Clock(req) => self.clock.handle_rpc_request(req, chan.map()).await?, +// } +// Ok(()) +// } +// } + +// #[derive(Debug, Clone)] +// pub struct Client { +// pub calc: calc::Client, +// pub clock: clock::Client, +// } + +// impl Client +// where +// S: Service, +// C: ServiceConnection, +// { +// pub fn new(client: RpcClient) -> Self { +// Self { +// calc: calc::Client::new(client.clone().map()), +// clock: clock::Client::new(client.clone().map()), +// } +// } +// } +// } + +// mod calc { +// //! This is a library providing a service, and a client. E.g. iroh-bytes or iroh-hypermerge. +// //! It does not use any `super` imports, it is completely decoupled. + +// use anyhow::{bail, Result}; +// use derive_more::{From, TryInto}; +// use futures_lite::{Stream, StreamExt}; +// use quic_rpc::{ +// message::{ClientStreaming, ClientStreamingMsg, Msg, RpcMsg}, +// server::RpcChannel, +// RpcClient, Service, ServiceConnection, ServiceEndpoint, +// }; +// use serde::{Deserialize, Serialize}; +// use std::fmt::Debug; + +// #[derive(Debug, Serialize, Deserialize)] +// pub struct AddRequest(pub i64, pub i64); + +// impl RpcMsg for AddRequest { +// type Response = AddResponse; +// } + +// #[derive(Debug, Serialize, Deserialize)] +// pub struct AddResponse(pub i64); + +// #[derive(Debug, Serialize, Deserialize)] +// pub struct SumRequest; + +// #[derive(Debug, Serialize, Deserialize)] +// pub struct SumUpdate(pub i64); + +// impl Msg for SumRequest { +// type Pattern = ClientStreaming; +// } + +// impl ClientStreamingMsg for SumRequest { +// type Update = SumUpdate; +// type Response = SumResponse; +// } + +// #[derive(Debug, Serialize, Deserialize)] +// pub struct SumResponse(pub i64); + +// #[derive(Debug, Serialize, Deserialize, From, TryInto)] +// pub enum Request { +// Add(AddRequest), +// Sum(SumRequest), +// SumUpdate(SumUpdate), +// } + +// #[derive(Debug, Serialize, Deserialize, From, TryInto)] +// pub enum Response { +// Add(AddResponse), +// Sum(SumResponse), +// } + +// #[derive(Copy, Clone, Debug)] +// pub struct CalcService; +// impl Service for CalcService { +// type Req = Request; +// type Res = Response; +// } + +// #[derive(Clone, Default)] +// pub struct Handler; + +// impl Handler { +// pub async fn handle_rpc_request( +// self, +// req: Request, +// chan: RpcChannel, +// ) -> Result<()> +// where +// S: Service, +// E: ServiceEndpoint, +// { +// match req { +// Request::Add(req) => chan.rpc(req, self, Self::on_add).await?, +// Request::Sum(req) => chan.client_streaming(req, self, Self::on_sum).await?, +// Request::SumUpdate(_) => bail!("Unexpected update message at start of request"), +// } +// Ok(()) +// } + +// pub async fn on_add(self, req: AddRequest) -> AddResponse { +// AddResponse(req.0 + req.1) +// } + +// pub async fn on_sum( +// self, +// _req: SumRequest, +// updates: impl Stream, +// ) -> SumResponse { +// let mut sum = 0i64; +// tokio::pin!(updates); +// while let Some(SumUpdate(n)) = updates.next().await { +// sum += n; +// } +// SumResponse(sum) +// } +// } + +// #[derive(Debug, Clone)] +// pub struct Client { +// client: RpcClient, +// } + +// impl Client +// where +// C: ServiceConnection, +// S: Service, +// { +// pub fn new(client: RpcClient) -> Self { +// Self { client } +// } +// pub async fn add(&self, a: i64, b: i64) -> anyhow::Result { +// let res = self.client.rpc(AddRequest(a, b)).await?; +// Ok(res.0) +// } +// } +// } + +// mod clock { +// //! This is a library providing a service, and a client. E.g. iroh-bytes or iroh-hypermerge. +// //! It does not use any `super` imports, it is completely decoupled. + +// use anyhow::Result; +// use derive_more::{From, TryInto}; +// use futures_lite::{stream::Boxed as BoxStream, Stream, StreamExt}; +// use futures_util::TryStreamExt; +// use quic_rpc::{ +// message::{Msg, ServerStreaming, ServerStreamingMsg}, +// server::RpcChannel, +// RpcClient, Service, ServiceConnection, ServiceEndpoint, +// }; +// use serde::{Deserialize, Serialize}; +// use std::{ +// fmt::Debug, +// sync::{Arc, RwLock}, +// time::Duration, +// }; +// use tokio::sync::Notify; + +// #[derive(Debug, Serialize, Deserialize)] +// pub struct TickRequest; + +// impl Msg for TickRequest { +// type Pattern = ServerStreaming; +// } + +// impl ServerStreamingMsg for TickRequest { +// type Response = TickResponse; +// } + +// #[derive(Debug, Serialize, Deserialize)] +// pub struct TickResponse { +// tick: usize, +// } + +// #[derive(Debug, Serialize, Deserialize, From, TryInto)] +// pub enum Request { +// Tick(TickRequest), +// } + +// #[derive(Debug, Serialize, Deserialize, From, TryInto)] +// pub enum Response { +// Tick(TickResponse), +// } + +// #[derive(Copy, Clone, Debug)] +// pub struct ClockService; +// impl Service for ClockService { +// type Req = Request; +// type Res = Response; +// } + +// #[derive(Clone)] +// pub struct Handler { +// tick: Arc>, +// ontick: Arc, +// } + +// impl Default for Handler { +// fn default() -> Self { +// Self::new(Duration::from_secs(1)) +// } +// } + +// impl Handler { +// pub fn new(tick_duration: Duration) -> Self { +// let h = Handler { +// tick: Default::default(), +// ontick: Default::default(), +// }; +// let h2 = h.clone(); +// tokio::task::spawn(async move { +// loop { +// tokio::time::sleep(tick_duration).await; +// *h2.tick.write().unwrap() += 1; +// h2.ontick.notify_waiters(); +// } +// }); +// h +// } + +// pub async fn handle_rpc_request( +// self, +// req: Request, +// chan: RpcChannel, +// ) -> Result<()> +// where +// S: Service, +// E: ServiceEndpoint, +// { +// match req { +// Request::Tick(req) => chan.server_streaming(req, self, Self::on_tick).await?, +// } +// Ok(()) +// } + +// pub fn on_tick( +// self, +// req: TickRequest, +// ) -> impl Stream + Send + 'static { +// let (tx, rx) = flume::bounded(2); +// tokio::task::spawn(async move { +// if let Err(err) = self.on_tick0(req, tx).await { +// tracing::warn!(?err, "on_tick RPC handler failed"); +// } +// }); +// rx.into_stream() +// } + +// pub async fn on_tick0( +// self, +// _req: TickRequest, +// tx: flume::Sender, +// ) -> Result<()> { +// loop { +// let tick = *self.tick.read().unwrap(); +// tx.send_async(TickResponse { tick }).await?; +// self.ontick.notified().await; +// } +// } +// } + +// #[derive(Debug, Clone)] +// pub struct Client { +// client: RpcClient, +// } + +// impl Client +// where +// C: ServiceConnection, +// S: Service, +// { +// pub fn new(client: RpcClient) -> Self { +// Self { client } +// } +// pub async fn tick(&self) -> Result>> { +// let res = self.client.server_streaming(TickRequest).await?; +// Ok(res.map_ok(|r| r.tick).map_err(anyhow::Error::from).boxed()) +// } +// } +// } + +fn main() {} diff --git a/src/macros.rs b/src/macros.rs index 208dae0..650e406 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -199,7 +199,7 @@ macro_rules! __derive_create_dispatch { macro_rules! $create_dispatch { ($target:ident, $handler:ident) => { pub async fn $handler>( - mut chan: $crate::server::RpcChannel<$service, C, $service>, + mut chan: $crate::server::RpcChannel<$service, C>, msg: <$service as $crate::Service>::Req, target: $target, ) -> Result<(), $crate::server::RpcServerError> { diff --git a/src/pattern/bidi_streaming.rs b/src/pattern/bidi_streaming.rs index c571c51..4ec145b 100644 --- a/src/pattern/bidi_streaming.rs +++ b/src/pattern/bidi_streaming.rs @@ -113,10 +113,9 @@ where } } -impl RpcChannel +impl RpcChannel where - SC: Service, - C: ConnectionCommon, + C: ConnectionCommon, S: Service, { /// handle the message M using the given function on the target object @@ -130,20 +129,20 @@ where ) -> result::Result<(), RpcServerError> where M: BidiStreamingMsg, - F: FnOnce(T, M, UpdateStream) -> Str + Send + 'static, + F: FnOnce(T, M, UpdateStream) -> Str + Send + 'static, Str: Stream + Send + 'static, T: Send + 'static, { let Self { mut send, recv, .. } = self; // downcast the updates - let (updates, read_error) = UpdateStream::new(recv, Arc::clone(&self.map)); + let (updates, read_error) = UpdateStream::new(recv); // get the response let responses = f(target, req, updates); race2(read_error.map(Err), async move { tokio::pin!(responses); while let Some(response) = responses.next().await { // turn into a S::Res so we can send it - let response = self.map.res_into_outer(response.into()); + let response = response.into(); // send it and return the error if any send.send(response) .await diff --git a/src/pattern/client_streaming.rs b/src/pattern/client_streaming.rs index 3775fd0..bac8e5d 100644 --- a/src/pattern/client_streaming.rs +++ b/src/pattern/client_streaming.rs @@ -120,11 +120,10 @@ where } } -impl RpcChannel +impl RpcChannel where S: Service, - C: ConnectionCommon, - SC: Service, + C: ConnectionCommon, { /// handle the message M using the given function on the target object /// @@ -137,17 +136,17 @@ where ) -> result::Result<(), RpcServerError> where M: ClientStreamingMsg, - F: FnOnce(T, M, UpdateStream) -> Fut + Send + 'static, + F: FnOnce(T, M, UpdateStream) -> Fut + Send + 'static, Fut: Future + Send + 'static, T: Send + 'static, { let Self { mut send, recv, .. } = self; - let (updates, read_error) = UpdateStream::new(recv, Arc::clone(&self.map)); + let (updates, read_error) = UpdateStream::new(recv); race2(read_error.map(Err), async move { // get the response let res = f(target, req, updates).await; // turn into a S::Res so we can send it - let res = self.map.res_into_outer(res.into()); + let res = res.into(); // send it and return the error if any send.send(res).await.map_err(RpcServerError::SendError) }) diff --git a/src/pattern/rpc.rs b/src/pattern/rpc.rs index 4545dca..448d68e 100644 --- a/src/pattern/rpc.rs +++ b/src/pattern/rpc.rs @@ -91,11 +91,10 @@ where } } -impl RpcChannel +impl RpcChannel where S: Service, - C: ConnectionCommon, - SC: Service, + C: ConnectionCommon, { /// handle the message of type `M` using the given function on the target object /// @@ -124,7 +123,7 @@ where // get the response let res = f(target, req).await; // turn into a S::Res so we can send it - let res = self.map.res_into_outer(res.into()); + let res = res.into(); // send it and return the error if any send.send(res).await.map_err(RpcServerError::SendError) }) diff --git a/src/pattern/server_streaming.rs b/src/pattern/server_streaming.rs index d744bec..911cf6d 100644 --- a/src/pattern/server_streaming.rs +++ b/src/pattern/server_streaming.rs @@ -100,11 +100,10 @@ where } } -impl RpcChannel +impl RpcChannel where S: Service, - C: ConnectionCommon, - SC: Service, + C: ConnectionCommon, { /// handle the message M using the given function on the target object /// @@ -135,7 +134,7 @@ where tokio::pin!(responses); while let Some(response) = responses.next().await { // turn into a S::Res so we can send it - let response = self.map.res_into_outer(response.into()); + let response = response.into(); // send it and return the error if any send.send(response) .await diff --git a/src/pattern/try_server_streaming.rs b/src/pattern/try_server_streaming.rs index 98ba89b..c79ce12 100644 --- a/src/pattern/try_server_streaming.rs +++ b/src/pattern/try_server_streaming.rs @@ -98,10 +98,9 @@ impl fmt::Display for ItemError { impl error::Error for ItemError {} -impl RpcChannel +impl RpcChannel where - SC: Service, - C: ConnectionCommon, + C: ConnectionCommon, S: Service, { /// handle the message M using the given function on the target object @@ -138,7 +137,7 @@ where let responses = match f(target, req).await { Ok(responses) => { // turn into a S::Res so we can send it - let response = self.map.res_into_outer(Ok(StreamCreated).into()); + let response = Ok(StreamCreated).into(); // send it and return the error if any send.send(response) .await @@ -147,7 +146,7 @@ where } Err(cause) => { // turn into a S::Res so we can send it - let response = self.map.res_into_outer(Err(cause).into()); + let response = Err(cause).into(); // send it and return the error if any send.send(response) .await @@ -158,7 +157,7 @@ where tokio::pin!(responses); while let Some(response) = responses.next().await { // turn into a S::Res so we can send it - let response = self.map.res_into_outer(response.into()); + let response = response.into(); // send it and return the error if any send.send(response) .await diff --git a/src/server.rs b/src/server.rs index dfb691e..182e667 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,8 +2,7 @@ //! //! The main entry point is [RpcServer] use crate::{ - map::{ChainedMapper, MapService, Mapper}, - transport::{ConnectionCommon, ConnectionErrors}, + transport::{mapped::{MappedConnectionTypes, MappedRecvStream, MappedSendSink}, ConnectionCommon, ConnectionErrors}, Service, ServiceEndpoint, }; use futures_lite::{Future, Stream, StreamExt}; @@ -14,7 +13,6 @@ use std::{ marker::PhantomData, pin::Pin, result, - sync::Arc, task::{self, Poll}, }; use tokio::sync::oneshot; @@ -79,18 +77,17 @@ impl> RpcServer { #[derive(Debug)] pub struct RpcChannel< S: Service, - C: ConnectionCommon = BoxedServiceEndpoint, - SC: Service = S, + C: ConnectionCommon = BoxedServiceEndpoint, > { /// Sink to send responses to the client. pub send: C::SendSink, /// Stream to receive requests from the client. pub recv: C::RecvStream, - /// Mapper to map between S and S2 - pub map: Arc>, + + pub(crate) p: PhantomData, } -impl RpcChannel +impl RpcChannel where S: Service, C: ConnectionCommon, @@ -100,16 +97,15 @@ where Self { send, recv, - map: Arc::new(Mapper::new()), + p: PhantomData, } } } -impl RpcChannel +impl RpcChannel where S: Service, - SC: Service, - C: ConnectionCommon, + C: ConnectionCommon, { /// Map this channel's service into an inner service. /// @@ -120,17 +116,16 @@ where /// Where SNext is the new service to map to and S is the current inner service. /// /// This method can be chained infintely. - pub fn map(self) -> RpcChannel + pub fn map(self) -> RpcChannel> where SNext: Service, - SNext::Req: Into + TryFrom, - SNext::Res: Into + TryFrom, + SNext::Req: TryFrom, + S::Res: From, { - let map = ChainedMapper::new(self.map); RpcChannel { - send: self.send, - recv: self.recv, - map: Arc::new(map), + send: MappedSendSink::new(self.send), + recv: MappedRecvStream::new(self.recv), + p: PhantomData, } } } @@ -152,9 +147,7 @@ impl> Accepting { /// /// Often sink and stream will wrap an an underlying byte stream. In this case you can /// call into_inner() on them to get it back to perform byte level reads and writes. - pub async fn read_first( - self, - ) -> result::Result<(S::Req, RpcChannel), RpcServerError> { + pub async fn read_first(self) -> result::Result<(S::Req, RpcChannel), RpcServerError> { let Accepting { send, mut recv, .. } = self; // get the first message from the client. This will tell us what it wants to do. let request: S::Req = recv @@ -164,7 +157,7 @@ impl> Accepting { .ok_or(RpcServerError::EarlyClose)? // recv error .map_err(RpcServerError::RecvError)?; - Ok((request, RpcChannel::new(send, recv))) + Ok((request, RpcChannel::::new(send, recv))) } } @@ -198,40 +191,30 @@ impl> AsRef for RpcServer { /// cause a termination of the RPC call. #[pin_project] #[derive(Debug)] -pub struct UpdateStream( +pub struct UpdateStream( #[pin] C::RecvStream, Option>>, PhantomData, - Arc>, ) where - SC: Service, - S: Service, - C: ConnectionCommon; + C: ConnectionCommon; -impl UpdateStream +impl UpdateStream where - SC: Service, - S: Service, - C: ConnectionCommon, - T: TryFrom, + C: ConnectionCommon, + T: TryFrom, { - pub(crate) fn new( - recv: C::RecvStream, - map: Arc>, - ) -> (Self, UnwrapToPending>) { + pub(crate) fn new(recv: C::RecvStream) -> (Self, UnwrapToPending>) { let (error_send, error_recv) = oneshot::channel(); let error_recv = UnwrapToPending(error_recv); - (Self(recv, Some(error_send), PhantomData, map), error_recv) + (Self(recv, Some(error_send), PhantomData), error_recv) } } -impl Stream for UpdateStream +impl Stream for UpdateStream where - SC: Service, - S: Service, - C: ConnectionCommon, - T: TryFrom, + C: ConnectionCommon, + T: TryFrom, { type Item = T; @@ -240,8 +223,7 @@ where match Pin::new(&mut this.0).poll_next(cx) { Poll::Ready(Some(msg)) => match msg { Ok(msg) => { - let msg = this.3.req_try_into_inner(msg); - let msg = msg.and_then(|msg| T::try_from(msg).map_err(|_cause| ())); + let msg = T::try_from(msg).map_err(|_cause| ()); match msg { Ok(msg) => Poll::Ready(Some(msg)), Err(_cause) => { @@ -339,7 +321,7 @@ where S: Service, C: ServiceEndpoint, T: Clone + Send + 'static, - F: FnMut(RpcChannel, S::Req, T) -> Fut + Send + 'static, + F: FnMut(RpcChannel, S::Req, T) -> Fut + Send + 'static, Fut: Future>> + Send + 'static, { let server: RpcServer = RpcServer::::new(conn); diff --git a/src/transport/combined.rs b/src/transport/combined.rs index 9628dd6..366c07e 100644 --- a/src/transport/combined.rs +++ b/src/transport/combined.rs @@ -1,13 +1,11 @@ //! Transport that combines two other transports use super::{Connection, ConnectionCommon, ConnectionErrors, LocalAddr, ServerEndpoint}; -use crate::RpcMessage; use futures_lite::Stream; use futures_sink::Sink; use pin_project::pin_project; use std::{ error, fmt, fmt::Debug, - marker::PhantomData, pin::Pin, task::{Context, Poll}, }; diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index 2a8b6c4..f6b508b 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -297,24 +297,26 @@ where } } -impl RpcChannel +impl RpcChannel where S: Service, - SC: Service, - C: ConnectionCommon, + C: ConnectionCommon, { /// Map the input and output types of this connection - pub fn map2(self) -> RpcChannel, S1> + pub fn map2(self) -> RpcChannel> where S1: Service, - S1::Req: TryFrom, - SC::Res: From, + S1::Req: TryFrom, + S::Res: From, { - RpcChannel { - send: MappedSendSink::new(self.send), - recv: MappedRecvStream::new(self.recv), - map: todo!(), - } + let send = MappedSendSink::::new(self.send); + let recv = MappedRecvStream::::new(self.recv); + let t: RpcChannel> = RpcChannel { + send, + recv, + p: PhantomData, + }; + t } } diff --git a/tests/flume.rs b/tests/flume.rs index 54f211e..1a7517e 100644 --- a/tests/flume.rs +++ b/tests/flume.rs @@ -73,8 +73,8 @@ async fn flume_channel_mapped_bench() -> anyhow::Result<()> { let req: OuterRequest = req; match req { OuterRequest::Inner(InnerRequest::Compute(req)) => { - let chan: RpcChannel = chan.map(); - let chan: RpcChannel = chan.map(); + let chan: RpcChannel = chan.map(); + let chan: RpcChannel = chan.map(); ComputeService::handle_rpc_request(service, req, chan).await } } diff --git a/tests/math.rs b/tests/math.rs index 94794f3..30a0774 100644 --- a/tests/math.rs +++ b/tests/math.rs @@ -15,6 +15,7 @@ use quic_rpc::{ ServerStreaming, ServerStreamingMsg, }, server::{RpcChannel, RpcServerError}, + transport::ConnectionCommon, RpcClient, RpcServer, Service, ServiceConnection, ServiceEndpoint, }; use serde::{Deserialize, Serialize}; @@ -172,14 +173,13 @@ impl ComputeService { } } - pub async fn handle_rpc_request( + pub async fn handle_rpc_request( service: ComputeService, req: ComputeRequest, - chan: RpcChannel, + chan: RpcChannel, ) -> Result<(), RpcServerError> where - S: Service, - E: ServiceEndpoint, + E: ConnectionCommon, { use ComputeRequest::*; #[rustfmt::skip] From 41e21ebfd285f82c2017659977a834512da7a44d Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 1 Nov 2024 23:30:21 +0200 Subject: [PATCH 05/32] Even more conversion --- examples/modularize.rs | 1 - src/client.rs | 68 ++++++++++++----------------- src/pattern/bidi_streaming.rs | 19 +++----- src/pattern/client_streaming.rs | 20 +++------ src/pattern/rpc.rs | 11 ++--- src/pattern/server_streaming.rs | 15 ++----- src/pattern/try_server_streaming.rs | 12 ++--- src/server.rs | 5 ++- src/transport/mapped.rs | 68 ++++++++++++++--------------- tests/flume.rs | 4 +- tests/math.rs | 5 +-- 11 files changed, 91 insertions(+), 137 deletions(-) diff --git a/examples/modularize.rs b/examples/modularize.rs index c91942e..975e8ad 100644 --- a/examples/modularize.rs +++ b/examples/modularize.rs @@ -535,5 +535,4 @@ // } // } // } - fn main() {} diff --git a/src/client.rs b/src/client.rs index bda3c3f..5f47f05 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,7 +2,10 @@ //! //! The main entry point is [RpcClient]. use crate::{ - map::{ChainedMapper, MapService, Mapper}, + transport::{ + mapped::MappedConnection, + ConnectionCommon, + }, Service, ServiceConnection, }; use futures_lite::Stream; @@ -13,7 +16,6 @@ use std::{ fmt::Debug, marker::PhantomData, pin::Pin, - sync::Arc, task::{Context, Poll}, }; @@ -32,19 +34,18 @@ pub type BoxStreamSync<'a, T> = Pin + Send + Sync + 'a> /// Type parameters: /// /// `S` is the service type that determines what interactions this client supports. -/// `SC` is the service type that is compatible with the connection. /// `C` is the substream source. #[derive(Debug)] -pub struct RpcClient, SC = S> { +pub struct RpcClient> { pub(crate) source: C, - pub(crate) map: Arc>, + pub(crate) p: PhantomData, } -impl Clone for RpcClient { +impl Clone for RpcClient { fn clone(&self) -> Self { Self { source: self.source.clone(), - map: Arc::clone(&self.map), + p: PhantomData, } } } @@ -53,23 +54,15 @@ impl Clone for RpcClient { /// that support it, [crate::message::ClientStreaming] and [crate::message::BidiStreaming]. #[pin_project] #[derive(Debug)] -pub struct UpdateSink( - #[pin] pub C::SendSink, - pub PhantomData, - pub Arc>, -) +pub struct UpdateSink(#[pin] pub C::SendSink, pub PhantomData) where - SC: Service, - S: Service, - C: ServiceConnection, - T: Into; + C: ConnectionCommon, + T: Into; -impl Sink for UpdateSink +impl Sink for UpdateSink where - SC: Service, - S: Service, - C: ServiceConnection, - T: Into, + C: ConnectionCommon, + T: Into, { type Error = C::SendError; @@ -78,7 +71,7 @@ where } fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { - let req = self.2.req_into_outer(item.into()); + let req = item.into(); self.project().0.start_send(req) } @@ -91,7 +84,7 @@ where } } -impl RpcClient +impl RpcClient where S: Service, C: ServiceConnection, @@ -101,24 +94,21 @@ where /// /// This is where a generic typed connection is converted into a client for a specific service. /// - /// When creating a new client, the outer service type `S` and the inner - /// service type `SC` that is compatible with the underlying connection will - /// be identical. - /// /// You can get a client for a nested service by calling [map](RpcClient::map). pub fn new(source: C) -> Self { Self { source, - map: Arc::new(Mapper::new()), + p: PhantomData, } } } -impl RpcClient +use crate::transport::mapped::ConnectionMapExt; + +impl RpcClient where S: Service, - SC: Service, - C: ServiceConnection, + C: ServiceConnection, { /// Get the underlying connection pub fn into_inner(self) -> C { @@ -134,25 +124,23 @@ where /// Where SNext is the new service to map to and S is the current inner service. /// /// This method can be chained infintely. - pub fn map(self) -> RpcClient + pub fn map(self) -> RpcClient> where SNext: Service, - SNext::Req: Into + TryFrom, - SNext::Res: Into + TryFrom, + S::Req: From, + SNext::Res: TryFrom, { - let map = ChainedMapper::new(self.map); RpcClient { - source: self.source, - map: Arc::new(map), + source: self.source.map::(), + p: PhantomData, } } } -impl AsRef for RpcClient +impl AsRef for RpcClient where S: Service, - SC: Service, - C: ServiceConnection, + C: ServiceConnection, { fn as_ref(&self) -> &C { &self.source diff --git a/src/pattern/bidi_streaming.rs b/src/pattern/bidi_streaming.rs index 4ec145b..201ccd2 100644 --- a/src/pattern/bidi_streaming.rs +++ b/src/pattern/bidi_streaming.rs @@ -75,10 +75,9 @@ impl fmt::Display for ItemError { impl error::Error for ItemError {} -impl RpcClient +impl RpcClient where - SC: Service, - C: ServiceConnection, + C: ServiceConnection, S: Service, { /// Bidi call to the server, request opens a stream, response is a stream @@ -87,7 +86,7 @@ where msg: M, ) -> result::Result< ( - UpdateSink, + UpdateSink, BoxStreamSync<'static, result::Result>>, ), Error, @@ -95,18 +94,12 @@ where where M: BidiStreamingMsg, { - let msg = self.map.req_into_outer(msg.into()); + let msg = msg.into(); let (mut send, recv) = self.source.open().await.map_err(Error::Open)?; send.send(msg).await.map_err(Error::::Send)?; - let send = UpdateSink(send, PhantomData, Arc::clone(&self.map)); - let map = Arc::clone(&self.map); + let send = UpdateSink(send, PhantomData); let recv = Box::pin(recv.map(move |x| match x { - Ok(x) => { - let x = map - .res_try_into_inner(x) - .map_err(|_| ItemError::DowncastError)?; - M::Response::try_from(x).map_err(|_| ItemError::DowncastError) - } + Ok(msg) => M::Response::try_from(msg).map_err(|_| ItemError::DowncastError), Err(e) => Err(ItemError::RecvError(e)), })); Ok((send, recv)) diff --git a/src/pattern/client_streaming.rs b/src/pattern/client_streaming.rs index bac8e5d..5262908 100644 --- a/src/pattern/client_streaming.rs +++ b/src/pattern/client_streaming.rs @@ -16,7 +16,6 @@ use std::{ fmt::{self, Debug}, marker::PhantomData, result, - sync::Arc, }; /// Client streaming interaction pattern @@ -77,11 +76,10 @@ impl fmt::Display for ItemError { impl error::Error for ItemError {} -impl RpcClient +impl RpcClient where S: Service, - SC: Service, - C: ServiceConnection, + C: ServiceConnection, { /// Call to the server that allows the client to stream, single response pub async fn client_streaming( @@ -89,7 +87,7 @@ where msg: M, ) -> result::Result< ( - UpdateSink, + UpdateSink, Boxed>>, ), Error, @@ -97,21 +95,15 @@ where where M: ClientStreamingMsg, { - let msg = self.map.req_into_outer(msg.into()); + let msg = msg.into(); let (mut send, mut recv) = self.source.open().await.map_err(Error::Open)?; send.send(msg).map_err(Error::Send).await?; - let send = UpdateSink::(send, PhantomData, Arc::clone(&self.map)); - let map = Arc::clone(&self.map); + let send = UpdateSink::(send, PhantomData); let recv = async move { let item = recv.next().await.ok_or(ItemError::EarlyClose)?; match item { - Ok(x) => { - let x = map - .res_try_into_inner(x) - .map_err(|_| ItemError::DowncastError)?; - M::Response::try_from(x).map_err(|_| ItemError::DowncastError) - } + Ok(msg) => M::Response::try_from(msg).map_err(|_| ItemError::DowncastError), Err(e) => Err(ItemError::RecvError(e)), } } diff --git a/src/pattern/rpc.rs b/src/pattern/rpc.rs index 448d68e..ed2e708 100644 --- a/src/pattern/rpc.rs +++ b/src/pattern/rpc.rs @@ -62,18 +62,17 @@ impl fmt::Display for Error { impl error::Error for Error {} -impl RpcClient +impl RpcClient where S: Service, - SC: Service, - C: ServiceConnection, + C: ServiceConnection, { /// RPC call to the server, single request, single response pub async fn rpc(&self, msg: M) -> result::Result> where M: RpcMsg, { - let msg = self.map.req_into_outer(msg.into()); + let msg = msg.into(); let (mut send, mut recv) = self.source.open().await.map_err(Error::Open)?; send.send(msg).await.map_err(Error::::Send)?; let res = recv @@ -83,10 +82,6 @@ where .map_err(Error::::RecvError)?; // keep send alive until we have the answer drop(send); - let res = self - .map - .res_try_into_inner(res) - .map_err(|_| Error::DowncastError)?; M::Response::try_from(res).map_err(|_| Error::DowncastError) } } diff --git a/src/pattern/server_streaming.rs b/src/pattern/server_streaming.rs index 911cf6d..bcf7987 100644 --- a/src/pattern/server_streaming.rs +++ b/src/pattern/server_streaming.rs @@ -67,10 +67,9 @@ impl fmt::Display for ItemError { impl error::Error for ItemError {} -impl RpcClient +impl RpcClient where - SC: Service, - C: ServiceConnection, + C: ServiceConnection, S: Service, { /// Bidi call to the server, request opens a stream, response is a stream @@ -81,17 +80,11 @@ where where M: ServerStreamingMsg, { - let msg = self.map.req_into_outer(msg.into()); + let msg = msg.into(); let (mut send, recv) = self.source.open().await.map_err(Error::Open)?; send.send(msg).map_err(Error::::Send).await?; - let map = Arc::clone(&self.map); let recv = recv.map(move |x| match x { - Ok(x) => { - let x = map - .res_try_into_inner(x) - .map_err(|_| ItemError::DowncastError)?; - M::Response::try_from(x).map_err(|_| ItemError::DowncastError) - } + Ok(msg) => M::Response::try_from(msg).map_err(|_| ItemError::DowncastError), Err(e) => Err(ItemError::RecvError(e)), }); // keep send alive so the request on the server side does not get cancelled diff --git a/src/pattern/try_server_streaming.rs b/src/pattern/try_server_streaming.rs index c79ce12..47f440d 100644 --- a/src/pattern/try_server_streaming.rs +++ b/src/pattern/try_server_streaming.rs @@ -169,10 +169,9 @@ where } } -impl RpcClient +impl RpcClient where - SC: Service, - C: ServiceConnection, + C: ServiceConnection, S: Service, { /// Bidi call to the server, request opens a stream, response is a stream @@ -188,23 +187,18 @@ where Result: Into + TryFrom, Result: Into + TryFrom, { - let msg = self.map.req_into_outer(msg.into()); + let msg = msg.into(); let (mut send, mut recv) = self.source.open().await.map_err(Error::Open)?; send.send(msg).map_err(Error::Send).await?; - let map = Arc::clone(&self.map); let Some(initial) = recv.next().await else { return Err(Error::EarlyClose); }; let initial = initial.map_err(Error::Recv)?; // initial response - let initial = map - .res_try_into_inner(initial) - .map_err(|_| Error::Downcast)?; let initial = >::try_from(initial) .map_err(|_| Error::Downcast)?; let _ = initial.map_err(Error::Application)?; let recv = recv.map(move |x| { let x = x.map_err(ItemError::Recv)?; - let x = map.res_try_into_inner(x).map_err(|_| ItemError::Downcast)?; let x = >::try_from(x) .map_err(|_| ItemError::Downcast)?; let x = x.map_err(ItemError::Application)?; diff --git a/src/server.rs b/src/server.rs index 182e667..32d078e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,7 +2,10 @@ //! //! The main entry point is [RpcServer] use crate::{ - transport::{mapped::{MappedConnectionTypes, MappedRecvStream, MappedSendSink}, ConnectionCommon, ConnectionErrors}, + transport::{ + mapped::{MappedConnectionTypes, MappedRecvStream, MappedSendSink}, + ConnectionCommon, ConnectionErrors, + }, Service, ServiceEndpoint, }; use futures_lite::{Future, Stream, StreamExt}; diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index f6b508b..ccaac86 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -58,41 +58,39 @@ where type SendError = C::SendError; } -// impl ConnectionCommon for MappedConnection -// where -// T: ConnectionCommon, -// In: RpcMessage, -// Out: RpcMessage, -// InT: RpcMessage, -// OutT: RpcMessage, -// In: TryFrom, -// OutT: From, -// { -// type RecvStream = MappedRecvStream; -// type SendSink = MappedSendSink; -// } - -// impl Connection for MappedConnection -// where -// T: Connection, -// In: RpcMessage, -// Out: RpcMessage, -// InT: RpcMessage, -// OutT: RpcMessage, -// In: TryFrom, -// OutT: From, -// { -// fn open( -// &self, -// ) -> impl std::future::Future> -// + Send { -// let inner = self.inner.open(); -// async move { -// let (send, recv) = inner.await?; -// Ok((MappedSendSink::new(send), MappedRecvStream::new(recv))) -// } -// } -// } +impl ConnectionCommon for MappedConnection +where + C: ConnectionCommon, + In: RpcMessage, + Out: RpcMessage, + In: TryFrom, + C::Out: From, +{ + type In = In; + type Out = Out; + type RecvStream = MappedRecvStream; + type SendSink = MappedSendSink; +} + +impl Connection for MappedConnection +where + C: Connection, + In: RpcMessage, + Out: RpcMessage, + In: TryFrom, + C::Out: From, +{ + fn open( + &self, + ) -> impl std::future::Future> + + Send { + let inner = self.inner.open(); + async move { + let (send, recv) = inner.await?; + Ok((MappedSendSink::new(send), MappedRecvStream::new(recv))) + } + } +} /// A combinator that maps a stream of incoming messages to a different type #[pin_project] diff --git a/tests/flume.rs b/tests/flume.rs index 1a7517e..514667b 100644 --- a/tests/flume.rs +++ b/tests/flume.rs @@ -83,8 +83,8 @@ async fn flume_channel_mapped_bench() -> anyhow::Result<()> { }); let client = RpcClient::::new(client); - let client: RpcClient = client.map(); - let client: RpcClient = client.map(); + let client: RpcClient = client.map(); + let client: RpcClient = client.map(); bench(client, 1000000).await?; // dropping the client will cause the server to terminate match server_handle.await? { diff --git a/tests/math.rs b/tests/math.rs index 30a0774..f1f890e 100644 --- a/tests/math.rs +++ b/tests/math.rs @@ -316,11 +316,10 @@ fn clear_line() { print!("\r{}\r", " ".repeat(80)); } -pub async fn bench(client: RpcClient, n: u64) -> anyhow::Result<()> +pub async fn bench(client: RpcClient, n: u64) -> anyhow::Result<()> where C::SendError: std::error::Error, - S: Service, - C: ServiceConnection, + C: ServiceConnection, { // individual RPCs { From 115753f0485d9b6575570e26e7a5b9afb9408d59 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 1 Nov 2024 23:46:04 +0200 Subject: [PATCH 06/32] Remove map.rs and some arcs --- src/lib.rs | 1 - src/map.rs | 145 ---------------------------- src/pattern/bidi_streaming.rs | 1 - src/pattern/server_streaming.rs | 1 - src/pattern/try_server_streaming.rs | 1 - src/transport/mapped.rs | 31 ------ 6 files changed, 180 deletions(-) delete mode 100644 src/map.rs diff --git a/src/lib.rs b/src/lib.rs index 320b6b1..c786cb3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,7 +102,6 @@ pub use client::RpcClient; pub use server::RpcServer; #[cfg(feature = "macros")] mod macros; -mod map; pub mod pattern; diff --git a/src/map.rs b/src/map.rs deleted file mode 100644 index 597ca93..0000000 --- a/src/map.rs +++ /dev/null @@ -1,145 +0,0 @@ -use std::{marker::PhantomData, sync::Arc}; - -use crate::Service; - -/// Convert requests and responses between an outer and an inner service. -/// -/// An "outer" service has request and response enums which wrap the requests and responses of an -/// "inner" service. This trait is implemented on the [`Mapper`] and [`ChainedMapper`] structs -/// to convert the requests and responses between the outer and inner services. -pub trait MapService: - std::fmt::Debug + Send + Sync + 'static -{ - /// Convert an inner request into the outer request. - fn req_into_outer(&self, req: SInner::Req) -> SOuter::Req; - - /// Convert an inner response into the outer response. - fn res_into_outer(&self, res: SInner::Res) -> SOuter::Res; - - /// Try to convert the outer request into the inner request. - /// - /// Returns an error if the request is not of the variant of the inner service. - fn req_try_into_inner(&self, req: SOuter::Req) -> Result; - - /// Try to convert the outer response into the inner request. - /// - /// Returns an error if the response is not of the variant of the inner service. - fn res_try_into_inner(&self, res: SOuter::Res) -> Result; -} - -/// Zero-sized struct to map between two services. -#[derive(Debug)] -pub struct Mapper(PhantomData, PhantomData); - -impl Mapper -where - SOuter: Service, - SInner: Service, - SInner::Req: Into + TryFrom, - SInner::Res: Into + TryFrom, -{ - /// Create a new mapper between `SOuter` and `SInner` services. - /// - /// This method is availalbe if the required bounds to convert between the outer and inner - /// request and response enums are met: - /// `SInner::Req: Into + TryFrom` - /// `SInner::Res: Into + TryFrom` - pub fn new() -> Self { - Self(PhantomData, PhantomData) - } -} - -impl MapService for Mapper -where - SOuter: Service, - SInner: Service, - SInner::Req: Into + TryFrom, - SInner::Res: Into + TryFrom, -{ - fn req_into_outer(&self, req: SInner::Req) -> SOuter::Req { - req.into() - } - - fn res_into_outer(&self, res: SInner::Res) -> SOuter::Res { - res.into() - } - - fn req_try_into_inner(&self, req: SOuter::Req) -> Result { - req.try_into().map_err(|_| ()) - } - - fn res_try_into_inner(&self, res: SOuter::Res) -> Result { - res.try_into().map_err(|_| ()) - } -} - -/// Map between an outer and an inner service with any number of intermediate services. -/// -/// This uses an `Arc` to contain an unlimited chain of [`Mapper`]s. -#[derive(Debug)] -pub struct ChainedMapper -where - SOuter: Service, - SMid: Service, - SInner: Service, - SInner::Req: Into + TryFrom, -{ - map1: Arc>, - map2: Mapper, -} - -impl ChainedMapper -where - SOuter: Service, - SMid: Service, - SInner: Service, - SInner::Req: Into + TryFrom, - SInner::Res: Into + TryFrom, -{ - /// Create a new [`ChainedMapper`] by appending a service `SInner` to the existing `dyn - /// MapService`. - /// - /// Usage example: - /// ```ignore - /// // S1 is a Service and impls the Into and TryFrom traits to map to S2 - /// // S2 is a Service and impls the Into and TryFrom traits to map to S3 - /// // S3 is also a Service - /// - /// let mapper: Mapper = Mapper::new(); - /// let mapper: Arc> = Arc::new(mapper); - /// let chained_mapper: ChainedMapper = ChainedMapper::new(mapper); - /// ``` - pub fn new(map1: Arc>) -> Self { - Self { - map1, - map2: Mapper::new(), - } - } -} - -impl MapService for ChainedMapper -where - SOuter: Service, - SMid: Service, - SInner: Service, - SInner::Req: Into + TryFrom, - SInner::Res: Into + TryFrom, -{ - fn req_into_outer(&self, req: SInner::Req) -> SOuter::Req { - let req = self.map2.req_into_outer(req); - self.map1.req_into_outer(req) - } - fn res_into_outer(&self, res: SInner::Res) -> SOuter::Res { - let res = self.map2.res_into_outer(res); - self.map1.res_into_outer(res) - } - fn req_try_into_inner(&self, req: SOuter::Req) -> Result { - let req = self.map1.req_try_into_inner(req)?; - self.map2.req_try_into_inner(req) - } - - fn res_try_into_inner(&self, res: SOuter::Res) -> Result { - let res = self.map1.res_try_into_inner(res)?; - self.map2.res_try_into_inner(res) - } -} diff --git a/src/pattern/bidi_streaming.rs b/src/pattern/bidi_streaming.rs index 201ccd2..c413faf 100644 --- a/src/pattern/bidi_streaming.rs +++ b/src/pattern/bidi_streaming.rs @@ -16,7 +16,6 @@ use std::{ fmt::{self, Debug}, marker::PhantomData, result, - sync::Arc, }; /// Bidirectional streaming interaction pattern diff --git a/src/pattern/server_streaming.rs b/src/pattern/server_streaming.rs index bcf7987..4ca56c5 100644 --- a/src/pattern/server_streaming.rs +++ b/src/pattern/server_streaming.rs @@ -15,7 +15,6 @@ use std::{ error, fmt::{self, Debug}, result, - sync::Arc, }; /// Server streaming interaction pattern diff --git a/src/pattern/try_server_streaming.rs b/src/pattern/try_server_streaming.rs index 47f440d..5633972 100644 --- a/src/pattern/try_server_streaming.rs +++ b/src/pattern/try_server_streaming.rs @@ -16,7 +16,6 @@ use std::{ error, fmt::{self, Debug}, result, - sync::Arc, }; /// A guard message to indicate that the stream has been created. diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index ccaac86..0a3ec9f 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -264,37 +264,6 @@ where type SendSink = MappedSendSink; } -/// -#[derive(Debug)] -pub struct RpcChannel2> { - /// Sink to send responses to the client. - pub send: C::SendSink, - /// Stream to receive requests from the client. - pub recv: C::RecvStream, - - _phantom: PhantomData, -} - -impl RpcChannel2 -where - S: Service, - C: ConnectionCommon, -{ - /// Map the input and output types of this connection - pub fn map2(self) -> RpcChannel2> - where - S1: Service, - S1::Req: TryFrom, - S::Res: From, - { - RpcChannel2 { - send: MappedSendSink::new(self.send), - recv: MappedRecvStream::new(self.recv), - _phantom: PhantomData, - } - } -} - impl RpcChannel where S: Service, From 3a916c2cc1efeb6fc1ad6f0065085612040ba50f Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Sat, 2 Nov 2024 12:30:57 +0200 Subject: [PATCH 07/32] Make modularize example work --- examples/modularize.rs | 1064 ++++++++++++++++++------------------- src/client.rs | 16 +- src/lib.rs | 5 +- src/server.rs | 34 +- src/transport/boxed.rs | 31 +- src/transport/mapped.rs | 16 +- src/transport/misc/mod.rs | 91 ++-- 7 files changed, 656 insertions(+), 601 deletions(-) diff --git a/examples/modularize.rs b/examples/modularize.rs index 975e8ad..ceb9e9b 100644 --- a/examples/modularize.rs +++ b/examples/modularize.rs @@ -1,538 +1,526 @@ -// //! This example shows how an RPC service can be modularized, even between different crates. -// //! -// //! * `app` module is the top level. it composes `iroh` plus one handler of the app itself -// //! * `iroh` module composes two other services, `calc` and `clock` -// //! -// //! The [`calc`] and [`clock`] modules both expose a [`quic_rpc::Service`] in a regular fashion. -// //! They do not `use` anything from `super` or `app` so they could live in their own crates -// //! unchanged. - -// use anyhow::Result; -// use futures_lite::StreamExt; -// use futures_util::SinkExt; -// use quic_rpc::{transport::flume, RpcClient, RpcServer, ServiceConnection, ServiceEndpoint}; -// use tracing::warn; - -// use app::AppService; - -// #[tokio::main] -// async fn main() -> Result<()> { -// // Spawn an inmemory connection. -// // Could use quic equally (all code in this example is generic over the transport) -// let (server_conn, client_conn) = flume::service_connection::(1); - -// // spawn the server -// let handler = app::Handler::default(); -// tokio::task::spawn(run_server(server_conn, handler)); - -// // run a client demo -// client_demo(client_conn).await?; - -// Ok(()) -// } - -// async fn run_server>(server_conn: C, handler: app::Handler) { -// let server = RpcServer::::new(server_conn); -// loop { -// let Ok(accepting) = server.accept().await else { -// continue; -// }; -// match accepting.read_first().await { -// Err(err) => warn!(?err, "server accept failed"), -// Ok((req, chan)) => { -// let handler = handler.clone(); -// tokio::task::spawn(async move { -// if let Err(err) = handler.handle_rpc_request(req, chan).await { -// warn!(?err, "internal rpc error"); -// } -// }); -// } -// } -// } -// } -// pub async fn client_demo>(conn: C) -> Result<()> { -// let rpc_client = RpcClient::new(conn); -// let client = app::Client::new(rpc_client.clone()); - -// // call a method from the top-level app client -// let res = client.app_version().await?; -// println!("app_version: {res:?}"); - -// // call a method from the wrapped iroh.calc client -// let res = client.iroh.calc.add(40, 2).await?; -// println!("iroh.calc.add: {res:?}"); - -// // can also do "raw" calls without using the wrapped clients -// let res = rpc_client -// .clone() -// .map::() -// .map::() -// .rpc(calc::AddRequest(19, 4)) -// .await?; -// println!("iroh.calc.add (raw): {res:?}"); - -// let (mut sink, res) = rpc_client -// .map::() -// .map::() -// .client_streaming(calc::SumRequest) -// .await?; -// sink.send(calc::SumUpdate(4)).await.unwrap(); -// sink.send(calc::SumUpdate(8)).await.unwrap(); -// sink.send(calc::SumUpdate(30)).await.unwrap(); -// drop(sink); -// let res = res.await?; -// println!("iroh.calc.sum (raw): {res:?}"); - -// // call a server-streaming method from the wrapped iroh.clock client -// let mut stream = client.iroh.clock.tick().await?; -// while let Some(tick) = stream.try_next().await? { -// println!("iroh.clock.tick: {tick}"); -// } -// Ok(()) -// } - -// mod app { -// //! This is the app-specific code. -// //! -// //! It composes all of `iroh` (which internally composes two other modules) and adds an -// //! application specific RPC. -// //! -// //! It could also easily compose services from other crates or internal modules. - -// use anyhow::Result; -// use derive_more::{From, TryInto}; -// use quic_rpc::{ -// message::RpcMsg, server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint, -// }; -// use serde::{Deserialize, Serialize}; - -// use super::iroh; - -// #[derive(Debug, Serialize, Deserialize, From, TryInto)] -// pub enum Request { -// Iroh(iroh::Request), -// AppVersion(AppVersionRequest), -// } - -// #[derive(Debug, Serialize, Deserialize, From, TryInto)] -// pub enum Response { -// Iroh(iroh::Response), -// AppVersion(AppVersionResponse), -// } - -// #[derive(Debug, Serialize, Deserialize)] -// pub struct AppVersionRequest; - -// impl RpcMsg for AppVersionRequest { -// type Response = AppVersionResponse; -// } - -// #[derive(Debug, Serialize, Deserialize)] -// pub struct AppVersionResponse(pub String); - -// #[derive(Copy, Clone, Debug)] -// pub struct AppService; -// impl Service for AppService { -// type Req = Request; -// type Res = Response; -// } - -// #[derive(Clone)] -// pub struct Handler { -// iroh: iroh::Handler, -// app_version: String, -// } - -// impl Default for Handler { -// fn default() -> Self { -// Self { -// iroh: iroh::Handler::default(), -// app_version: "v0.1-alpha".to_string(), -// } -// } -// } - -// impl Handler { -// pub async fn handle_rpc_request>( -// self, -// req: Request, -// chan: RpcChannel, -// ) -> Result<()> { -// match req { -// Request::Iroh(req) => self.iroh.handle_rpc_request(req, chan.map()).await?, -// Request::AppVersion(req) => chan.rpc(req, self, Self::on_version).await?, -// }; -// Ok(()) -// } - -// pub async fn on_version(self, _req: AppVersionRequest) -> AppVersionResponse { -// AppVersionResponse(self.app_version.clone()) -// } -// } - -// #[derive(Debug, Clone)] -// pub struct Client> { -// pub iroh: iroh::Client, -// client: RpcClient, -// } - -// impl Client -// where -// S: Service, -// C: ServiceConnection, -// { -// pub fn new(client: RpcClient) -> Self { -// Self { -// iroh: iroh::Client::new(client.clone().map()), -// client, -// } -// } - -// pub async fn app_version(&self) -> Result { -// let res = self.client.rpc(AppVersionRequest).await?; -// Ok(res.0) -// } -// } -// } - -// mod iroh { -// //! This module composes two sub-services. Think `iroh` crate which exposes services and -// //! clients for iroh-bytes and iroh-gossip or so. -// //! It uses only the `calc` and `clock` modules and nothing else. - -// use anyhow::Result; -// use derive_more::{From, TryInto}; -// use quic_rpc::{server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint}; -// use serde::{Deserialize, Serialize}; - -// use super::{calc, clock}; - -// #[derive(Debug, Serialize, Deserialize, From, TryInto)] -// pub enum Request { -// Calc(calc::Request), -// Clock(clock::Request), -// } - -// #[derive(Debug, Serialize, Deserialize, From, TryInto)] -// pub enum Response { -// Calc(calc::Response), -// Clock(clock::Response), -// } - -// #[derive(Copy, Clone, Debug)] -// pub struct IrohService; -// impl Service for IrohService { -// type Req = Request; -// type Res = Response; -// } - -// #[derive(Clone, Default)] -// pub struct Handler { -// calc: calc::Handler, -// clock: clock::Handler, -// } - -// impl Handler { -// pub async fn handle_rpc_request( -// self, -// req: Request, -// chan: RpcChannel, -// ) -> Result<()> -// where -// S: Service, -// E: ServiceEndpoint, -// { -// match req { -// Request::Calc(req) => self.calc.handle_rpc_request(req, chan.map()).await?, -// Request::Clock(req) => self.clock.handle_rpc_request(req, chan.map()).await?, -// } -// Ok(()) -// } -// } - -// #[derive(Debug, Clone)] -// pub struct Client { -// pub calc: calc::Client, -// pub clock: clock::Client, -// } - -// impl Client -// where -// S: Service, -// C: ServiceConnection, -// { -// pub fn new(client: RpcClient) -> Self { -// Self { -// calc: calc::Client::new(client.clone().map()), -// clock: clock::Client::new(client.clone().map()), -// } -// } -// } -// } - -// mod calc { -// //! This is a library providing a service, and a client. E.g. iroh-bytes or iroh-hypermerge. -// //! It does not use any `super` imports, it is completely decoupled. - -// use anyhow::{bail, Result}; -// use derive_more::{From, TryInto}; -// use futures_lite::{Stream, StreamExt}; -// use quic_rpc::{ -// message::{ClientStreaming, ClientStreamingMsg, Msg, RpcMsg}, -// server::RpcChannel, -// RpcClient, Service, ServiceConnection, ServiceEndpoint, -// }; -// use serde::{Deserialize, Serialize}; -// use std::fmt::Debug; - -// #[derive(Debug, Serialize, Deserialize)] -// pub struct AddRequest(pub i64, pub i64); - -// impl RpcMsg for AddRequest { -// type Response = AddResponse; -// } - -// #[derive(Debug, Serialize, Deserialize)] -// pub struct AddResponse(pub i64); - -// #[derive(Debug, Serialize, Deserialize)] -// pub struct SumRequest; - -// #[derive(Debug, Serialize, Deserialize)] -// pub struct SumUpdate(pub i64); - -// impl Msg for SumRequest { -// type Pattern = ClientStreaming; -// } - -// impl ClientStreamingMsg for SumRequest { -// type Update = SumUpdate; -// type Response = SumResponse; -// } - -// #[derive(Debug, Serialize, Deserialize)] -// pub struct SumResponse(pub i64); - -// #[derive(Debug, Serialize, Deserialize, From, TryInto)] -// pub enum Request { -// Add(AddRequest), -// Sum(SumRequest), -// SumUpdate(SumUpdate), -// } - -// #[derive(Debug, Serialize, Deserialize, From, TryInto)] -// pub enum Response { -// Add(AddResponse), -// Sum(SumResponse), -// } - -// #[derive(Copy, Clone, Debug)] -// pub struct CalcService; -// impl Service for CalcService { -// type Req = Request; -// type Res = Response; -// } - -// #[derive(Clone, Default)] -// pub struct Handler; - -// impl Handler { -// pub async fn handle_rpc_request( -// self, -// req: Request, -// chan: RpcChannel, -// ) -> Result<()> -// where -// S: Service, -// E: ServiceEndpoint, -// { -// match req { -// Request::Add(req) => chan.rpc(req, self, Self::on_add).await?, -// Request::Sum(req) => chan.client_streaming(req, self, Self::on_sum).await?, -// Request::SumUpdate(_) => bail!("Unexpected update message at start of request"), -// } -// Ok(()) -// } - -// pub async fn on_add(self, req: AddRequest) -> AddResponse { -// AddResponse(req.0 + req.1) -// } - -// pub async fn on_sum( -// self, -// _req: SumRequest, -// updates: impl Stream, -// ) -> SumResponse { -// let mut sum = 0i64; -// tokio::pin!(updates); -// while let Some(SumUpdate(n)) = updates.next().await { -// sum += n; -// } -// SumResponse(sum) -// } -// } - -// #[derive(Debug, Clone)] -// pub struct Client { -// client: RpcClient, -// } - -// impl Client -// where -// C: ServiceConnection, -// S: Service, -// { -// pub fn new(client: RpcClient) -> Self { -// Self { client } -// } -// pub async fn add(&self, a: i64, b: i64) -> anyhow::Result { -// let res = self.client.rpc(AddRequest(a, b)).await?; -// Ok(res.0) -// } -// } -// } - -// mod clock { -// //! This is a library providing a service, and a client. E.g. iroh-bytes or iroh-hypermerge. -// //! It does not use any `super` imports, it is completely decoupled. - -// use anyhow::Result; -// use derive_more::{From, TryInto}; -// use futures_lite::{stream::Boxed as BoxStream, Stream, StreamExt}; -// use futures_util::TryStreamExt; -// use quic_rpc::{ -// message::{Msg, ServerStreaming, ServerStreamingMsg}, -// server::RpcChannel, -// RpcClient, Service, ServiceConnection, ServiceEndpoint, -// }; -// use serde::{Deserialize, Serialize}; -// use std::{ -// fmt::Debug, -// sync::{Arc, RwLock}, -// time::Duration, -// }; -// use tokio::sync::Notify; - -// #[derive(Debug, Serialize, Deserialize)] -// pub struct TickRequest; - -// impl Msg for TickRequest { -// type Pattern = ServerStreaming; -// } - -// impl ServerStreamingMsg for TickRequest { -// type Response = TickResponse; -// } - -// #[derive(Debug, Serialize, Deserialize)] -// pub struct TickResponse { -// tick: usize, -// } - -// #[derive(Debug, Serialize, Deserialize, From, TryInto)] -// pub enum Request { -// Tick(TickRequest), -// } - -// #[derive(Debug, Serialize, Deserialize, From, TryInto)] -// pub enum Response { -// Tick(TickResponse), -// } - -// #[derive(Copy, Clone, Debug)] -// pub struct ClockService; -// impl Service for ClockService { -// type Req = Request; -// type Res = Response; -// } - -// #[derive(Clone)] -// pub struct Handler { -// tick: Arc>, -// ontick: Arc, -// } - -// impl Default for Handler { -// fn default() -> Self { -// Self::new(Duration::from_secs(1)) -// } -// } - -// impl Handler { -// pub fn new(tick_duration: Duration) -> Self { -// let h = Handler { -// tick: Default::default(), -// ontick: Default::default(), -// }; -// let h2 = h.clone(); -// tokio::task::spawn(async move { -// loop { -// tokio::time::sleep(tick_duration).await; -// *h2.tick.write().unwrap() += 1; -// h2.ontick.notify_waiters(); -// } -// }); -// h -// } - -// pub async fn handle_rpc_request( -// self, -// req: Request, -// chan: RpcChannel, -// ) -> Result<()> -// where -// S: Service, -// E: ServiceEndpoint, -// { -// match req { -// Request::Tick(req) => chan.server_streaming(req, self, Self::on_tick).await?, -// } -// Ok(()) -// } - -// pub fn on_tick( -// self, -// req: TickRequest, -// ) -> impl Stream + Send + 'static { -// let (tx, rx) = flume::bounded(2); -// tokio::task::spawn(async move { -// if let Err(err) = self.on_tick0(req, tx).await { -// tracing::warn!(?err, "on_tick RPC handler failed"); -// } -// }); -// rx.into_stream() -// } - -// pub async fn on_tick0( -// self, -// _req: TickRequest, -// tx: flume::Sender, -// ) -> Result<()> { -// loop { -// let tick = *self.tick.read().unwrap(); -// tx.send_async(TickResponse { tick }).await?; -// self.ontick.notified().await; -// } -// } -// } - -// #[derive(Debug, Clone)] -// pub struct Client { -// client: RpcClient, -// } - -// impl Client -// where -// C: ServiceConnection, -// S: Service, -// { -// pub fn new(client: RpcClient) -> Self { -// Self { client } -// } -// pub async fn tick(&self) -> Result>> { -// let res = self.client.server_streaming(TickRequest).await?; -// Ok(res.map_ok(|r| r.tick).map_err(anyhow::Error::from).boxed()) -// } -// } -// } -fn main() {} +//! This example shows how an RPC service can be modularized, even between different crates. +//! +//! * `app` module is the top level. it composes `iroh` plus one handler of the app itself +//! * `iroh` module composes two other services, `calc` and `clock` +//! +//! The [`calc`] and [`clock`] modules both expose a [`quic_rpc::Service`] in a regular fashion. +//! They do not `use` anything from `super` or `app` so they could live in their own crates +//! unchanged. + +use anyhow::Result; +use futures_lite::StreamExt; +use futures_util::SinkExt; +use quic_rpc::{ + client::BoxedServiceConnection, transport::flume, RpcClient, RpcServer, ServiceConnection, + ServiceEndpoint, +}; +use tracing::warn; + +use app::AppService; + +#[tokio::main] +async fn main() -> Result<()> { + // Spawn an inmemory connection. + // Could use quic equally (all code in this example is generic over the transport) + let (server_conn, client_conn) = flume::service_connection::(1); + + // spawn the server + let handler = app::Handler::default(); + tokio::task::spawn(run_server(server_conn, handler)); + + // run a client demo + client_demo(BoxedServiceConnection::::new(client_conn)).await?; + + Ok(()) +} + +async fn run_server>(server_conn: C, handler: app::Handler) { + let server = RpcServer::::new(server_conn); + loop { + let Ok(accepting) = server.accept().await else { + continue; + }; + match accepting.read_first().await { + Err(err) => warn!(?err, "server accept failed"), + Ok((req, chan)) => { + let handler = handler.clone(); + tokio::task::spawn(async move { + if let Err(err) = handler.handle_rpc_request(req, chan).await { + warn!(?err, "internal rpc error"); + } + }); + } + } + } +} +pub async fn client_demo(conn: BoxedServiceConnection) -> Result<()> { + let rpc_client = RpcClient::::new(conn); + let client = app::Client::new(rpc_client.clone()); + + // call a method from the top-level app client + let res = client.app_version().await?; + println!("app_version: {res:?}"); + + // call a method from the wrapped iroh.calc client + let res = client.iroh.calc.add(40, 2).await?; + println!("iroh.calc.add: {res:?}"); + + // can also do "raw" calls without using the wrapped clients + let res = rpc_client + .clone() + .map::() + .map::() + .rpc(calc::AddRequest(19, 4)) + .await?; + println!("iroh.calc.add (raw): {res:?}"); + + let (mut sink, res) = rpc_client + .map::() + .map::() + .client_streaming(calc::SumRequest) + .await?; + sink.send(calc::SumUpdate(4)).await.unwrap(); + sink.send(calc::SumUpdate(8)).await.unwrap(); + sink.send(calc::SumUpdate(30)).await.unwrap(); + drop(sink); + let res = res.await?; + println!("iroh.calc.sum (raw): {res:?}"); + + // call a server-streaming method from the wrapped iroh.clock client + let mut stream = client.iroh.clock.tick().await?; + while let Some(tick) = stream.try_next().await? { + println!("iroh.clock.tick: {tick}"); + } + Ok(()) +} + +mod app { + //! This is the app-specific code. + //! + //! It composes all of `iroh` (which internally composes two other modules) and adds an + //! application specific RPC. + //! + //! It could also easily compose services from other crates or internal modules. + + use anyhow::Result; + use derive_more::{From, TryInto}; + use quic_rpc::{ + message::RpcMsg, server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint, + }; + use serde::{Deserialize, Serialize}; + + use crate::iroh::IrohService; + + use super::iroh; + + #[derive(Debug, Serialize, Deserialize, From, TryInto)] + pub enum Request { + Iroh(iroh::Request), + AppVersion(AppVersionRequest), + } + + #[derive(Debug, Serialize, Deserialize, From, TryInto)] + pub enum Response { + Iroh(iroh::Response), + AppVersion(AppVersionResponse), + } + + #[derive(Debug, Serialize, Deserialize)] + pub struct AppVersionRequest; + + impl RpcMsg for AppVersionRequest { + type Response = AppVersionResponse; + } + + #[derive(Debug, Serialize, Deserialize)] + pub struct AppVersionResponse(pub String); + + #[derive(Copy, Clone, Debug)] + pub struct AppService; + impl Service for AppService { + type Req = Request; + type Res = Response; + } + + #[derive(Clone)] + pub struct Handler { + iroh: iroh::Handler, + app_version: String, + } + + impl Default for Handler { + fn default() -> Self { + Self { + iroh: iroh::Handler::default(), + app_version: "v0.1-alpha".to_string(), + } + } + } + + impl Handler { + pub async fn handle_rpc_request>( + self, + req: Request, + chan: RpcChannel, + ) -> Result<()> { + match req { + Request::Iroh(req) => { + self.iroh + .handle_rpc_request(req, chan.map::().boxed()) + .await? + } + Request::AppVersion(req) => chan.rpc(req, self, Self::on_version).await?, + }; + Ok(()) + } + + pub async fn on_version(self, _req: AppVersionRequest) -> AppVersionResponse { + AppVersionResponse(self.app_version.clone()) + } + } + + #[derive(Debug, Clone)] + pub struct Client { + pub iroh: iroh::Client, + client: RpcClient, + } + + impl Client { + pub fn new(client: RpcClient) -> Self { + Self { + iroh: iroh::Client::new(client.clone().map::().boxed()), + client, + } + } + + pub async fn app_version(&self) -> Result { + let res = self.client.rpc(AppVersionRequest).await?; + Ok(res.0) + } + } +} + +mod iroh { + //! This module composes two sub-services. Think `iroh` crate which exposes services and + //! clients for iroh-bytes and iroh-gossip or so. + //! It uses only the `calc` and `clock` modules and nothing else. + + use anyhow::Result; + use derive_more::{From, TryInto}; + use quic_rpc::{server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint}; + use serde::{Deserialize, Serialize}; + + use super::{calc, clock}; + + #[derive(Debug, Serialize, Deserialize, From, TryInto)] + pub enum Request { + Calc(calc::Request), + Clock(clock::Request), + } + + #[derive(Debug, Serialize, Deserialize, From, TryInto)] + pub enum Response { + Calc(calc::Response), + Clock(clock::Response), + } + + #[derive(Copy, Clone, Debug)] + pub struct IrohService; + impl Service for IrohService { + type Req = Request; + type Res = Response; + } + + #[derive(Clone, Default)] + pub struct Handler { + calc: calc::Handler, + clock: clock::Handler, + } + + impl Handler { + pub async fn handle_rpc_request( + self, + req: Request, + chan: RpcChannel, + ) -> Result<()> { + match req { + Request::Calc(req) => { + self.calc + .handle_rpc_request(req, chan.map().boxed()) + .await? + } + Request::Clock(req) => { + self.clock + .handle_rpc_request(req, chan.map().boxed()) + .await? + } + } + Ok(()) + } + } + + #[derive(Debug, Clone)] + pub struct Client { + pub calc: calc::Client, + pub clock: clock::Client, + } + + impl Client { + pub fn new(client: RpcClient) -> Self { + Self { + calc: calc::Client::new(client.clone().map().boxed()), + clock: clock::Client::new(client.clone().map().boxed()), + } + } + } +} + +mod calc { + //! This is a library providing a service, and a client. E.g. iroh-bytes or iroh-hypermerge. + //! It does not use any `super` imports, it is completely decoupled. + + use anyhow::{bail, Result}; + use derive_more::{From, TryInto}; + use futures_lite::{Stream, StreamExt}; + use quic_rpc::{ + message::{ClientStreaming, ClientStreamingMsg, Msg, RpcMsg}, + server::RpcChannel, + RpcClient, Service, ServiceConnection, ServiceEndpoint, + }; + use serde::{Deserialize, Serialize}; + use std::fmt::Debug; + + #[derive(Debug, Serialize, Deserialize)] + pub struct AddRequest(pub i64, pub i64); + + impl RpcMsg for AddRequest { + type Response = AddResponse; + } + + #[derive(Debug, Serialize, Deserialize)] + pub struct AddResponse(pub i64); + + #[derive(Debug, Serialize, Deserialize)] + pub struct SumRequest; + + #[derive(Debug, Serialize, Deserialize)] + pub struct SumUpdate(pub i64); + + impl Msg for SumRequest { + type Pattern = ClientStreaming; + } + + impl ClientStreamingMsg for SumRequest { + type Update = SumUpdate; + type Response = SumResponse; + } + + #[derive(Debug, Serialize, Deserialize)] + pub struct SumResponse(pub i64); + + #[derive(Debug, Serialize, Deserialize, From, TryInto)] + pub enum Request { + Add(AddRequest), + Sum(SumRequest), + SumUpdate(SumUpdate), + } + + #[derive(Debug, Serialize, Deserialize, From, TryInto)] + pub enum Response { + Add(AddResponse), + Sum(SumResponse), + } + + #[derive(Copy, Clone, Debug)] + pub struct CalcService; + impl Service for CalcService { + type Req = Request; + type Res = Response; + } + + #[derive(Clone, Default)] + pub struct Handler; + + impl Handler { + pub async fn handle_rpc_request( + self, + req: Request, + chan: RpcChannel, + ) -> Result<()> { + match req { + Request::Add(req) => chan.rpc(req, self, Self::on_add).await?, + Request::Sum(req) => chan.client_streaming(req, self, Self::on_sum).await?, + Request::SumUpdate(_) => bail!("Unexpected update message at start of request"), + } + Ok(()) + } + + pub async fn on_add(self, req: AddRequest) -> AddResponse { + AddResponse(req.0 + req.1) + } + + pub async fn on_sum( + self, + _req: SumRequest, + updates: impl Stream, + ) -> SumResponse { + let mut sum = 0i64; + tokio::pin!(updates); + while let Some(SumUpdate(n)) = updates.next().await { + sum += n; + } + SumResponse(sum) + } + } + + #[derive(Debug, Clone)] + pub struct Client { + client: RpcClient, + } + + impl Client { + pub fn new(client: RpcClient) -> Self { + Self { client } + } + pub async fn add(&self, a: i64, b: i64) -> anyhow::Result { + let res = self.client.rpc(AddRequest(a, b)).await?; + Ok(res.0) + } + } +} + +mod clock { + //! This is a library providing a service, and a client. E.g. iroh-bytes or iroh-hypermerge. + //! It does not use any `super` imports, it is completely decoupled. + + use anyhow::Result; + use derive_more::{From, TryInto}; + use futures_lite::{stream::Boxed as BoxStream, Stream, StreamExt}; + use futures_util::TryStreamExt; + use quic_rpc::{ + message::{Msg, ServerStreaming, ServerStreamingMsg}, + server::RpcChannel, + RpcClient, Service, ServiceConnection, ServiceEndpoint, + }; + use serde::{Deserialize, Serialize}; + use std::{ + fmt::Debug, + sync::{Arc, RwLock}, + time::Duration, + }; + use tokio::sync::Notify; + + #[derive(Debug, Serialize, Deserialize)] + pub struct TickRequest; + + impl Msg for TickRequest { + type Pattern = ServerStreaming; + } + + impl ServerStreamingMsg for TickRequest { + type Response = TickResponse; + } + + #[derive(Debug, Serialize, Deserialize)] + pub struct TickResponse { + tick: usize, + } + + #[derive(Debug, Serialize, Deserialize, From, TryInto)] + pub enum Request { + Tick(TickRequest), + } + + #[derive(Debug, Serialize, Deserialize, From, TryInto)] + pub enum Response { + Tick(TickResponse), + } + + #[derive(Copy, Clone, Debug)] + pub struct ClockService; + impl Service for ClockService { + type Req = Request; + type Res = Response; + } + + #[derive(Clone)] + pub struct Handler { + tick: Arc>, + ontick: Arc, + } + + impl Default for Handler { + fn default() -> Self { + Self::new(Duration::from_secs(1)) + } + } + + impl Handler { + pub fn new(tick_duration: Duration) -> Self { + let h = Handler { + tick: Default::default(), + ontick: Default::default(), + }; + let h2 = h.clone(); + tokio::task::spawn(async move { + loop { + tokio::time::sleep(tick_duration).await; + *h2.tick.write().unwrap() += 1; + h2.ontick.notify_waiters(); + } + }); + h + } + + pub async fn handle_rpc_request( + self, + req: Request, + chan: RpcChannel, + ) -> Result<()> { + match req { + Request::Tick(req) => chan.server_streaming(req, self, Self::on_tick).await?, + } + Ok(()) + } + + pub fn on_tick( + self, + req: TickRequest, + ) -> impl Stream + Send + 'static { + let (tx, rx) = flume::bounded(2); + tokio::task::spawn(async move { + if let Err(err) = self.on_tick0(req, tx).await { + tracing::warn!(?err, "on_tick RPC handler failed"); + } + }); + rx.into_stream() + } + + pub async fn on_tick0( + self, + _req: TickRequest, + tx: flume::Sender, + ) -> Result<()> { + loop { + let tick = *self.tick.read().unwrap(); + tx.send_async(TickResponse { tick }).await?; + self.ontick.notified().await; + } + } + } + + #[derive(Debug, Clone)] + pub struct Client { + client: RpcClient, + } + + impl Client { + pub fn new(client: RpcClient) -> Self { + Self { client } + } + pub async fn tick(&self) -> Result>> { + let res = self.client.server_streaming(TickRequest).await?; + Ok(res.map_ok(|r| r.tick).map_err(anyhow::Error::from).boxed()) + } + } +} diff --git a/src/client.rs b/src/client.rs index 5f47f05..a139fda 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,10 +2,7 @@ //! //! The main entry point is [RpcClient]. use crate::{ - transport::{ - mapped::MappedConnection, - ConnectionCommon, - }, + transport::{boxed::BoxableConnection, mapped::MappedConnection, ConnectionCommon}, Service, ServiceConnection, }; use futures_lite::Stream; @@ -135,6 +132,17 @@ where p: PhantomData, } } + + /// box + pub fn boxed(self) -> RpcClient> + where + C: BoxableConnection, + { + RpcClient { + source: BoxedServiceConnection::::new(self.source), + p: PhantomData, + } + } } impl AsRef for RpcClient diff --git a/src/lib.rs b/src/lib.rs index c786cb3..7afdf63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,9 +126,10 @@ impl RpcMessage for T where /// /// We don't require them to implement [std::error::Error] so we can use /// anyhow::Error as an error type. -pub trait RpcError: Debug + Display + Send + Sync + Unpin + 'static {} +pub trait RpcError: Debug + Display + Into + Send + Sync + Unpin + 'static {} -impl RpcError for T where T: Debug + Display + Send + Sync + Unpin + 'static {} +impl RpcError for T where T: Debug + Display + Into + Send + Sync + Unpin + 'static +{} /// A service /// diff --git a/src/server.rs b/src/server.rs index 32d078e..dfb7139 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,17 +2,20 @@ //! //! The main entry point is [RpcServer] use crate::{ + client::BoxedServiceConnection, transport::{ + self, mapped::{MappedConnectionTypes, MappedRecvStream, MappedSendSink}, ConnectionCommon, ConnectionErrors, }, Service, ServiceEndpoint, }; use futures_lite::{Future, Stream, StreamExt}; +use futures_util::{SinkExt, TryStreamExt}; use pin_project::pin_project; use std::{ error, - fmt::{self, Debug}, + fmt::{self, Debug, Display}, marker::PhantomData, pin::Pin, result, @@ -20,6 +23,10 @@ use std::{ }; use tokio::sync::oneshot; +/// Type alias for a boxed connection to a specific service +pub type BoxedServiceChannel = + crate::transport::boxed::Connection<::Req, ::Res>; + /// Type alias for a service endpoint pub type BoxedServiceEndpoint = crate::transport::boxed::ServerEndpoint<::Req, ::Res>; @@ -75,12 +82,11 @@ impl> RpcServer { /// Type parameters: /// /// `S` is the service type. -/// `SC` is the service type that is compatible with the connection. /// `C` is the service endpoint from which the channel was created. #[derive(Debug)] pub struct RpcChannel< S: Service, - C: ConnectionCommon = BoxedServiceEndpoint, + C: ConnectionCommon = BoxedServiceChannel, > { /// Sink to send responses to the client. pub send: C::SendSink, @@ -103,13 +109,23 @@ where p: PhantomData, } } -} -impl RpcChannel -where - S: Service, - C: ConnectionCommon, -{ + /// Convert this channel into a boxed channel. + pub fn boxed(self) -> RpcChannel> + where + C::SendError: Into + Send + Sync + 'static, + C::RecvError: Into + Send + Sync + 'static, + { + let send = + transport::boxed::SendSink::boxed(Box::new(self.send.sink_map_err(|e| e.into()))); + let recv = transport::boxed::RecvStream::boxed(Box::new(self.recv.map_err(|e| e.into()))); + RpcChannel { + send, + recv, + p: PhantomData, + } + } + /// Map this channel's service into an inner service. /// /// This method is available if the required bounds are upheld: diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index 17cea21..e27cad7 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -1,6 +1,7 @@ //! Boxed transport with concrete types use std::{ + any, fmt::Debug, pin::Pin, task::{Context, Poll}, @@ -144,7 +145,7 @@ impl<'a, In: RpcMessage, Out: RpcMessage> OpenFuture<'a, In, Out> { /// Create a new boxed future pub fn boxed( - f: impl Future, RecvStream)>> + Send + Sync + 'a, + f: impl Future, RecvStream)>> + Send + 'a, ) -> Self { Self(OpenFutureInner::Boxed(Box::pin(f))) } @@ -380,6 +381,34 @@ impl BoxableServerEndpoint } } +impl BoxableConnection for super::mapped::MappedConnection +where + In: RpcMessage, + Out: RpcMessage, + C: super::Connection, + C::Out: From, + In: TryFrom, + C::SendError: Into, + C::RecvError: Into, + C::OpenError: Into, +{ + fn clone_box(&self) -> Box> { + Box::new(self.clone()) + } + + fn open_boxed(&self) -> OpenFuture { + let f = Box::pin(async move { + let (send, recv) = super::Connection::open(self).await.map_err(|e| e.into())?; + // map the error types to anyhow + let send = send.sink_map_err(|e| e.into()); + let recv = recv.map_err(|e| e.into()); + // return the boxed streams + anyhow::Ok((SendSink::boxed(send), RecvStream::boxed(recv))) + }); + OpenFuture::boxed(f) + } +} + #[cfg(test)] mod tests { use crate::Service; diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index 0a3ec9f..63d4a74 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -15,8 +15,8 @@ use super::{Connection, ConnectionCommon, ConnectionErrors}; /// A connection that maps input and output types #[derive(Debug)] -pub struct MappedConnection { - inner: T, +pub struct MappedConnection { + inner: C, _phantom: std::marker::PhantomData<(In, Out)>, } @@ -118,6 +118,8 @@ pub enum ErrorOrMapError { Conversion, } +impl std::error::Error for ErrorOrMapError {} + impl Display for ErrorOrMapError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -291,8 +293,9 @@ where mod tests { use crate::{ - server::RpcChannel, - transport::{flume::FlumeConnection, ServerEndpoint}, + client::BoxedServiceConnection, + server::{BoxedServiceChannel, RpcChannel}, + transport::{boxed::BoxableConnection, flume::FlumeConnection, ServerEndpoint}, RpcClient, RpcServer, ServiceConnection, ServiceEndpoint, }; use serde::{Deserialize, Serialize}; @@ -332,13 +335,14 @@ mod tests { async fn smoke() -> TestResult<()> { async fn handle_sub_request( req: String, - chan: RpcChannel>, + chan: RpcChannel>, ) -> anyhow::Result<()> { Ok(()) } let (s, c): (_, FlumeConnection) = crate::transport::flume::connection::(32); let _x = c.clone().map::(); + let _y = c.clone().map_to_service::(); let s = RpcServer::::new(s); return Ok(()); @@ -346,7 +350,7 @@ mod tests { let (msg, chan) = accepting.read_first().await?; match msg { Request::A(x) => todo!(), - Request::B(x) => todo!(), // handle_sub_request(x, chan).await?, + Request::B(x) => handle_sub_request(x, chan.map::().boxed()).await?, } } Ok(()) diff --git a/src/transport/misc/mod.rs b/src/transport/misc/mod.rs index dec902d..c111119 100644 --- a/src/transport/misc/mod.rs +++ b/src/transport/misc/mod.rs @@ -1,42 +1,51 @@ //! Miscellaneous transport utilities - -// use futures_lite::stream; -// use futures_sink::Sink; - -// use crate::{ -// transport::{ConnectionErrors, ServerEndpoint}, -// RpcMessage, -// }; -// use std::convert::Infallible; - -// use super::ConnectionCommon; - -// /// A dummy server endpoint that does nothing -// /// -// /// This can be useful as a default if you want to configure -// /// an optional server endpoint. -// #[derive(Debug, Clone, Default)] -// pub struct DummyServerEndpoint; - -// impl ConnectionErrors for DummyServerEndpoint { -// type OpenError = Infallible; -// type RecvError = Infallible; -// type SendError = Infallible; -// } - -// impl ConnectionCommon for DummyServerEndpoint { -// type In = In; -// type Out = Out; -// type RecvStream = stream::Pending>; -// type SendSink = Box + Unpin + Send + Sync>; -// } - -// impl ServerEndpoint for DummyServerEndpoint { -// async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { -// futures_lite::future::pending().await -// } - -// fn local_addr(&self) -> &[super::LocalAddr] { -// &[] -// } -// } +use futures_lite::stream; +use futures_sink::Sink; + +use crate::{ + transport::{ConnectionErrors, ServerEndpoint}, + RpcMessage, +}; +use std::convert::Infallible; + +use super::ConnectionCommon; + +/// A dummy server endpoint that does nothing +/// +/// This can be useful as a default if you want to configure +/// an optional server endpoint. +#[derive(Debug, Default)] +pub struct DummyServerEndpoint { + _phantom: std::marker::PhantomData<(In, Out)>, +} + +impl Clone for DummyServerEndpoint { + fn clone(&self) -> Self { + Self { + _phantom: std::marker::PhantomData, + } + } +} + +impl ConnectionErrors for DummyServerEndpoint { + type OpenError = Infallible; + type RecvError = Infallible; + type SendError = Infallible; +} + +impl ConnectionCommon for DummyServerEndpoint { + type In = In; + type Out = Out; + type RecvStream = stream::Pending>; + type SendSink = Box + Unpin + Send + Sync>; +} + +impl ServerEndpoint for DummyServerEndpoint { + async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { + futures_lite::future::pending().await + } + + fn local_addr(&self) -> &[super::LocalAddr] { + &[] + } +} From 791ebb467b888338c1d9a3f5028d9f6a044ed02c Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Sat, 2 Nov 2024 15:00:59 +0200 Subject: [PATCH 08/32] Remove explicit debug impl where possible --- examples/modularize.rs | 12 ++++++------ src/transport/boxed.rs | 11 +++++++++++ src/transport/combined.rs | 38 ++------------------------------------ 3 files changed, 19 insertions(+), 42 deletions(-) diff --git a/examples/modularize.rs b/examples/modularize.rs index ceb9e9b..3efc0b1 100644 --- a/examples/modularize.rs +++ b/examples/modularize.rs @@ -22,7 +22,7 @@ use app::AppService; async fn main() -> Result<()> { // Spawn an inmemory connection. // Could use quic equally (all code in this example is generic over the transport) - let (server_conn, client_conn) = flume::service_connection::(1); + let (server_conn, client_conn) = flume::connection(1); // spawn the server let handler = app::Handler::default(); @@ -166,7 +166,7 @@ mod app { match req { Request::Iroh(req) => { self.iroh - .handle_rpc_request(req, chan.map::().boxed()) + .handle_rpc_request(req, chan.map().boxed()) .await? } Request::AppVersion(req) => chan.rpc(req, self, Self::on_version).await?, @@ -188,8 +188,8 @@ mod app { impl Client { pub fn new(client: RpcClient) -> Self { Self { - iroh: iroh::Client::new(client.clone().map::().boxed()), - client, + client: client.clone(), + iroh: iroh::Client::new(client.map().boxed()), } } @@ -285,7 +285,7 @@ mod calc { use quic_rpc::{ message::{ClientStreaming, ClientStreamingMsg, Msg, RpcMsg}, server::RpcChannel, - RpcClient, Service, ServiceConnection, ServiceEndpoint, + RpcClient, Service, }; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -400,7 +400,7 @@ mod clock { use quic_rpc::{ message::{Msg, ServerStreaming, ServerStreamingMsg}, server::RpcChannel, - RpcClient, Service, ServiceConnection, ServiceEndpoint, + RpcClient, Service, }; use serde::{Deserialize, Serialize}; use std::{ diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index e27cad7..a4cecf5 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -306,6 +306,17 @@ impl super::ServerEndpoint for ServerEndpoint BoxableConnection + for Connection +{ + fn clone_box(&self) -> Box> { + Box::new(self.clone()) + } + + fn open_boxed(&self) -> OpenFuture { + OpenFuture::boxed(crate::transport::Connection::open(self)) + } +} #[cfg(feature = "quinn-transport")] impl BoxableConnection diff --git a/src/transport/combined.rs b/src/transport/combined.rs index 366c07e..d8e83de 100644 --- a/src/transport/combined.rs +++ b/src/transport/combined.rs @@ -11,6 +11,7 @@ use std::{ }; /// A connection that combines two other connections +#[derive(Debug, Clone)] pub struct CombinedConnection { /// First connection pub a: Option, @@ -26,25 +27,9 @@ impl> CombinedConnection< Self { a, b } } } -impl Clone for CombinedConnection { - fn clone(&self) -> Self { - Self { - a: self.a.clone(), - b: self.b.clone(), - } - } -} - -impl Debug for CombinedConnection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CombinedConnection") - .field("a", &self.a) - .field("b", &self.b) - .finish() - } -} /// An endpoint that combines two other endpoints +#[derive(Debug, Clone)] pub struct CombinedServerEndpoint { /// First endpoint pub a: Option, @@ -78,25 +63,6 @@ impl> CombinedSer } } -impl Clone for CombinedServerEndpoint { - fn clone(&self) -> Self { - Self { - a: self.a.clone(), - b: self.b.clone(), - local_addr: self.local_addr.clone(), - } - } -} - -impl Debug for CombinedServerEndpoint { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CombinedServerEndpoint") - .field("a", &self.a) - .field("b", &self.b) - .finish() - } -} - /// Send sink for combined channels #[pin_project(project = SendSinkProj)] pub enum SendSink { From 4994efc71276d3e14112785b0e351d85d81a3f93 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Sun, 3 Nov 2024 08:59:40 +0200 Subject: [PATCH 09/32] Separate AcceptError type in ConnectionErrors --- examples/modularize.rs | 9 +++------ src/pattern/bidi_streaming.rs | 14 +++++++------- src/pattern/client_streaming.rs | 6 +++--- src/pattern/rpc.rs | 6 +++--- src/pattern/server_streaming.rs | 6 +++--- src/pattern/try_server_streaming.rs | 8 ++++---- src/server.rs | 5 ++--- src/transport/boxed.rs | 13 ++++++------- src/transport/combined.rs | 10 ++++++---- src/transport/flume.rs | 8 +++----- src/transport/hyper.rs | 5 +++-- src/transport/mapped.rs | 6 ++++-- src/transport/misc/mod.rs | 5 +++-- src/transport/mod.rs | 8 +++++--- src/transport/quinn.rs | 6 ++---- 15 files changed, 57 insertions(+), 58 deletions(-) diff --git a/examples/modularize.rs b/examples/modularize.rs index 3efc0b1..a67b7f5 100644 --- a/examples/modularize.rs +++ b/examples/modularize.rs @@ -11,8 +11,7 @@ use anyhow::Result; use futures_lite::StreamExt; use futures_util::SinkExt; use quic_rpc::{ - client::BoxedServiceConnection, transport::flume, RpcClient, RpcServer, ServiceConnection, - ServiceEndpoint, + client::BoxedServiceConnection, transport::flume, RpcClient, RpcServer, ServiceEndpoint, }; use tracing::warn; @@ -104,9 +103,7 @@ mod app { use anyhow::Result; use derive_more::{From, TryInto}; - use quic_rpc::{ - message::RpcMsg, server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint, - }; + use quic_rpc::{message::RpcMsg, server::RpcChannel, RpcClient, Service, ServiceEndpoint}; use serde::{Deserialize, Serialize}; use crate::iroh::IrohService; @@ -207,7 +204,7 @@ mod iroh { use anyhow::Result; use derive_more::{From, TryInto}; - use quic_rpc::{server::RpcChannel, RpcClient, Service, ServiceConnection, ServiceEndpoint}; + use quic_rpc::{server::RpcChannel, RpcClient, Service}; use serde::{Deserialize, Serialize}; use super::{calc, clock}; diff --git a/src/pattern/bidi_streaming.rs b/src/pattern/bidi_streaming.rs index c413faf..4b0fb2e 100644 --- a/src/pattern/bidi_streaming.rs +++ b/src/pattern/bidi_streaming.rs @@ -7,8 +7,8 @@ use crate::{ client::{BoxStreamSync, UpdateSink}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, - transport::{ConnectionCommon, ConnectionErrors}, - RpcClient, Service, ServiceConnection, + transport::{Connection, ConnectionCommon, ConnectionErrors}, + RpcClient, Service, }; use std::{ @@ -49,13 +49,13 @@ pub enum Error { Send(C::SendError), } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} /// Server error when receiving an item for a bidi request #[derive(Debug)] @@ -66,18 +66,18 @@ pub enum ItemError { DowncastError, } -impl fmt::Display for ItemError { +impl fmt::Display for ItemError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for ItemError {} +impl error::Error for ItemError {} impl RpcClient where - C: ServiceConnection, S: Service, + C: Connection, { /// Bidi call to the server, request opens a stream, response is a stream pub async fn bidi( diff --git a/src/pattern/client_streaming.rs b/src/pattern/client_streaming.rs index 5262908..8d489e1 100644 --- a/src/pattern/client_streaming.rs +++ b/src/pattern/client_streaming.rs @@ -7,7 +7,7 @@ use crate::{ client::UpdateSink, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, - transport::{ConnectionCommon, ConnectionErrors}, + transport::{Connection, ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, }; @@ -49,13 +49,13 @@ pub enum Error { Send(C::SendError), } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} /// Server error when receiving an item for a client streaming request #[derive(Debug)] diff --git a/src/pattern/rpc.rs b/src/pattern/rpc.rs index ed2e708..5a10228 100644 --- a/src/pattern/rpc.rs +++ b/src/pattern/rpc.rs @@ -6,7 +6,7 @@ use futures_util::{FutureExt, SinkExt}; use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::{ConnectionCommon, ConnectionErrors}, + transport::{Connection, ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, }; @@ -54,13 +54,13 @@ pub enum Error { DowncastError, } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} impl RpcClient where diff --git a/src/pattern/server_streaming.rs b/src/pattern/server_streaming.rs index 4ca56c5..e288101 100644 --- a/src/pattern/server_streaming.rs +++ b/src/pattern/server_streaming.rs @@ -7,7 +7,7 @@ use crate::{ client::{BoxStreamSync, DeferDrop}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::{ConnectionCommon, ConnectionErrors}, + transport::{Connection, ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, }; @@ -41,13 +41,13 @@ pub enum Error { Send(C::SendError), } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} /// Client error when handling responses from a server streaming request #[derive(Debug)] diff --git a/src/pattern/try_server_streaming.rs b/src/pattern/try_server_streaming.rs index 5633972..e57c85c 100644 --- a/src/pattern/try_server_streaming.rs +++ b/src/pattern/try_server_streaming.rs @@ -8,7 +8,7 @@ use crate::{ client::{BoxStreamSync, DeferDrop}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::{ConnectionCommon, ConnectionErrors}, + transport::{Connection, ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, }; @@ -53,7 +53,7 @@ where /// care about the exact nature of the error, but if you want to handle /// application errors differently, you can match on this enum. #[derive(Debug)] -pub enum Error { +pub enum Error { /// Unable to open a substream at all Open(C::OpenError), /// Unable to send the request to the server @@ -68,13 +68,13 @@ pub enum Error { Application(E), } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} /// Client error when handling responses from a server streaming request. /// diff --git a/src/server.rs b/src/server.rs index dfb7139..5e4172d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,7 +2,6 @@ //! //! The main entry point is [RpcServer] use crate::{ - client::BoxedServiceConnection, transport::{ self, mapped::{MappedConnectionTypes, MappedRecvStream, MappedSendSink}, @@ -15,7 +14,7 @@ use futures_util::{SinkExt, TryStreamExt}; use pin_project::pin_project; use std::{ error, - fmt::{self, Debug, Display}, + fmt::{self, Debug}, marker::PhantomData, pin::Pin, result, @@ -271,7 +270,7 @@ where /// Server error. All server DSL methods return a `Result` with this error type. pub enum RpcServerError { /// Unable to open a new channel - Accept(C::OpenError), + Accept(C::AcceptError), /// Recv side for a channel was closed before getting the first message EarlyClose, /// Got an unexpected first message, e.g. an update message diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index a4cecf5..e932a45 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -1,7 +1,6 @@ //! Boxed transport with concrete types use std::{ - any, fmt::Debug, pin::Pin, task::{Context, Poll}, @@ -239,9 +238,10 @@ impl ConnectionCommon for Connection { } impl ConnectionErrors for Connection { - type OpenError = anyhow::Error; type SendError = anyhow::Error; type RecvError = anyhow::Error; + type OpenError = anyhow::Error; + type AcceptError = anyhow::Error; } impl super::Connection for Connection { @@ -289,15 +289,16 @@ impl ConnectionCommon for ServerEndpoint ConnectionErrors for ServerEndpoint { - type OpenError = anyhow::Error; type SendError = anyhow::Error; type RecvError = anyhow::Error; + type OpenError = anyhow::Error; + type AcceptError = anyhow::Error; } impl super::ServerEndpoint for ServerEndpoint { fn accept( &self, - ) -> impl Future> + Send + ) -> impl Future> + Send { self.0.accept_bi_boxed() } @@ -306,9 +307,7 @@ impl super::ServerEndpoint for ServerEndpoint BoxableConnection - for Connection -{ +impl BoxableConnection for Connection { fn clone_box(&self) -> Box> { Box::new(self.clone()) } diff --git a/src/transport/combined.rs b/src/transport/combined.rs index d8e83de..bf1cb06 100644 --- a/src/transport/combined.rs +++ b/src/transport/combined.rs @@ -185,9 +185,9 @@ impl error::Error for OpenBiError { /// A variant - A(A::OpenError), + A(A::AcceptError), /// B variant - B(B::OpenError), + B(B::AcceptError), } impl fmt::Display for AcceptBiError { @@ -202,6 +202,7 @@ impl ConnectionErrors for CombinedConn type SendError = self::SendError; type RecvError = self::RecvError; type OpenError = self::OpenBiError; + type AcceptError = self::AcceptBiError; } impl> ConnectionCommon @@ -234,7 +235,8 @@ impl> Connection impl ConnectionErrors for CombinedServerEndpoint { type SendError = self::SendError; type RecvError = self::RecvError; - type OpenError = self::AcceptBiError; + type OpenError = self::OpenBiError; + type AcceptError = self::AcceptBiError; } impl> ConnectionCommon @@ -249,7 +251,7 @@ impl> ConnectionC impl> ServerEndpoint for CombinedServerEndpoint { - async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { + async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::AcceptError> { let a_fut = async { if let Some(a) = &self.a { let (send, recv) = a.accept().await.map_err(AcceptBiError::A)?; diff --git a/src/transport/flume.rs b/src/transport/flume.rs index 78b0dff..4c9ec1d 100644 --- a/src/transport/flume.rs +++ b/src/transport/flume.rs @@ -123,10 +123,9 @@ impl fmt::Debug for FlumeServerEndpoint ConnectionErrors for FlumeServerEndpoint { type SendError = self::SendError; - type RecvError = self::RecvError; - - type OpenError = self::AcceptBiError; + type OpenError = self::OpenBiError; + type AcceptError = self::AcceptBiError; } type Socket = (self::SendSink, self::RecvStream); @@ -218,10 +217,9 @@ impl ServerEndpoint for FlumeServerEndpoint ConnectionErrors for FlumeConnection { type SendError = self::SendError; - type RecvError = self::RecvError; - type OpenError = self::OpenBiError; + type AcceptError = self::AcceptBiError; } impl ConnectionCommon for FlumeConnection { diff --git a/src/transport/hyper.rs b/src/transport/hyper.rs index ee21f6c..c8ac35c 100644 --- a/src/transport/hyper.rs +++ b/src/transport/hyper.rs @@ -580,6 +580,8 @@ impl ConnectionErrors for HyperConnection ConnectionCommon for HyperConnection { @@ -612,10 +614,9 @@ impl Connection for HyperConnection { impl ConnectionErrors for HyperServerEndpoint { type SendError = self::SendError; - type RecvError = self::RecvError; - type OpenError = AcceptBiError; + type AcceptError = AcceptBiError; } impl ConnectionCommon for HyperServerEndpoint { diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index 63d4a74..5b3c0ec 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -53,9 +53,10 @@ where Out: RpcMessage, C: ConnectionErrors, { - type OpenError = C::OpenError; type RecvError = ErrorOrMapError; type SendError = C::SendError; + type OpenError = C::OpenError; + type AcceptError = C::AcceptError; } impl ConnectionCommon for MappedConnection @@ -247,9 +248,10 @@ where Out: RpcMessage, C: ConnectionErrors, { - type OpenError = C::OpenError; type RecvError = ErrorOrMapError; type SendError = C::SendError; + type OpenError = C::OpenError; + type AcceptError = C::AcceptError; } impl ConnectionCommon for MappedConnectionTypes diff --git a/src/transport/misc/mod.rs b/src/transport/misc/mod.rs index c111119..b998111 100644 --- a/src/transport/misc/mod.rs +++ b/src/transport/misc/mod.rs @@ -28,9 +28,10 @@ impl Clone for DummyServerEndpoint { } impl ConnectionErrors for DummyServerEndpoint { - type OpenError = Infallible; type RecvError = Infallible; type SendError = Infallible; + type OpenError = Infallible; + type AcceptError = Infallible; } impl ConnectionCommon for DummyServerEndpoint { @@ -41,7 +42,7 @@ impl ConnectionCommon for DummyServerEndpoint ServerEndpoint for DummyServerEndpoint { - async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { + async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::AcceptError> { futures_lite::future::pending().await } diff --git a/src/transport/mod.rs b/src/transport/mod.rs index e30a337..70de1b9 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -45,12 +45,14 @@ pub mod mapped; /// Errors that can happen when creating and using a [`Connection`] or [`ServerEndpoint`]. pub trait ConnectionErrors: Debug + Clone + Send + Sync + 'static { - /// Error when opening or accepting a channel - type OpenError: RpcError; /// Error when sending a message via a channel type SendError: RpcError; /// Error when receiving a message via a channel type RecvError: RpcError; + /// Error when opening a channel + type OpenError: RpcError; + /// Error when accepting a channel + type AcceptError: RpcError; } /// Types that are common to both [`Connection`] and [`ServerEndpoint`]. @@ -90,7 +92,7 @@ pub trait ServerEndpoint: ConnectionCommon { /// have currently opened. fn accept( &self, - ) -> impl Future> + Send; + ) -> impl Future> + Send; /// The local addresses this endpoint is bound to. fn local_addr(&self) -> &[LocalAddr]; diff --git a/src/transport/quinn.rs b/src/transport/quinn.rs index 9e7fdf9..dcbb891 100644 --- a/src/transport/quinn.rs +++ b/src/transport/quinn.rs @@ -189,10 +189,9 @@ impl Clone for QuinnServerEndpoint { impl ConnectionErrors for QuinnServerEndpoint { type SendError = io::Error; - type RecvError = io::Error; - type OpenError = quinn::ConnectionError; + type AcceptError = quinn::ConnectionError; } impl ConnectionCommon for QuinnServerEndpoint { @@ -622,10 +621,9 @@ impl Clone for QuinnConnection { impl ConnectionErrors for QuinnConnection { type SendError = io::Error; - type RecvError = io::Error; - type OpenError = quinn::ConnectionError; + type AcceptError = quinn::ConnectionError; } impl ConnectionCommon for QuinnConnection { From e6f9a1a1b350835d0eb712230b02645be7578096 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Sun, 3 Nov 2024 20:29:24 +0200 Subject: [PATCH 10/32] cleanup --- Cargo.lock | 22 +++++++++++++++++ Cargo.toml | 1 + examples/modularize.rs | 5 +--- src/client.rs | 18 ++++++-------- src/lib.rs | 13 +++++----- src/server.rs | 29 +++++++++------------- src/transport/mapped.rs | 51 +++++++++++++++------------------------ src/transport/misc/mod.rs | 4 +-- src/transport/quinn.rs | 18 +++++++------- 9 files changed, 80 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 87f17ed..154a043 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -713,6 +713,18 @@ dependencies = [ "getrandom", ] +[[package]] +name = "nested_enum_utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f256ef99e7ac37428ef98c89bef9d84b590172de4bbfbe81b68a4cd3abadb32" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -870,6 +882,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -898,6 +919,7 @@ dependencies = [ "hex", "hyper", "iroh-quinn", + "nested_enum_utils", "pin-project", "proc-macro2", "rcgen", diff --git a/Cargo.toml b/Cargo.toml index ba87bb1..b718abc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ tempfile = "3.5.0" proc-macro2 = "1.0.66" futures-buffered = "0.2.4" testresult = "0.4.1" +nested_enum_utils = "0.1.0" [features] hyper-transport = ["dep:flume", "dep:hyper", "dep:bincode", "dep:bytes", "dep:tokio-serde", "dep:tokio-util"] diff --git a/examples/modularize.rs b/examples/modularize.rs index a67b7f5..2e0719c 100644 --- a/examples/modularize.rs +++ b/examples/modularize.rs @@ -101,15 +101,12 @@ mod app { //! //! It could also easily compose services from other crates or internal modules. + use super::iroh; use anyhow::Result; use derive_more::{From, TryInto}; use quic_rpc::{message::RpcMsg, server::RpcChannel, RpcClient, Service, ServiceEndpoint}; use serde::{Deserialize, Serialize}; - use crate::iroh::IrohService; - - use super::iroh; - #[derive(Debug, Serialize, Deserialize, From, TryInto)] pub enum Request { Iroh(iroh::Request), diff --git a/src/client.rs b/src/client.rs index a139fda..5f3f0af 100644 --- a/src/client.rs +++ b/src/client.rs @@ -17,6 +17,8 @@ use std::{ }; /// Type alias for a boxed connection to a specific service +/// +/// This is a convenience type alias for a boxed connection to a specific service. pub type BoxedServiceConnection = crate::transport::boxed::Connection<::Res, ::Req>; @@ -35,14 +37,14 @@ pub type BoxStreamSync<'a, T> = Pin + Send + Sync + 'a> #[derive(Debug)] pub struct RpcClient> { pub(crate) source: C, - pub(crate) p: PhantomData, + pub(crate) _p: PhantomData, } impl Clone for RpcClient { fn clone(&self) -> Self { Self { source: self.source.clone(), - p: PhantomData, + _p: PhantomData, } } } @@ -95,7 +97,7 @@ where pub fn new(source: C) -> Self { Self { source, - p: PhantomData, + _p: PhantomData, } } } @@ -127,10 +129,7 @@ where S::Req: From, SNext::Res: TryFrom, { - RpcClient { - source: self.source.map::(), - p: PhantomData, - } + RpcClient::new(self.source.map::()) } /// box @@ -138,10 +137,7 @@ where where C: BoxableConnection, { - RpcClient { - source: BoxedServiceConnection::::new(self.source), - p: PhantomData, - } + RpcClient::new(BoxedServiceConnection::::new(self.source)) } } diff --git a/src/lib.rs b/src/lib.rs index 7afdf63..7a261ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -159,19 +159,18 @@ pub trait Service: Send + Sync + Debug + Clone + 'static { /// A connection to a specific service on a specific remote machine /// -/// This is just a trait alias for a [Connection] with the right types. -/// -/// This can be used to create a [RpcClient] that can be used to send requests. +/// This is just a trait alias for a [Connection] with the right types. It is used +/// to make it easier to specify the bounds of a connection that matches a specific +/// service. pub trait ServiceConnection: Connection {} impl, S: Service> ServiceConnection for T {} /// A server endpoint for a specific service /// -/// This is just a trait alias for a [ServerEndpoint] with the right types. -/// -/// This can be used to create a [RpcServer] that can be used to handle -/// requests. +/// This is just a trait alias for a [ServerEndpoint] with the right types. It is used +/// to make it easier to specify the bounds of a server endpoint that matches a specific +/// service. pub trait ServiceEndpoint: ServerEndpoint {} impl, S: Service> ServiceEndpoint for T {} diff --git a/src/server.rs b/src/server.rs index 5e4172d..0281ab2 100644 --- a/src/server.rs +++ b/src/server.rs @@ -45,14 +45,14 @@ pub struct RpcServer> { /// Each new request is a receiver and channel pair on which messages for this request /// are received and responses sent. source: C, - p: PhantomData, + _p: PhantomData, } impl Clone for RpcServer { fn clone(&self) -> Self { Self { source: self.source.clone(), - p: PhantomData, + _p: PhantomData, } } } @@ -65,7 +65,7 @@ impl> RpcServer { pub fn new(source: C) -> Self { Self { source, - p: PhantomData, + _p: PhantomData, } } } @@ -92,7 +92,7 @@ pub struct RpcChannel< /// Stream to receive requests from the client. pub recv: C::RecvStream, - pub(crate) p: PhantomData, + pub(crate) _p: PhantomData, } impl RpcChannel @@ -105,7 +105,7 @@ where Self { send, recv, - p: PhantomData, + _p: PhantomData, } } @@ -118,11 +118,7 @@ where let send = transport::boxed::SendSink::boxed(Box::new(self.send.sink_map_err(|e| e.into()))); let recv = transport::boxed::RecvStream::boxed(Box::new(self.recv.map_err(|e| e.into()))); - RpcChannel { - send, - recv, - p: PhantomData, - } + RpcChannel::new(send, recv) } /// Map this channel's service into an inner service. @@ -140,11 +136,10 @@ where SNext::Req: TryFrom, S::Res: From, { - RpcChannel { - send: MappedSendSink::new(self.send), - recv: MappedRecvStream::new(self.recv), - p: PhantomData, - } + RpcChannel::new( + MappedSendSink::new(self.send), + MappedRecvStream::new(self.recv), + ) } } @@ -152,7 +147,7 @@ where pub struct Accepting> { send: C::SendSink, recv: C::RecvStream, - p: PhantomData, + _p: PhantomData, } impl> Accepting { @@ -187,7 +182,7 @@ impl> RpcServer { Ok(Accepting { send, recv, - p: PhantomData, + _p: PhantomData, }) } diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index 5b3c0ec..a46a261 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -17,7 +17,7 @@ use super::{Connection, ConnectionCommon, ConnectionErrors}; #[derive(Debug)] pub struct MappedConnection { inner: C, - _phantom: std::marker::PhantomData<(In, Out)>, + _p: std::marker::PhantomData<(In, Out)>, } impl MappedConnection @@ -30,7 +30,7 @@ where pub fn new(inner: C) -> Self { Self { inner, - _phantom: std::marker::PhantomData, + _p: std::marker::PhantomData, } } } @@ -42,7 +42,7 @@ where fn clone(&self) -> Self { Self { inner: self.inner.clone(), - _phantom: std::marker::PhantomData, + _p: std::marker::PhantomData, } } } @@ -97,7 +97,7 @@ where #[pin_project] pub struct MappedRecvStream { inner: S, - _phantom: std::marker::PhantomData, + _p: std::marker::PhantomData, } impl MappedRecvStream { @@ -105,7 +105,7 @@ impl MappedRecvStream { pub fn new(inner: S) -> Self { Self { inner, - _phantom: std::marker::PhantomData, + _p: std::marker::PhantomData, } } } @@ -158,7 +158,7 @@ where #[pin_project] pub struct MappedSendSink { inner: S, - _phantom: std::marker::PhantomData<(Out, OutS)>, + _p: std::marker::PhantomData<(Out, OutS)>, } impl MappedSendSink { @@ -166,7 +166,7 @@ impl MappedSendSink { pub fn new(inner: S) -> Self { Self { inner, - _phantom: std::marker::PhantomData, + _p: std::marker::PhantomData, } } } @@ -214,15 +214,6 @@ pub trait ConnectionMapExt: Connection { { MappedConnection::new(self) } - - /// Map this connection to a service - fn map_to_service(self) -> MappedConnection - where - S::Res: TryFrom, - Out: From, - { - MappedConnection::new(self) - } } impl ConnectionMapExt for C {} @@ -285,7 +276,7 @@ where let t: RpcChannel> = RpcChannel { send, recv, - p: PhantomData, + _p: PhantomData, }; t } @@ -295,10 +286,8 @@ where mod tests { use crate::{ - client::BoxedServiceConnection, server::{BoxedServiceChannel, RpcChannel}, - transport::{boxed::BoxableConnection, flume::FlumeConnection, ServerEndpoint}, - RpcClient, RpcServer, ServiceConnection, ServiceEndpoint, + RpcClient, RpcServer, }; use serde::{Deserialize, Serialize}; use testresult::TestResult; @@ -336,22 +325,22 @@ mod tests { #[tokio::test] async fn smoke() -> TestResult<()> { async fn handle_sub_request( - req: String, - chan: RpcChannel>, + _req: String, + _chan: RpcChannel>, ) -> anyhow::Result<()> { Ok(()) } - let (s, c): (_, FlumeConnection) = - crate::transport::flume::connection::(32); - let _x = c.clone().map::(); - - let _y = c.clone().map_to_service::(); - let s = RpcServer::::new(s); - return Ok(()); - while let Ok(accepting) = s.accept().await { + // create a server endpoint / connection pair. Type will be inferred + let (s, c) = crate::transport::flume::connection(32); + // wrap the server in a RpcServer, this is where the service type is specified + let server = RpcServer::::new(s); + // create a client in a RpcClient, this is where the service type is specified + let client = RpcClient::::new(c); + let _sub_client = client.clone().map::(); + while let Ok(accepting) = server.accept().await { let (msg, chan) = accepting.read_first().await?; match msg { - Request::A(x) => todo!(), + Request::A(_x) => todo!(), Request::B(x) => handle_sub_request(x, chan.map::().boxed()).await?, } } diff --git a/src/transport/misc/mod.rs b/src/transport/misc/mod.rs index b998111..53ea72f 100644 --- a/src/transport/misc/mod.rs +++ b/src/transport/misc/mod.rs @@ -16,13 +16,13 @@ use super::ConnectionCommon; /// an optional server endpoint. #[derive(Debug, Default)] pub struct DummyServerEndpoint { - _phantom: std::marker::PhantomData<(In, Out)>, + _p: std::marker::PhantomData<(In, Out)>, } impl Clone for DummyServerEndpoint { fn clone(&self) -> Self { Self { - _phantom: std::marker::PhantomData, + _p: std::marker::PhantomData, } } } diff --git a/src/transport/quinn.rs b/src/transport/quinn.rs index dcbb891..a47ad9e 100644 --- a/src/transport/quinn.rs +++ b/src/transport/quinn.rs @@ -58,7 +58,7 @@ impl Drop for ServerEndpointInner { #[derive(Debug)] pub struct QuinnServerEndpoint { inner: Arc, - _phantom: PhantomData<(In, Out)>, + _p: PhantomData<(In, Out)>, } impl QuinnServerEndpoint { @@ -128,7 +128,7 @@ impl QuinnServerEndpoint { local_addr: [LocalAddr::Socket(local_addr)], receiver, }), - _phantom: PhantomData, + _p: PhantomData, }) } @@ -154,7 +154,7 @@ impl QuinnServerEndpoint { local_addr: [LocalAddr::Socket(local_addr)], receiver, }), - _phantom: PhantomData, + _p: PhantomData, } } @@ -173,7 +173,7 @@ impl QuinnServerEndpoint { local_addr: [LocalAddr::Socket(local_addr)], receiver, }), - _phantom: PhantomData, + _p: PhantomData, } } } @@ -182,7 +182,7 @@ impl Clone for QuinnServerEndpoint { fn clone(&self) -> Self { Self { inner: self.inner.clone(), - _phantom: PhantomData, + _p: PhantomData, } } } @@ -257,7 +257,7 @@ impl Drop for ClientConnectionInner { /// A connection using a quinn connection pub struct QuinnConnection { inner: Arc, - _phantom: PhantomData<(In, Out)>, + _p: PhantomData<(In, Out)>, } impl QuinnConnection { @@ -442,7 +442,7 @@ impl QuinnConnection { task: Some(task), sender, }), - _phantom: PhantomData, + _p: PhantomData, } } @@ -461,7 +461,7 @@ impl QuinnConnection { task: Some(task), sender, }), - _phantom: PhantomData, + _p: PhantomData, } } } @@ -614,7 +614,7 @@ impl Clone for QuinnConnection { fn clone(&self) -> Self { Self { inner: self.inner.clone(), - _phantom: PhantomData, + _p: PhantomData, } } } From 6600b0deccd5934337455796d1a90c79e346b625 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Sun, 3 Nov 2024 20:52:12 +0200 Subject: [PATCH 11/32] clippy --- tests/util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/util.rs b/tests/util.rs index 6565748..47c560a 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -1,8 +1,8 @@ use anyhow::Context; -use quic_rpc::{server::RpcServerError, transport::Connection, RpcMessage}; +use quic_rpc::{server::RpcServerError, transport::Connection}; #[allow(unused)] -pub async fn check_termination_anyhow( +pub async fn check_termination_anyhow( server_handle: tokio::task::JoinHandle>, ) -> anyhow::Result<()> { // dropping the client will cause the server to terminate From f999020c4755a4439c7536dfe8dc2dc8b9d53bb9 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Sun, 3 Nov 2024 21:36:21 +0200 Subject: [PATCH 12/32] ignore smoke test that just hangs --- src/transport/mapped.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index a46a261..f534dbe 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -323,6 +323,7 @@ mod tests { } #[tokio::test] + #[ignore] async fn smoke() -> TestResult<()> { async fn handle_sub_request( _req: String, From 9e1a04bfd18a3622b989dd7cb08c246d837086f7 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Sun, 3 Nov 2024 21:49:51 +0200 Subject: [PATCH 13/32] Get rid of remaining XBiY They are all bi --- src/transport/boxed.rs | 8 +++--- src/transport/combined.rs | 38 ++++++++++++------------- src/transport/flume.rs | 58 +++++++++++++++++++-------------------- src/transport/hyper.rs | 32 ++++++++++----------- src/transport/quinn.rs | 6 ++-- 5 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index e932a45..599fddc 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -128,7 +128,7 @@ impl Stream for RecvStream { enum OpenFutureInner<'a, In: RpcMessage, Out: RpcMessage> { /// A direct future (todo) - Direct(super::flume::OpenBiFuture), + Direct(super::flume::OpenFuture), /// A boxed future Boxed(BoxFuture<'a, anyhow::Result<(SendSink, RecvStream)>>), } @@ -138,7 +138,7 @@ enum OpenFutureInner<'a, In: RpcMessage, Out: RpcMessage> { pub struct OpenFuture<'a, In: RpcMessage, Out: RpcMessage>(OpenFutureInner<'a, In, Out>); impl<'a, In: RpcMessage, Out: RpcMessage> OpenFuture<'a, In, Out> { - fn direct(f: super::flume::OpenBiFuture) -> Self { + fn direct(f: super::flume::OpenFuture) -> Self { Self(OpenFutureInner::Direct(f)) } @@ -166,7 +166,7 @@ impl<'a, In: RpcMessage, Out: RpcMessage> Future for OpenFuture<'a, In, Out> { enum AcceptFutureInner<'a, In: RpcMessage, Out: RpcMessage> { /// A direct future - Direct(super::flume::AcceptBiFuture), + Direct(super::flume::AcceptFuture), /// A boxed future Boxed(BoxedFuture<'a, anyhow::Result<(SendSink, RecvStream)>>), } @@ -176,7 +176,7 @@ enum AcceptFutureInner<'a, In: RpcMessage, Out: RpcMessage> { pub struct AcceptFuture<'a, In: RpcMessage, Out: RpcMessage>(AcceptFutureInner<'a, In, Out>); impl<'a, In: RpcMessage, Out: RpcMessage> AcceptFuture<'a, In, Out> { - fn direct(f: super::flume::AcceptBiFuture) -> Self { + fn direct(f: super::flume::AcceptFuture) -> Self { Self(AcceptFutureInner::Direct(f)) } diff --git a/src/transport/combined.rs b/src/transport/combined.rs index bf1cb06..cb3aef2 100644 --- a/src/transport/combined.rs +++ b/src/transport/combined.rs @@ -162,9 +162,9 @@ impl fmt::Display for RecvError impl error::Error for RecvError {} -/// OpenBiError for combined channels +/// OpenError for combined channels #[derive(Debug)] -pub enum OpenBiError { +pub enum OpenError { /// A variant A(A::OpenError), /// B variant @@ -173,36 +173,36 @@ pub enum OpenBiError { NoChannel, } -impl fmt::Display for OpenBiError { +impl fmt::Display for OpenError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for OpenBiError {} +impl error::Error for OpenError {} -/// AcceptBiError for combined channels +/// AcceptError for combined channels #[derive(Debug)] -pub enum AcceptBiError { +pub enum AcceptError { /// A variant A(A::AcceptError), /// B variant B(B::AcceptError), } -impl fmt::Display for AcceptBiError { +impl fmt::Display for AcceptError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for AcceptBiError {} +impl error::Error for AcceptError {} impl ConnectionErrors for CombinedConnection { type SendError = self::SendError; type RecvError = self::RecvError; - type OpenError = self::OpenBiError; - type AcceptError = self::AcceptBiError; + type OpenError = self::OpenError; + type AcceptError = self::AcceptError; } impl> ConnectionCommon @@ -221,13 +221,13 @@ impl> Connection let this = self.clone(); // try a first, then b if let Some(a) = this.a { - let (send, recv) = a.open().await.map_err(OpenBiError::A)?; + let (send, recv) = a.open().await.map_err(OpenError::A)?; Ok((SendSink::A(send), RecvStream::A(recv))) } else if let Some(b) = this.b { - let (send, recv) = b.open().await.map_err(OpenBiError::B)?; + let (send, recv) = b.open().await.map_err(OpenError::B)?; Ok((SendSink::B(send), RecvStream::B(recv))) } else { - Err(OpenBiError::NoChannel) + Err(OpenError::NoChannel) } } } @@ -235,8 +235,8 @@ impl> Connection impl ConnectionErrors for CombinedServerEndpoint { type SendError = self::SendError; type RecvError = self::RecvError; - type OpenError = self::OpenBiError; - type AcceptError = self::AcceptBiError; + type OpenError = self::OpenError; + type AcceptError = self::AcceptError; } impl> ConnectionCommon @@ -254,7 +254,7 @@ impl> ServerEndpo async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::AcceptError> { let a_fut = async { if let Some(a) = &self.a { - let (send, recv) = a.accept().await.map_err(AcceptBiError::A)?; + let (send, recv) = a.accept().await.map_err(AcceptError::A)?; Ok((SendSink::A(send), RecvStream::A(recv))) } else { std::future::pending().await @@ -262,7 +262,7 @@ impl> ServerEndpo }; let b_fut = async { if let Some(b) = &self.b { - let (send, recv) = b.accept().await.map_err(AcceptBiError::B)?; + let (send, recv) = b.accept().await.map_err(AcceptError::B)?; Ok((SendSink::B(send), RecvStream::B(recv))) } else { std::future::pending().await @@ -286,7 +286,7 @@ impl> ServerEndpo mod tests { use crate::{ transport::{ - combined::{self, OpenBiError}, + combined::{self, OpenError}, flume, }, Connection, @@ -299,6 +299,6 @@ mod tests { flume::FlumeConnection<(), ()>, >::new(None, None); let res = channel.open().await; - assert!(matches!(res, Err(OpenBiError::NoChannel))); + assert!(matches!(res, Err(OpenError::NoChannel))); } } diff --git a/src/transport/flume.rs b/src/transport/flume.rs index 4c9ec1d..9e5f736 100644 --- a/src/transport/flume.rs +++ b/src/transport/flume.rs @@ -124,25 +124,25 @@ impl fmt::Debug for FlumeServerEndpoint ConnectionErrors for FlumeServerEndpoint { type SendError = self::SendError; type RecvError = self::RecvError; - type OpenError = self::OpenBiError; - type AcceptError = self::AcceptBiError; + type OpenError = self::OpenError; + type AcceptError = self::AcceptError; } type Socket = (self::SendSink, self::RecvStream); /// Future returned by [FlumeConnection::open] -pub struct OpenBiFuture { +pub struct OpenFuture { inner: flume::r#async::SendFut<'static, Socket>, res: Option>, } -impl fmt::Debug for OpenBiFuture { +impl fmt::Debug for OpenFuture { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OpenBiFuture").finish() + f.debug_struct("OpenFuture").finish() } } -impl OpenBiFuture { +impl OpenFuture { fn new(inner: flume::r#async::SendFut<'static, Socket>, res: Socket) -> Self { Self { inner, @@ -151,8 +151,8 @@ impl OpenBiFuture { } } -impl Future for OpenBiFuture { - type Output = result::Result, self::OpenBiError>; +impl Future for OpenFuture { + type Output = result::Result, self::OpenError>; fn poll( mut self: Pin<&mut Self>, @@ -164,31 +164,31 @@ impl Future for OpenBiFuture { .take() .map(|x| Poll::Ready(Ok(x))) .unwrap_or(Poll::Pending), - Poll::Ready(Err(_)) => Poll::Ready(Err(self::OpenBiError::RemoteDropped)), + Poll::Ready(Err(_)) => Poll::Ready(Err(self::OpenError::RemoteDropped)), Poll::Pending => Poll::Pending, } } } /// Future returned by [FlumeServerEndpoint::accept] -pub struct AcceptBiFuture { +pub struct AcceptFuture { wrapped: flume::r#async::RecvFut<'static, (SendSink, RecvStream)>, _p: PhantomData<(In, Out)>, } -impl fmt::Debug for AcceptBiFuture { +impl fmt::Debug for AcceptFuture { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("AcceptBiFuture").finish() + f.debug_struct("AcceptFuture").finish() } } -impl Future for AcceptBiFuture { - type Output = result::Result<(SendSink, RecvStream), AcceptBiError>; +impl Future for AcceptFuture { + type Output = result::Result<(SendSink, RecvStream), AcceptError>; fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { match Pin::new(&mut self.wrapped).poll(cx) { Poll::Ready(Ok((send, recv))) => Poll::Ready(Ok((send, recv))), - Poll::Ready(Err(_)) => Poll::Ready(Err(AcceptBiError::RemoteDropped)), + Poll::Ready(Err(_)) => Poll::Ready(Err(AcceptError::RemoteDropped)), Poll::Pending => Poll::Pending, } } @@ -203,8 +203,8 @@ impl ConnectionCommon for FlumeServerEndpoint ServerEndpoint for FlumeServerEndpoint { #[allow(refining_impl_trait)] - fn accept(&self) -> AcceptBiFuture { - AcceptBiFuture { + fn accept(&self) -> AcceptFuture { + AcceptFuture { wrapped: self.stream.clone().into_recv_async(), _p: PhantomData, } @@ -218,8 +218,8 @@ impl ServerEndpoint for FlumeServerEndpoint ConnectionErrors for FlumeConnection { type SendError = self::SendError; type RecvError = self::RecvError; - type OpenError = self::OpenBiError; - type AcceptError = self::AcceptBiError; + type OpenError = self::OpenError; + type AcceptError = self::AcceptError; } impl ConnectionCommon for FlumeConnection { @@ -231,7 +231,7 @@ impl ConnectionCommon for FlumeConnection Connection for FlumeConnection { #[allow(refining_impl_trait)] - fn open(&self) -> OpenBiFuture { + fn open(&self) -> OpenFuture { let (local_send, remote_recv) = flume::bounded::(128); let (remote_send, local_recv) = flume::bounded::(128); let remote_chan = ( @@ -242,7 +242,7 @@ impl Connection for FlumeConnection { SendSink(local_send.into_sink()), RecvStream(local_recv.into_stream()), ); - OpenBiFuture::new(self.sink.clone().into_send_async(remote_chan), local_chan) + OpenFuture::new(self.sink.clone().into_send_async(remote_chan), local_chan) } } @@ -270,22 +270,22 @@ impl fmt::Debug for FlumeConnection { } } -/// AcceptBiError for mem channels. +/// AcceptError for mem channels. /// /// There is not much that can go wrong with mem channels. #[derive(Debug)] -pub enum AcceptBiError { +pub enum AcceptError { /// The remote side of the channel was dropped RemoteDropped, } -impl fmt::Display for AcceptBiError { +impl fmt::Display for AcceptError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for AcceptBiError {} +impl error::Error for AcceptError {} /// SendError for mem channels. /// @@ -304,20 +304,20 @@ impl Display for SendError { impl std::error::Error for SendError {} -/// OpenBiError for mem channels. +/// OpenError for mem channels. #[derive(Debug)] -pub enum OpenBiError { +pub enum OpenError { /// The remote side of the channel was dropped RemoteDropped, } -impl Display for OpenBiError { +impl Display for OpenError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl std::error::Error for OpenBiError {} +impl std::error::Error for OpenError {} /// CreateChannelError for mem channels. /// diff --git a/src/transport/hyper.rs b/src/transport/hyper.rs index c8ac35c..b0bba7f 100644 --- a/src/transport/hyper.rs +++ b/src/transport/hyper.rs @@ -536,9 +536,9 @@ impl fmt::Display for RecvError { impl error::Error for RecvError {} -/// OpenBiError for hyper channels. +/// OpenError for hyper channels. #[derive(Debug)] -pub enum OpenBiError { +pub enum OpenError { /// Hyper http error HyperHttp(hyper::http::Error), /// Generic hyper error @@ -547,41 +547,41 @@ pub enum OpenBiError { RemoteDropped, } -impl fmt::Display for OpenBiError { +impl fmt::Display for OpenError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl std::error::Error for OpenBiError {} +impl std::error::Error for OpenError {} -/// AcceptBiError for hyper channels. +/// AcceptError for hyper channels. /// /// There is not much that can go wrong with hyper channels. #[derive(Debug)] -pub enum AcceptBiError { +pub enum AcceptError { /// Hyper error Hyper(hyper::http::Error), /// The remote side of the channel was dropped RemoteDropped, } -impl fmt::Display for AcceptBiError { +impl fmt::Display for AcceptError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for AcceptBiError {} +impl error::Error for AcceptError {} impl ConnectionErrors for HyperConnection { type SendError = self::SendError; type RecvError = self::RecvError; - type OpenError = OpenBiError; + type OpenError = OpenError; - type AcceptError = AcceptBiError; + type AcceptError = AcceptError; } impl ConnectionCommon for HyperConnection { @@ -596,13 +596,13 @@ impl Connection for HyperConnection { let (out_tx, out_rx) = flume::bounded::>(32); let req: Request = Request::post(&self.inner.uri) .body(Body::wrap_stream(out_rx.into_stream())) - .map_err(OpenBiError::HyperHttp)?; + .map_err(OpenError::HyperHttp)?; let res = self .inner .client .request(req) .await - .map_err(OpenBiError::Hyper)?; + .map_err(OpenError::Hyper)?; let (in_tx, in_rx) = flume::bounded::>(32); spawn_recv_forwarder(res.into_body(), in_tx); @@ -615,8 +615,8 @@ impl Connection for HyperConnection { impl ConnectionErrors for HyperServerEndpoint { type SendError = self::SendError; type RecvError = self::RecvError; - type OpenError = AcceptBiError; - type AcceptError = AcceptBiError; + type OpenError = AcceptError; + type AcceptError = AcceptError; } impl ConnectionCommon for HyperServerEndpoint { @@ -631,12 +631,12 @@ impl ServerEndpoint for HyperServerEndpoint Result<(Self::SendSink, Self::RecvStream), AcceptBiError> { + async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), AcceptError> { let (recv, send) = self .channel .recv_async() .await - .map_err(|_| AcceptBiError::RemoteDropped)?; + .map_err(|_| AcceptError::RemoteDropped)?; Ok(( SendSink::new(send, self.config.clone()), RecvStream::new(recv), diff --git a/src/transport/quinn.rs b/src/transport/quinn.rs index a47ad9e..261f5a7 100644 --- a/src/transport/quinn.rs +++ b/src/transport/quinn.rs @@ -202,7 +202,7 @@ impl ConnectionCommon for QuinnServerEndpoint ServerEndpoint for QuinnServerEndpoint { - async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), AcceptBiError> { + async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), AcceptError> { let (send, recv) = self .inner .receiver @@ -745,10 +745,10 @@ impl Stream for RecvStream { } /// Error for open. Currently just a quinn::ConnectionError -pub type OpenBiError = quinn::ConnectionError; +pub type OpenError = quinn::ConnectionError; /// Error for accept. Currently just a quinn::ConnectionError -pub type AcceptBiError = quinn::ConnectionError; +pub type AcceptError = quinn::ConnectionError; /// CreateChannelError for quinn channels. #[derive(Debug, Clone)] From 66eeeb1ce7aea4fdc8b87c06774a3098f0894c95 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Sun, 3 Nov 2024 22:26:51 +0200 Subject: [PATCH 14/32] Make the boxed transport available by default. --- Cargo.toml | 2 +- src/transport/boxed.rs | 21 ++++++++++++++++++--- src/transport/combined.rs | 1 + src/transport/mapped.rs | 1 + src/transport/mod.rs | 1 - 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b718abc..785d4a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,7 @@ quinn-transport = ["dep:flume", "dep:quinn", "dep:bincode", "dep:tokio-serde", " flume-transport = ["dep:flume"] combined-transport = [] macros = [] -default = ["flume-transport", "quinn-transport", "combined-transport"] +default = ["quinn-transport", "combined-transport"] [package.metadata.docs.rs] all-features = true diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index 599fddc..11ed81c 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -8,9 +8,7 @@ use std::{ use futures_lite::FutureExt; use futures_sink::Sink; -#[cfg(feature = "quinn-transport")] -use futures_util::TryStreamExt; -use futures_util::{future::BoxFuture, SinkExt, Stream, StreamExt}; +use futures_util::{future::BoxFuture, SinkExt, Stream, StreamExt, TryStreamExt}; use pin_project::pin_project; use std::future::Future; @@ -20,6 +18,7 @@ use super::{ConnectionCommon, ConnectionErrors}; type BoxedFuture<'a, T> = Pin + Send + Sync + 'a>>; enum SendSinkInner { + #[cfg(feature = "flume-transport")] Direct(::flume::r#async::SendSink<'static, T>), Boxed(Pin + Send + Sync + 'static>>), } @@ -39,6 +38,7 @@ impl SendSink { } /// Create a new send sink from a direct flume send sink + #[cfg(feature = "flume-transport")] pub(crate) fn direct(sink: ::flume::r#async::SendSink<'static, T>) -> Self { Self(SendSinkInner::Direct(sink)) } @@ -52,6 +52,7 @@ impl Sink for SendSink { cx: &mut std::task::Context<'_>, ) -> Poll> { match self.project().0 { + #[cfg(feature = "flume-transport")] SendSinkInner::Direct(sink) => sink.poll_ready_unpin(cx).map_err(anyhow::Error::from), SendSinkInner::Boxed(sink) => sink.poll_ready_unpin(cx).map_err(anyhow::Error::from), } @@ -59,6 +60,7 @@ impl Sink for SendSink { fn start_send(self: std::pin::Pin<&mut Self>, item: T) -> Result<(), Self::Error> { match self.project().0 { + #[cfg(feature = "flume-transport")] SendSinkInner::Direct(sink) => sink.start_send_unpin(item).map_err(anyhow::Error::from), SendSinkInner::Boxed(sink) => sink.start_send_unpin(item).map_err(anyhow::Error::from), } @@ -69,6 +71,7 @@ impl Sink for SendSink { cx: &mut Context<'_>, ) -> Poll> { match self.project().0 { + #[cfg(feature = "flume-transport")] SendSinkInner::Direct(sink) => sink.poll_flush_unpin(cx).map_err(anyhow::Error::from), SendSinkInner::Boxed(sink) => sink.poll_flush_unpin(cx).map_err(anyhow::Error::from), } @@ -79,6 +82,7 @@ impl Sink for SendSink { cx: &mut Context<'_>, ) -> Poll> { match self.project().0 { + #[cfg(feature = "flume-transport")] SendSinkInner::Direct(sink) => sink.poll_close_unpin(cx).map_err(anyhow::Error::from), SendSinkInner::Boxed(sink) => sink.poll_close_unpin(cx).map_err(anyhow::Error::from), } @@ -86,6 +90,7 @@ impl Sink for SendSink { } enum RecvStreamInner { + #[cfg(feature = "flume-transport")] Direct(::flume::r#async::RecvStream<'static, T>), Boxed(Pin> + Send + Sync + 'static>>), } @@ -106,6 +111,7 @@ impl RecvStream { } /// Create a new receive stream from a direct flume receive stream + #[cfg(feature = "flume-transport")] pub(crate) fn direct(stream: ::flume::r#async::RecvStream<'static, T>) -> Self { Self(RecvStreamInner::Direct(stream)) } @@ -116,6 +122,7 @@ impl Stream for RecvStream { fn poll_next(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { match self.project().0 { + #[cfg(feature = "flume-transport")] RecvStreamInner::Direct(stream) => match stream.poll_next_unpin(cx) { Poll::Ready(Some(item)) => Poll::Ready(Some(Ok(item))), Poll::Ready(None) => Poll::Ready(None), @@ -128,6 +135,7 @@ impl Stream for RecvStream { enum OpenFutureInner<'a, In: RpcMessage, Out: RpcMessage> { /// A direct future (todo) + #[cfg(feature = "flume-transport")] Direct(super::flume::OpenFuture), /// A boxed future Boxed(BoxFuture<'a, anyhow::Result<(SendSink, RecvStream)>>), @@ -138,6 +146,8 @@ enum OpenFutureInner<'a, In: RpcMessage, Out: RpcMessage> { pub struct OpenFuture<'a, In: RpcMessage, Out: RpcMessage>(OpenFutureInner<'a, In, Out>); impl<'a, In: RpcMessage, Out: RpcMessage> OpenFuture<'a, In, Out> { + + #[cfg(feature = "flume-transport")] fn direct(f: super::flume::OpenFuture) -> Self { Self(OpenFutureInner::Direct(f)) } @@ -155,6 +165,7 @@ impl<'a, In: RpcMessage, Out: RpcMessage> Future for OpenFuture<'a, In, Out> { fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { match self.project().0 { + #[cfg(feature = "flume-transport")] OpenFutureInner::Direct(f) => f .poll(cx) .map_ok(|(send, recv)| (SendSink::direct(send.0), RecvStream::direct(recv.0))) @@ -166,6 +177,7 @@ impl<'a, In: RpcMessage, Out: RpcMessage> Future for OpenFuture<'a, In, Out> { enum AcceptFutureInner<'a, In: RpcMessage, Out: RpcMessage> { /// A direct future + #[cfg(feature = "flume-transport")] Direct(super::flume::AcceptFuture), /// A boxed future Boxed(BoxedFuture<'a, anyhow::Result<(SendSink, RecvStream)>>), @@ -176,6 +188,8 @@ enum AcceptFutureInner<'a, In: RpcMessage, Out: RpcMessage> { pub struct AcceptFuture<'a, In: RpcMessage, Out: RpcMessage>(AcceptFutureInner<'a, In, Out>); impl<'a, In: RpcMessage, Out: RpcMessage> AcceptFuture<'a, In, Out> { + + #[cfg(feature = "flume-transport")] fn direct(f: super::flume::AcceptFuture) -> Self { Self(AcceptFutureInner::Direct(f)) } @@ -193,6 +207,7 @@ impl<'a, In: RpcMessage, Out: RpcMessage> Future for AcceptFuture<'a, In, Out> { fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { match self.project().0 { + #[cfg(feature = "flume-transport")] AcceptFutureInner::Direct(f) => f .poll(cx) .map_ok(|(send, recv)| (SendSink::direct(send.0), RecvStream::direct(recv.0))) diff --git a/src/transport/combined.rs b/src/transport/combined.rs index cb3aef2..43742ba 100644 --- a/src/transport/combined.rs +++ b/src/transport/combined.rs @@ -283,6 +283,7 @@ impl> ServerEndpo } #[cfg(test)] +#[cfg(feature = "flume-transport")] mod tests { use crate::{ transport::{ diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index f534dbe..48dfa2d 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -283,6 +283,7 @@ where } #[cfg(test)] +#[cfg(feature = "flume-transport")] mod tests { use crate::{ diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 70de1b9..ff7bba2 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -25,7 +25,6 @@ use std::{ fmt::{self, Debug, Display}, net::SocketAddr, }; -#[cfg(feature = "flume-transport")] pub mod boxed; #[cfg(feature = "combined-transport")] pub mod combined; From 69edba32ffa523679d1ef334b67e0be10261e9a3 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Sun, 3 Nov 2024 22:57:47 +0200 Subject: [PATCH 15/32] Make boxed and combined available by default. They don't bring in deps, so why not. Boxed is universally useful, and if it is not default I can't use it as default. --- Cargo.toml | 3 +-- examples/errors.rs | 4 ++-- examples/macro.rs | 2 +- examples/store.rs | 4 ++-- src/lib.rs | 2 +- src/transport/boxed.rs | 4 +--- src/transport/mod.rs | 1 - tests/flume.rs | 6 +++--- tests/try.rs | 2 +- 9 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 785d4a5..c1b468b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,9 +56,8 @@ nested_enum_utils = "0.1.0" hyper-transport = ["dep:flume", "dep:hyper", "dep:bincode", "dep:bytes", "dep:tokio-serde", "dep:tokio-util"] quinn-transport = ["dep:flume", "dep:quinn", "dep:bincode", "dep:tokio-serde", "dep:tokio-util"] flume-transport = ["dep:flume"] -combined-transport = [] macros = [] -default = ["quinn-transport", "combined-transport"] +default = ["flume-transport", "quinn-transport"] [package.metadata.docs.rs] all-features = true diff --git a/examples/errors.rs b/examples/errors.rs index ffedb1e..4f9a069 100644 --- a/examples/errors.rs +++ b/examples/errors.rs @@ -55,8 +55,8 @@ impl Fs { #[tokio::main] async fn main() -> anyhow::Result<()> { let fs = Fs; - let (server, client) = quic_rpc::transport::flume::service_connection::(1); - let client = RpcClient::new(client); + let (server, client) = quic_rpc::transport::flume::connection(1); + let client = RpcClient::::new(client); let server = RpcServer::new(server); let handle = tokio::task::spawn(async move { for _ in 0..1 { diff --git a/examples/macro.rs b/examples/macro.rs index e626816..7492ec0 100644 --- a/examples/macro.rs +++ b/examples/macro.rs @@ -105,7 +105,7 @@ create_store_dispatch!(Store, dispatch_store_request); #[tokio::main] async fn main() -> anyhow::Result<()> { - let (server, client) = flume::service_connection::(1); + let (server, client) = flume::connection(1); let server_handle = tokio::task::spawn(async move { let target = Store; run_server_loop(StoreService, server, target, dispatch_store_request).await diff --git a/examples/store.rs b/examples/store.rs index 8f8e0f8..280ca87 100644 --- a/examples/store.rs +++ b/examples/store.rs @@ -184,7 +184,7 @@ async fn main() -> anyhow::Result<()> { } } - let (server, client) = flume::service_connection::(1); + let (server, client) = flume::connection(1); let client = RpcClient::::new(client); let server = RpcServer::::new(server); let server_handle = tokio::task::spawn(server_future(server)); @@ -237,7 +237,7 @@ async fn _main_unsugared() -> anyhow::Result<()> { type Req = u64; type Res = String; } - let (server, client) = flume::service_connection::(1); + let (server, client) = flume::connection::(1); let to_string_service = tokio::spawn(async move { let (mut send, mut recv) = server.accept().await?; while let Some(item) = recv.next().await { diff --git a/src/lib.rs b/src/lib.rs index 7a261ae..197e8c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ //! } //! //! // create a transport channel, here a memory channel for testing -//! let (server, client) = quic_rpc::transport::flume::service_connection::(1); +//! let (server, client) = quic_rpc::transport::flume::connection(1); //! //! // client side //! // create the rpc client given the channel and the service type diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index 11ed81c..47833bb 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -146,7 +146,6 @@ enum OpenFutureInner<'a, In: RpcMessage, Out: RpcMessage> { pub struct OpenFuture<'a, In: RpcMessage, Out: RpcMessage>(OpenFutureInner<'a, In, Out>); impl<'a, In: RpcMessage, Out: RpcMessage> OpenFuture<'a, In, Out> { - #[cfg(feature = "flume-transport")] fn direct(f: super::flume::OpenFuture) -> Self { Self(OpenFutureInner::Direct(f)) @@ -188,7 +187,6 @@ enum AcceptFutureInner<'a, In: RpcMessage, Out: RpcMessage> { pub struct AcceptFuture<'a, In: RpcMessage, Out: RpcMessage>(AcceptFutureInner<'a, In, Out>); impl<'a, In: RpcMessage, Out: RpcMessage> AcceptFuture<'a, In, Out> { - #[cfg(feature = "flume-transport")] fn direct(f: super::flume::AcceptFuture) -> Self { Self(AcceptFutureInner::Direct(f)) @@ -454,7 +452,7 @@ mod tests { use crate::transport::{Connection, ServerEndpoint}; - let (server, client) = crate::transport::flume::service_connection::(1); + let (server, client) = crate::transport::flume::connection(1); let server = super::ServerEndpoint::new(server); let client = super::Connection::new(client); // spawn echo server diff --git a/src/transport/mod.rs b/src/transport/mod.rs index ff7bba2..3b6aee7 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -26,7 +26,6 @@ use std::{ net::SocketAddr, }; pub mod boxed; -#[cfg(feature = "combined-transport")] pub mod combined; #[cfg(feature = "flume-transport")] pub mod flume; diff --git a/tests/flume.rs b/tests/flume.rs index 514667b..e9e1097 100644 --- a/tests/flume.rs +++ b/tests/flume.rs @@ -11,7 +11,7 @@ use quic_rpc::{ #[tokio::test] async fn flume_channel_bench() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); - let (server, client) = flume::service_connection::(1); + let (server, client) = flume::connection(1); let server = RpcServer::::new(server); let server_handle = tokio::task::spawn(ComputeService::server(server)); @@ -60,7 +60,7 @@ async fn flume_channel_mapped_bench() -> anyhow::Result<()> { type Req = InnerRequest; type Res = InnerResponse; } - let (server, client) = flume::service_connection::(1); + let (server, client) = flume::connection(1); let server = RpcServer::::new(server); let server_handle: tokio::task::JoinHandle>> = @@ -98,7 +98,7 @@ async fn flume_channel_mapped_bench() -> anyhow::Result<()> { #[tokio::test] async fn flume_channel_smoke() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); - let (server, client) = flume::service_connection::(1); + let (server, client) = flume::connection(1); let server = RpcServer::::new(server); let server_handle = tokio::task::spawn(ComputeService::server(server)); diff --git a/tests/try.rs b/tests/try.rs index 72ae87d..66cabcd 100644 --- a/tests/try.rs +++ b/tests/try.rs @@ -72,7 +72,7 @@ impl Handler { #[tokio::test] async fn try_server_streaming() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); - let (server, client) = flume::service_connection::(1); + let (server, client) = flume::connection(1); let server = RpcServer::::new(server); let server_handle = tokio::task::spawn(async move { From ffaf803dff9eb210c540914b27e8f04efa8e2c3f Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Mon, 4 Nov 2024 11:41:27 +0200 Subject: [PATCH 16/32] Avoid using public PhantomData in UpdateSink also make sure boxing is more convenient --- src/client.rs | 16 +++++++++++++--- src/lib.rs | 3 +++ src/pattern/bidi_streaming.rs | 11 +++++------ src/pattern/client_streaming.rs | 9 ++++----- src/pattern/rpc.rs | 6 +++--- src/server.rs | 12 ++++++++++++ src/transport/boxed.rs | 16 ++++++++++++++++ src/transport/mapped.rs | 18 +++++++++++++++--- 8 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/client.rs b/src/client.rs index 5f3f0af..d62e8ce 100644 --- a/src/client.rs +++ b/src/client.rs @@ -53,10 +53,20 @@ impl Clone for RpcClient { /// that support it, [crate::message::ClientStreaming] and [crate::message::BidiStreaming]. #[pin_project] #[derive(Debug)] -pub struct UpdateSink(#[pin] pub C::SendSink, pub PhantomData) +pub struct UpdateSink(#[pin] pub C::SendSink, PhantomData) +where + C: ConnectionCommon; + +impl UpdateSink where C: ConnectionCommon, - T: Into; + T: Into, +{ + /// Create a new update sink + pub fn new(sink: C::SendSink) -> Self { + Self(sink, PhantomData) + } +} impl Sink for UpdateSink where @@ -137,7 +147,7 @@ where where C: BoxableConnection, { - RpcClient::new(BoxedServiceConnection::::new(self.source)) + RpcClient::new(self.source.boxed()) } } diff --git a/src/lib.rs b/src/lib.rs index 197e8c9..9c182c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,6 +126,9 @@ impl RpcMessage for T where /// /// We don't require them to implement [std::error::Error] so we can use /// anyhow::Error as an error type. +/// +/// Instead we require them to implement `Into`, which is available +/// both for any type that implements [std::error::Error] and anyhow itself. pub trait RpcError: Debug + Display + Into + Send + Sync + Unpin + 'static {} impl RpcError for T where T: Debug + Display + Into + Send + Sync + Unpin + 'static diff --git a/src/pattern/bidi_streaming.rs b/src/pattern/bidi_streaming.rs index 4b0fb2e..7411130 100644 --- a/src/pattern/bidi_streaming.rs +++ b/src/pattern/bidi_streaming.rs @@ -14,7 +14,6 @@ use crate::{ use std::{ error, fmt::{self, Debug}, - marker::PhantomData, result, }; @@ -49,13 +48,13 @@ pub enum Error { Send(C::SendError), } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} /// Server error when receiving an item for a bidi request #[derive(Debug)] @@ -66,13 +65,13 @@ pub enum ItemError { DowncastError, } -impl fmt::Display for ItemError { +impl fmt::Display for ItemError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for ItemError {} +impl error::Error for ItemError {} impl RpcClient where @@ -96,7 +95,7 @@ where let msg = msg.into(); let (mut send, recv) = self.source.open().await.map_err(Error::Open)?; send.send(msg).await.map_err(Error::::Send)?; - let send = UpdateSink(send, PhantomData); + let send = UpdateSink::new(send); let recv = Box::pin(recv.map(move |x| match x { Ok(msg) => M::Response::try_from(msg).map_err(|_| ItemError::DowncastError), Err(e) => Err(ItemError::RecvError(e)), diff --git a/src/pattern/client_streaming.rs b/src/pattern/client_streaming.rs index 8d489e1..49549a3 100644 --- a/src/pattern/client_streaming.rs +++ b/src/pattern/client_streaming.rs @@ -7,14 +7,13 @@ use crate::{ client::UpdateSink, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, - transport::{Connection, ConnectionCommon, ConnectionErrors}, + transport::{ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, }; use std::{ error, fmt::{self, Debug}, - marker::PhantomData, result, }; @@ -49,13 +48,13 @@ pub enum Error { Send(C::SendError), } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} /// Server error when receiving an item for a client streaming request #[derive(Debug)] @@ -98,7 +97,7 @@ where let msg = msg.into(); let (mut send, mut recv) = self.source.open().await.map_err(Error::Open)?; send.send(msg).map_err(Error::Send).await?; - let send = UpdateSink::(send, PhantomData); + let send = UpdateSink::::new(send); let recv = async move { let item = recv.next().await.ok_or(ItemError::EarlyClose)?; diff --git a/src/pattern/rpc.rs b/src/pattern/rpc.rs index 5a10228..ed2e708 100644 --- a/src/pattern/rpc.rs +++ b/src/pattern/rpc.rs @@ -6,7 +6,7 @@ use futures_util::{FutureExt, SinkExt}; use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::{Connection, ConnectionCommon, ConnectionErrors}, + transport::{ConnectionCommon, ConnectionErrors}, RpcClient, Service, ServiceConnection, }; @@ -54,13 +54,13 @@ pub enum Error { DowncastError, } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} impl RpcClient where diff --git a/src/server.rs b/src/server.rs index 0281ab2..1b99904 100644 --- a/src/server.rs +++ b/src/server.rs @@ -4,6 +4,7 @@ use crate::{ transport::{ self, + boxed::BoxableServerEndpoint, mapped::{MappedConnectionTypes, MappedRecvStream, MappedSendSink}, ConnectionCommon, ConnectionErrors, }, @@ -68,6 +69,17 @@ impl> RpcServer { _p: PhantomData, } } + + /// Box the transport for the service. + /// + /// The boxed transport is the default for the `C` type parameter, so by boxing we can avoid + /// having to specify the type parameter. + pub fn boxed(self) -> RpcServer> + where + C: BoxableServerEndpoint, + { + RpcServer::new(self.source.boxed()) + } } /// A channel for requests and responses for a specific service. diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index 47833bb..66af78d 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -224,6 +224,14 @@ pub trait BoxableConnection: /// Open a channel to the remote che fn open_boxed(&self) -> OpenFuture; + + /// Box the connection + fn boxed(self) -> self::Connection + where + Self: Sized + 'static, + { + self::Connection::new(self) + } } /// A boxed connection @@ -275,6 +283,14 @@ pub trait BoxableServerEndpoint: /// Get the local address fn local_addr(&self) -> &[super::LocalAddr]; + + /// Box the server endpoint + fn boxed(self) -> ServerEndpoint + where + Self: Sized + 'static, + { + ServerEndpoint::new(self) + } } /// A boxed server endpoint diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index 48dfa2d..d5d8d67 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -288,6 +288,7 @@ mod tests { use crate::{ server::{BoxedServiceChannel, RpcChannel}, + transport::boxed::BoxableServerEndpoint, RpcClient, RpcServer, }; use serde::{Deserialize, Serialize}; @@ -335,15 +336,26 @@ mod tests { // create a server endpoint / connection pair. Type will be inferred let (s, c) = crate::transport::flume::connection(32); // wrap the server in a RpcServer, this is where the service type is specified - let server = RpcServer::::new(s); + let server = RpcServer::::new(s.clone()); + // when using a boxed transport, we can omit the transport type and use the default + let _server_boxed: RpcServer = RpcServer::::new(s.boxed()); // create a client in a RpcClient, this is where the service type is specified let client = RpcClient::::new(c); - let _sub_client = client.clone().map::(); + // when using a boxed transport, we can omit the transport type and use the default + let _boxed_client = client.clone().boxed(); + // map the client to a sub-service + let _sub_client: RpcClient = client.clone().map::(); + // when using a boxed transport, we can omit the transport type and use the default + let _sub_client_boxed: RpcClient = client.clone().map::().boxed(); + // we can not map the service to a sub-service, since we need the first message to determine which sub-service to use while let Ok(accepting) = server.accept().await { let (msg, chan) = accepting.read_first().await?; match msg { Request::A(_x) => todo!(), - Request::B(x) => handle_sub_request(x, chan.map::().boxed()).await?, + Request::B(x) => { + // map the channel to the sub-service + handle_sub_request(x, chan.map::().boxed()).await? + } } } Ok(()) From c30ba6a08c3ec0e1a05ff6f15a1681cd75ddcf0f Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Mon, 4 Nov 2024 12:47:15 +0200 Subject: [PATCH 17/32] Drop ConnectionMapExt and just move map directly to Connection --- src/client.rs | 2 -- src/transport/mapped.rs | 41 ++--------------------------------------- src/transport/mod.rs | 10 ++++++++++ 3 files changed, 12 insertions(+), 41 deletions(-) diff --git a/src/client.rs b/src/client.rs index d62e8ce..b2cc2f6 100644 --- a/src/client.rs +++ b/src/client.rs @@ -112,8 +112,6 @@ where } } -use crate::transport::mapped::ConnectionMapExt; - impl RpcClient where S: Service, diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index d5d8d67..857f59b 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -9,7 +9,7 @@ use futures_lite::{Stream, StreamExt}; use futures_util::SinkExt; use pin_project::pin_project; -use crate::{server::RpcChannel, RpcError, RpcMessage, Service}; +use crate::{RpcError, RpcMessage}; use super::{Connection, ConnectionCommon, ConnectionErrors}; @@ -204,20 +204,6 @@ where } } -/// Extension trait for mapping connections -pub trait ConnectionMapExt: Connection { - /// Map the input and output types of this connection - fn map(self) -> MappedConnection - where - In1: TryFrom, - Out: From, - { - MappedConnection::new(self) - } -} - -impl ConnectionMapExt for C {} - /// Connection types for a mapped connection pub struct MappedConnectionTypes(PhantomData<(In, Out, C)>); @@ -259,29 +245,6 @@ where type SendSink = MappedSendSink; } -impl RpcChannel -where - S: Service, - C: ConnectionCommon, -{ - /// Map the input and output types of this connection - pub fn map2(self) -> RpcChannel> - where - S1: Service, - S1::Req: TryFrom, - S::Res: From, - { - let send = MappedSendSink::::new(self.send); - let recv = MappedRecvStream::::new(self.recv); - let t: RpcChannel> = RpcChannel { - send, - recv, - _p: PhantomData, - }; - t - } -} - #[cfg(test)] #[cfg(feature = "flume-transport")] mod tests { @@ -353,7 +316,7 @@ mod tests { match msg { Request::A(_x) => todo!(), Request::B(x) => { - // map the channel to the sub-service + // but we can map the channel to the sub-service, once we know which one to use handle_sub_request(x, chan.map::().boxed()).await? } } diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 3b6aee7..277ffb7 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -19,6 +19,7 @@ //! Errors for both sides are defined by implementing the [`ConnectionErrors`] trait. use futures_lite::{Future, Stream}; use futures_sink::Sink; +use mapped::MappedConnection; use crate::{RpcError, RpcMessage}; use std::{ @@ -79,6 +80,15 @@ pub trait Connection: ConnectionCommon { fn open( &self, ) -> impl Future> + Send; + + /// Map the input and output types of this connection + fn map(self) -> MappedConnection + where + In1: TryFrom, + Self::Out: From, + { + MappedConnection::new(self) + } } /// A server endpoint that listens for connections From 13b7ef06852e351f1ff08830c0a9c4d86d2b7706 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 11:24:23 +0200 Subject: [PATCH 18/32] Add ServiceChannel trait alias --- src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 9c182c5..c4fa115 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,7 @@ #![deny(rustdoc::broken_intra_doc_links)] use serde::{de::DeserializeOwned, Serialize}; use std::fmt::{Debug, Display}; -use transport::{Connection, ServerEndpoint}; +use transport::{Connection, ConnectionCommon, ServerEndpoint}; pub mod client; pub mod message; pub mod server; @@ -177,3 +177,8 @@ impl, S: Service> ServiceConnection pub trait ServiceEndpoint: ServerEndpoint {} impl, S: Service> ServiceEndpoint for T {} + +/// A channel for a specific service +pub trait ServiceChannel: ConnectionCommon {} + +impl, S: Service> ServiceChannel for T {} From 7bad06c7243b53b7c612e95293c1fb2d5643f864 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 11:29:15 +0200 Subject: [PATCH 19/32] fix --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c4fa115..2ff5913 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -179,6 +179,6 @@ pub trait ServiceEndpoint: ServerEndpoint impl, S: Service> ServiceEndpoint for T {} /// A channel for a specific service -pub trait ServiceChannel: ConnectionCommon {} +pub trait ServiceChannel: ConnectionCommon {} -impl, S: Service> ServiceChannel for T {} +impl, S: Service> ServiceChannel for T {} From 03f97ab0bc5287f873970984d783320350ad3d8a Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 12:10:31 +0200 Subject: [PATCH 20/32] Provide utilities to transform RpcServerError As a complement to map() --- src/server.rs | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/server.rs b/src/server.rs index 1b99904..747b3ab 100644 --- a/src/server.rs +++ b/src/server.rs @@ -5,10 +5,10 @@ use crate::{ transport::{ self, boxed::BoxableServerEndpoint, - mapped::{MappedConnectionTypes, MappedRecvStream, MappedSendSink}, + mapped::{ErrorOrMapError, MappedConnectionTypes, MappedRecvStream, MappedSendSink}, ConnectionCommon, ConnectionErrors, }, - Service, ServiceEndpoint, + RpcMessage, Service, ServiceEndpoint, }; use futures_lite::{Future, Stream, StreamExt}; use futures_util::{SinkExt, TryStreamExt}; @@ -290,6 +290,45 @@ pub enum RpcServerError { UnexpectedUpdateMessage, } +impl + RpcServerError> +{ + /// For a mapped connection, map the error back to the original error type + pub fn map_back(self) -> RpcServerError { + match self { + RpcServerError::EarlyClose => RpcServerError::EarlyClose, + RpcServerError::UnexpectedStartMessage => RpcServerError::UnexpectedStartMessage, + RpcServerError::UnexpectedUpdateMessage => RpcServerError::UnexpectedUpdateMessage, + RpcServerError::SendError(x) => RpcServerError::SendError(x), + RpcServerError::Accept(x) => RpcServerError::Accept(x), + RpcServerError::RecvError(ErrorOrMapError::Inner(x)) => RpcServerError::RecvError(x), + RpcServerError::RecvError(ErrorOrMapError::Conversion) => { + RpcServerError::UnexpectedUpdateMessage + } + } + } +} + +impl RpcServerError { + /// Convert into a different error type provided the send, recv and accept errors can be converted + pub fn errors_into(self) -> RpcServerError + where + T: ConnectionErrors, + C::SendError: Into, + C::RecvError: Into, + C::AcceptError: Into, + { + match self { + RpcServerError::EarlyClose => RpcServerError::EarlyClose, + RpcServerError::UnexpectedStartMessage => RpcServerError::UnexpectedStartMessage, + RpcServerError::UnexpectedUpdateMessage => RpcServerError::UnexpectedUpdateMessage, + RpcServerError::SendError(x) => RpcServerError::SendError(x.into()), + RpcServerError::Accept(x) => RpcServerError::Accept(x.into()), + RpcServerError::RecvError(x) => RpcServerError::RecvError(x.into()), + } + } +} + impl fmt::Debug for RpcServerError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { From 2070d6595233c853fc4cff0ef1863508eaafebe6 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 13:57:37 +0200 Subject: [PATCH 21/32] rename all the things --- Cargo.toml | 2 +- examples/split/client/src/main.rs | 4 +- examples/split/server/src/main.rs | 4 +- examples/store.rs | 2 +- src/client.rs | 12 ++-- src/lib.rs | 16 ++--- src/pattern/bidi_streaming.rs | 6 +- src/pattern/client_streaming.rs | 4 +- src/pattern/rpc.rs | 4 +- src/pattern/server_streaming.rs | 8 +-- src/pattern/try_server_streaming.rs | 10 +-- src/server.rs | 20 +++--- src/transport/boxed.rs | 106 +++++++++++++--------------- src/transport/combined.rs | 52 ++++++-------- src/transport/flume.rs | 42 +++++------ src/transport/hyper.rs | 30 ++++---- src/transport/mapped.rs | 18 ++--- src/transport/misc/mod.rs | 14 ++-- src/transport/mod.rs | 29 ++++---- src/transport/quinn.rs | 42 +++++------ tests/hyper.rs | 14 ++-- tests/math.rs | 4 +- tests/quinn.rs | 12 ++-- tests/util.rs | 4 +- 24 files changed, 220 insertions(+), 239 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 48dd2f8..208dc6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ hyper-transport = ["dep:flume", "dep:hyper", "dep:bincode", "dep:bytes", "dep:to quinn-transport = ["dep:flume", "dep:quinn", "dep:bincode", "dep:tokio-serde", "dep:tokio-util"] flume-transport = ["dep:flume"] macros = [] -default = ["flume-transport", "quinn-transport"] +default = ["flume-transport", "quinn-transport", "hyper-transport"] [package.metadata.docs.rs] all-features = true diff --git a/examples/split/client/src/main.rs b/examples/split/client/src/main.rs index 1d4c5c9..f68406d 100644 --- a/examples/split/client/src/main.rs +++ b/examples/split/client/src/main.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use anyhow::Result; use futures::sink::SinkExt; use futures::stream::StreamExt; -use quic_rpc::transport::quinn::QuinnConnection; +use quic_rpc::transport::quinn::QuinnConnector; use quic_rpc::RpcClient; use quinn::crypto::rustls::QuicClientConfig; use quinn::{ClientConfig, Endpoint}; @@ -19,7 +19,7 @@ async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt::init(); let server_addr: SocketAddr = "127.0.0.1:12345".parse()?; let endpoint = make_insecure_client_endpoint("0.0.0.0:0".parse()?)?; - let client = QuinnConnection::new(endpoint, server_addr, "localhost".to_string()); + let client = QuinnConnector::new(endpoint, server_addr, "localhost".to_string()); let client = RpcClient::new(client); // let mut client = ComputeClient(client); diff --git a/examples/split/server/src/main.rs b/examples/split/server/src/main.rs index db46ec7..ec28ad0 100644 --- a/examples/split/server/src/main.rs +++ b/examples/split/server/src/main.rs @@ -1,7 +1,7 @@ use async_stream::stream; use futures::stream::{Stream, StreamExt}; use quic_rpc::server::run_server_loop; -use quic_rpc::transport::quinn::QuinnServerEndpoint; +use quic_rpc::transport::quinn::QuinnListener; use quinn::{Endpoint, ServerConfig}; use std::net::SocketAddr; use std::sync::Arc; @@ -62,7 +62,7 @@ async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt::init(); let server_addr: SocketAddr = "127.0.0.1:12345".parse()?; let (server, _server_certs) = make_server_endpoint(server_addr)?; - let channel = QuinnServerEndpoint::new(server)?; + let channel = QuinnListener::new(server)?; let target = Compute; run_server_loop( ComputeService, diff --git a/examples/store.rs b/examples/store.rs index 280ca87..23e53b4 100644 --- a/examples/store.rs +++ b/examples/store.rs @@ -5,7 +5,7 @@ use futures_lite::{Stream, StreamExt}; use futures_util::SinkExt; use quic_rpc::{ server::RpcServerError, - transport::{flume, Connection, ServerEndpoint}, + transport::{flume, Connector, Listener}, *, }; use serde::{Deserialize, Serialize}; diff --git a/src/client.rs b/src/client.rs index b2cc2f6..9205bdf 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,7 +2,7 @@ //! //! The main entry point is [RpcClient]. use crate::{ - transport::{boxed::BoxableConnection, mapped::MappedConnection, ConnectionCommon}, + transport::{boxed::BoxableConnector, mapped::MappedConnection, StreamTypes}, Service, ServiceConnection, }; use futures_lite::Stream; @@ -20,7 +20,7 @@ use std::{ /// /// This is a convenience type alias for a boxed connection to a specific service. pub type BoxedServiceConnection = - crate::transport::boxed::Connection<::Res, ::Req>; + crate::transport::boxed::Connector<::Res, ::Req>; /// Sync version of `future::stream::BoxStream`. pub type BoxStreamSync<'a, T> = Pin + Send + Sync + 'a>>; @@ -55,11 +55,11 @@ impl Clone for RpcClient { #[derive(Debug)] pub struct UpdateSink(#[pin] pub C::SendSink, PhantomData) where - C: ConnectionCommon; + C: StreamTypes; impl UpdateSink where - C: ConnectionCommon, + C: StreamTypes, T: Into, { /// Create a new update sink @@ -70,7 +70,7 @@ where impl Sink for UpdateSink where - C: ConnectionCommon, + C: StreamTypes, T: Into, { type Error = C::SendError; @@ -143,7 +143,7 @@ where /// box pub fn boxed(self) -> RpcClient> where - C: BoxableConnection, + C: BoxableConnector, { RpcClient::new(self.source.boxed()) } diff --git a/src/lib.rs b/src/lib.rs index 2ff5913..4eda0bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,7 @@ #![deny(rustdoc::broken_intra_doc_links)] use serde::{de::DeserializeOwned, Serialize}; use std::fmt::{Debug, Display}; -use transport::{Connection, ConnectionCommon, ServerEndpoint}; +use transport::{Connector, Listener, StreamTypes}; pub mod client; pub mod message; pub mod server; @@ -165,20 +165,20 @@ pub trait Service: Send + Sync + Debug + Clone + 'static { /// This is just a trait alias for a [Connection] with the right types. It is used /// to make it easier to specify the bounds of a connection that matches a specific /// service. -pub trait ServiceConnection: Connection {} +pub trait ServiceConnection: transport::Connector {} -impl, S: Service> ServiceConnection for T {} +impl, S: Service> ServiceConnection for T {} /// A server endpoint for a specific service /// -/// This is just a trait alias for a [ServerEndpoint] with the right types. It is used +/// This is just a trait alias for a [`transport::Listener`] with the right types. It is used /// to make it easier to specify the bounds of a server endpoint that matches a specific /// service. -pub trait ServiceEndpoint: ServerEndpoint {} +pub trait ServiceEndpoint: transport::Listener {} -impl, S: Service> ServiceEndpoint for T {} +impl, S: Service> ServiceEndpoint for T {} /// A channel for a specific service -pub trait ServiceChannel: ConnectionCommon {} +pub trait ServiceChannel: transport::StreamTypes {} -impl, S: Service> ServiceChannel for T {} +impl, S: Service> ServiceChannel for T {} diff --git a/src/pattern/bidi_streaming.rs b/src/pattern/bidi_streaming.rs index 7411130..53e6275 100644 --- a/src/pattern/bidi_streaming.rs +++ b/src/pattern/bidi_streaming.rs @@ -7,7 +7,7 @@ use crate::{ client::{BoxStreamSync, UpdateSink}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, - transport::{Connection, ConnectionCommon, ConnectionErrors}, + transport::{ConnectionErrors, Connector, StreamTypes}, RpcClient, Service, }; @@ -76,7 +76,7 @@ impl error::Error for ItemError {} impl RpcClient where S: Service, - C: Connection, + C: Connector, { /// Bidi call to the server, request opens a stream, response is a stream pub async fn bidi( @@ -106,7 +106,7 @@ where impl RpcChannel where - C: ConnectionCommon, + C: StreamTypes, S: Service, { /// handle the message M using the given function on the target object diff --git a/src/pattern/client_streaming.rs b/src/pattern/client_streaming.rs index 49549a3..1b8618b 100644 --- a/src/pattern/client_streaming.rs +++ b/src/pattern/client_streaming.rs @@ -7,7 +7,7 @@ use crate::{ client::UpdateSink, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, - transport::{ConnectionCommon, ConnectionErrors}, + transport::{ConnectionErrors, StreamTypes}, RpcClient, Service, ServiceConnection, }; @@ -114,7 +114,7 @@ where impl RpcChannel where S: Service, - C: ConnectionCommon, + C: StreamTypes, { /// handle the message M using the given function on the target object /// diff --git a/src/pattern/rpc.rs b/src/pattern/rpc.rs index ed2e708..70413f4 100644 --- a/src/pattern/rpc.rs +++ b/src/pattern/rpc.rs @@ -6,7 +6,7 @@ use futures_util::{FutureExt, SinkExt}; use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::{ConnectionCommon, ConnectionErrors}, + transport::{ConnectionErrors, StreamTypes}, RpcClient, Service, ServiceConnection, }; @@ -89,7 +89,7 @@ where impl RpcChannel where S: Service, - C: ConnectionCommon, + C: StreamTypes, { /// handle the message of type `M` using the given function on the target object /// diff --git a/src/pattern/server_streaming.rs b/src/pattern/server_streaming.rs index e288101..d7c983c 100644 --- a/src/pattern/server_streaming.rs +++ b/src/pattern/server_streaming.rs @@ -7,7 +7,7 @@ use crate::{ client::{BoxStreamSync, DeferDrop}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::{Connection, ConnectionCommon, ConnectionErrors}, + transport::{ConnectionErrors, Connector, StreamTypes}, RpcClient, Service, ServiceConnection, }; @@ -41,13 +41,13 @@ pub enum Error { Send(C::SendError), } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} /// Client error when handling responses from a server streaming request #[derive(Debug)] @@ -95,7 +95,7 @@ where impl RpcChannel where S: Service, - C: ConnectionCommon, + C: StreamTypes, { /// handle the message M using the given function on the target object /// diff --git a/src/pattern/try_server_streaming.rs b/src/pattern/try_server_streaming.rs index e57c85c..15e68fb 100644 --- a/src/pattern/try_server_streaming.rs +++ b/src/pattern/try_server_streaming.rs @@ -8,7 +8,7 @@ use crate::{ client::{BoxStreamSync, DeferDrop}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::{Connection, ConnectionCommon, ConnectionErrors}, + transport::{ConnectionErrors, Connector, StreamTypes}, RpcClient, Service, ServiceConnection, }; @@ -53,7 +53,7 @@ where /// care about the exact nature of the error, but if you want to handle /// application errors differently, you can match on this enum. #[derive(Debug)] -pub enum Error { +pub enum Error { /// Unable to open a substream at all Open(C::OpenError), /// Unable to send the request to the server @@ -68,13 +68,13 @@ pub enum Error { Application(E), } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} /// Client error when handling responses from a server streaming request. /// @@ -99,7 +99,7 @@ impl error::Error for ItemError {} impl RpcChannel where - C: ConnectionCommon, + C: StreamTypes, S: Service, { /// handle the message M using the given function on the target object diff --git a/src/server.rs b/src/server.rs index 747b3ab..28aa3b9 100644 --- a/src/server.rs +++ b/src/server.rs @@ -4,9 +4,9 @@ use crate::{ transport::{ self, - boxed::BoxableServerEndpoint, + boxed::BoxableListener, mapped::{ErrorOrMapError, MappedConnectionTypes, MappedRecvStream, MappedSendSink}, - ConnectionCommon, ConnectionErrors, + ConnectionErrors, StreamTypes, }, RpcMessage, Service, ServiceEndpoint, }; @@ -25,11 +25,11 @@ use tokio::sync::oneshot; /// Type alias for a boxed connection to a specific service pub type BoxedServiceChannel = - crate::transport::boxed::Connection<::Req, ::Res>; + crate::transport::boxed::Connector<::Req, ::Res>; /// Type alias for a service endpoint pub type BoxedServiceEndpoint = - crate::transport::boxed::ServerEndpoint<::Req, ::Res>; + crate::transport::boxed::Listener<::Req, ::Res>; /// A server for a specific service. /// @@ -76,7 +76,7 @@ impl> RpcServer { /// having to specify the type parameter. pub fn boxed(self) -> RpcServer> where - C: BoxableServerEndpoint, + C: BoxableListener, { RpcServer::new(self.source.boxed()) } @@ -97,7 +97,7 @@ impl> RpcServer { #[derive(Debug)] pub struct RpcChannel< S: Service, - C: ConnectionCommon = BoxedServiceChannel, + C: StreamTypes = BoxedServiceChannel, > { /// Sink to send responses to the client. pub send: C::SendSink, @@ -110,7 +110,7 @@ pub struct RpcChannel< impl RpcChannel where S: Service, - C: ConnectionCommon, + C: StreamTypes, { /// Create a new RPC channel. pub fn new(send: C::SendSink, recv: C::RecvStream) -> Self { @@ -222,11 +222,11 @@ pub struct UpdateStream( PhantomData, ) where - C: ConnectionCommon; + C: StreamTypes; impl UpdateStream where - C: ConnectionCommon, + C: StreamTypes, T: TryFrom, { pub(crate) fn new(recv: C::RecvStream) -> (Self, UnwrapToPending>) { @@ -238,7 +238,7 @@ where impl Stream for UpdateStream where - C: ConnectionCommon, + C: StreamTypes, T: TryFrom, { type Item = T; diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index 66af78d..df2421f 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -14,7 +14,7 @@ use std::future::Future; use crate::RpcMessage; -use super::{ConnectionCommon, ConnectionErrors}; +use super::{ConnectionErrors, StreamTypes}; type BoxedFuture<'a, T> = Pin + Send + Sync + 'a>>; enum SendSinkInner { @@ -216,67 +216,63 @@ impl<'a, In: RpcMessage, Out: RpcMessage> Future for AcceptFuture<'a, In, Out> { } /// A boxable connection -pub trait BoxableConnection: - Debug + Send + Sync + 'static -{ +pub trait BoxableConnector: Debug + Send + Sync + 'static { /// Clone the connection and box it - fn clone_box(&self) -> Box>; + fn clone_box(&self) -> Box>; /// Open a channel to the remote che fn open_boxed(&self) -> OpenFuture; /// Box the connection - fn boxed(self) -> self::Connection + fn boxed(self) -> self::Connector where Self: Sized + 'static, { - self::Connection::new(self) + self::Connector::new(self) } } /// A boxed connection #[derive(Debug)] -pub struct Connection(Box>); +pub struct Connector(Box>); -impl Connection { +impl Connector { /// Wrap a boxable server endpoint into a box, transforming all the types to concrete types - pub fn new(x: impl BoxableConnection) -> Self { + pub fn new(x: impl BoxableConnector) -> Self { Self(Box::new(x)) } } -impl Clone for Connection { +impl Clone for Connector { fn clone(&self) -> Self { Self(self.0.clone_box()) } } -impl ConnectionCommon for Connection { +impl StreamTypes for Connector { type In = In; type Out = Out; type RecvStream = RecvStream; type SendSink = SendSink; } -impl ConnectionErrors for Connection { +impl ConnectionErrors for Connector { type SendError = anyhow::Error; type RecvError = anyhow::Error; type OpenError = anyhow::Error; type AcceptError = anyhow::Error; } -impl super::Connection for Connection { +impl super::Connector for Connector { async fn open(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { self.0.open_boxed().await } } /// A boxable server endpoint -pub trait BoxableServerEndpoint: - Debug + Send + Sync + 'static -{ +pub trait BoxableListener: Debug + Send + Sync + 'static { /// Clone the server endpoint and box it - fn clone_box(&self) -> Box>; + fn clone_box(&self) -> Box>; /// Accept a channel from a remote client fn accept_bi_boxed(&self) -> AcceptFuture; @@ -285,46 +281,46 @@ pub trait BoxableServerEndpoint: fn local_addr(&self) -> &[super::LocalAddr]; /// Box the server endpoint - fn boxed(self) -> ServerEndpoint + fn boxed(self) -> Listener where Self: Sized + 'static, { - ServerEndpoint::new(self) + Listener::new(self) } } /// A boxed server endpoint #[derive(Debug)] -pub struct ServerEndpoint(Box>); +pub struct Listener(Box>); -impl ServerEndpoint { +impl Listener { /// Wrap a boxable server endpoint into a box, transforming all the types to concrete types - pub fn new(x: impl BoxableServerEndpoint) -> Self { + pub fn new(x: impl BoxableListener) -> Self { Self(Box::new(x)) } } -impl Clone for ServerEndpoint { +impl Clone for Listener { fn clone(&self) -> Self { Self(self.0.clone_box()) } } -impl ConnectionCommon for ServerEndpoint { +impl StreamTypes for Listener { type In = In; type Out = Out; type RecvStream = RecvStream; type SendSink = SendSink; } -impl ConnectionErrors for ServerEndpoint { +impl ConnectionErrors for Listener { type SendError = anyhow::Error; type RecvError = anyhow::Error; type OpenError = anyhow::Error; type AcceptError = anyhow::Error; } -impl super::ServerEndpoint for ServerEndpoint { +impl super::Listener for Listener { fn accept( &self, ) -> impl Future> + Send @@ -336,27 +332,27 @@ impl super::ServerEndpoint for ServerEndpoint BoxableConnection for Connection { - fn clone_box(&self) -> Box> { +impl BoxableConnector for Connector { + fn clone_box(&self) -> Box> { Box::new(self.clone()) } fn open_boxed(&self) -> OpenFuture { - OpenFuture::boxed(crate::transport::Connection::open(self)) + OpenFuture::boxed(crate::transport::Connector::open(self)) } } #[cfg(feature = "quinn-transport")] -impl BoxableConnection - for super::quinn::QuinnConnection +impl BoxableConnector + for super::quinn::QuinnConnector { - fn clone_box(&self) -> Box> { + fn clone_box(&self) -> Box> { Box::new(self.clone()) } fn open_boxed(&self) -> OpenFuture { let f = Box::pin(async move { - let (send, recv) = super::Connection::open(self).await?; + let (send, recv) = super::Connector::open(self).await?; // map the error types to anyhow let send = send.sink_map_err(anyhow::Error::from); let recv = recv.map_err(anyhow::Error::from); @@ -368,16 +364,16 @@ impl BoxableConnection } #[cfg(feature = "quinn-transport")] -impl BoxableServerEndpoint - for super::quinn::QuinnServerEndpoint +impl BoxableListener + for super::quinn::QuinnListener { - fn clone_box(&self) -> Box> { + fn clone_box(&self) -> Box> { Box::new(self.clone()) } fn accept_bi_boxed(&self) -> AcceptFuture { let f = async move { - let (send, recv) = super::ServerEndpoint::accept(self).await?; + let (send, recv) = super::Listener::accept(self).await?; let send = send.sink_map_err(anyhow::Error::from); let recv = recv.map_err(anyhow::Error::from); anyhow::Ok((SendSink::boxed(send), RecvStream::boxed(recv))) @@ -386,58 +382,58 @@ impl BoxableServerEndpoint } fn local_addr(&self) -> &[super::LocalAddr] { - super::ServerEndpoint::local_addr(self) + super::Listener::local_addr(self) } } #[cfg(feature = "flume-transport")] -impl BoxableConnection - for super::flume::FlumeConnection +impl BoxableConnector + for super::flume::FlumeConnector { - fn clone_box(&self) -> Box> { + fn clone_box(&self) -> Box> { Box::new(self.clone()) } fn open_boxed(&self) -> OpenFuture { - OpenFuture::direct(super::Connection::open(self)) + OpenFuture::direct(super::Connector::open(self)) } } #[cfg(feature = "flume-transport")] -impl BoxableServerEndpoint - for super::flume::FlumeServerEndpoint +impl BoxableListener + for super::flume::FlumeListener { - fn clone_box(&self) -> Box> { + fn clone_box(&self) -> Box> { Box::new(self.clone()) } fn accept_bi_boxed(&self) -> AcceptFuture { - AcceptFuture::direct(super::ServerEndpoint::accept(self)) + AcceptFuture::direct(super::Listener::accept(self)) } fn local_addr(&self) -> &[super::LocalAddr] { - super::ServerEndpoint::local_addr(self) + super::Listener::local_addr(self) } } -impl BoxableConnection for super::mapped::MappedConnection +impl BoxableConnector for super::mapped::MappedConnection where In: RpcMessage, Out: RpcMessage, - C: super::Connection, + C: super::Connector, C::Out: From, In: TryFrom, C::SendError: Into, C::RecvError: Into, C::OpenError: Into, { - fn clone_box(&self) -> Box> { + fn clone_box(&self) -> Box> { Box::new(self.clone()) } fn open_boxed(&self) -> OpenFuture { let f = Box::pin(async move { - let (send, recv) = super::Connection::open(self).await.map_err(|e| e.into())?; + let (send, recv) = super::Connector::open(self).await.map_err(|e| e.into())?; // map the error types to anyhow let send = send.sink_map_err(|e| e.into()); let recv = recv.map_err(|e| e.into()); @@ -466,11 +462,11 @@ mod tests { use futures_lite::StreamExt; use futures_util::SinkExt; - use crate::transport::{Connection, ServerEndpoint}; + use crate::transport::{Connector, Listener}; let (server, client) = crate::transport::flume::connection(1); - let server = super::ServerEndpoint::new(server); - let client = super::Connection::new(client); + let server = super::Listener::new(server); + let client = super::Connector::new(client); // spawn echo server tokio::spawn(async move { while let Ok((mut send, mut recv)) = server.accept().await { diff --git a/src/transport/combined.rs b/src/transport/combined.rs index 43742ba..21c4cc4 100644 --- a/src/transport/combined.rs +++ b/src/transport/combined.rs @@ -1,5 +1,5 @@ //! Transport that combines two other transports -use super::{Connection, ConnectionCommon, ConnectionErrors, LocalAddr, ServerEndpoint}; +use super::{ConnectionErrors, Connector, Listener, LocalAddr, StreamTypes}; use futures_lite::Stream; use futures_sink::Sink; use pin_project::pin_project; @@ -12,14 +12,14 @@ use std::{ /// A connection that combines two other connections #[derive(Debug, Clone)] -pub struct CombinedConnection { +pub struct CombinedConnector { /// First connection pub a: Option, /// Second connection pub b: Option, } -impl> CombinedConnection { +impl> CombinedConnector { /// Create a combined connection from two other connections /// /// It will always use the first connection that is not `None`. @@ -30,7 +30,7 @@ impl> CombinedConnection< /// An endpoint that combines two other endpoints #[derive(Debug, Clone)] -pub struct CombinedServerEndpoint { +pub struct CombinedListener { /// First endpoint pub a: Option, /// Second endpoint @@ -39,11 +39,11 @@ pub struct CombinedServerEndpoint { local_addr: Vec, } -impl> CombinedServerEndpoint { +impl> CombinedListener { /// Create a combined server endpoint from two other server endpoints /// /// When listening for incoming connections with - /// [crate::ServerEndpoint::accept], all configured channels will be listened on, + /// [crate::Listener::accept], all configured channels will be listened on, /// and the first to receive a connection will be used. If no channels are configured, /// accept_bi will not throw an error but wait forever. pub fn new(a: Option, b: Option) -> Self { @@ -65,16 +65,14 @@ impl> CombinedSer /// Send sink for combined channels #[pin_project(project = SendSinkProj)] -pub enum SendSink { +pub enum SendSink { /// A variant A(#[pin] A::SendSink), /// B variant B(#[pin] B::SendSink), } -impl> Sink - for SendSink -{ +impl> Sink for SendSink { type Error = self::SendError; fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { @@ -108,16 +106,14 @@ impl> Sink { +pub enum RecvStream { /// A variant A(#[pin] A::RecvStream), /// B variant B(#[pin] B::RecvStream), } -impl> Stream - for RecvStream -{ +impl> Stream for RecvStream { type Item = Result>; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { @@ -198,25 +194,21 @@ impl fmt::Display for AcceptError error::Error for AcceptError {} -impl ConnectionErrors for CombinedConnection { +impl ConnectionErrors for CombinedConnector { type SendError = self::SendError; type RecvError = self::RecvError; type OpenError = self::OpenError; type AcceptError = self::AcceptError; } -impl> ConnectionCommon - for CombinedConnection -{ +impl> StreamTypes for CombinedConnector { type In = A::In; type Out = A::Out; type RecvStream = self::RecvStream; type SendSink = self::SendSink; } -impl> Connection - for CombinedConnection -{ +impl> Connector for CombinedConnector { async fn open(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { let this = self.clone(); // try a first, then b @@ -232,25 +224,21 @@ impl> Connection } } -impl ConnectionErrors for CombinedServerEndpoint { +impl ConnectionErrors for CombinedListener { type SendError = self::SendError; type RecvError = self::RecvError; type OpenError = self::OpenError; type AcceptError = self::AcceptError; } -impl> ConnectionCommon - for CombinedServerEndpoint -{ +impl> StreamTypes for CombinedListener { type In = A::In; type Out = A::Out; type RecvStream = self::RecvStream; type SendSink = self::SendSink; } -impl> ServerEndpoint - for CombinedServerEndpoint -{ +impl> Listener for CombinedListener { async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::AcceptError> { let a_fut = async { if let Some(a) = &self.a { @@ -290,14 +278,14 @@ mod tests { combined::{self, OpenError}, flume, }, - Connection, + Connector, }; #[tokio::test] async fn open_empty_channel() { - let channel = combined::CombinedConnection::< - flume::FlumeConnection<(), ()>, - flume::FlumeConnection<(), ()>, + let channel = combined::CombinedConnector::< + flume::FlumeConnector<(), ()>, + flume::FlumeConnector<(), ()>, >::new(None, None); let res = channel.open().await; assert!(matches!(res, Err(OpenError::NoChannel))); diff --git a/src/transport/flume.rs b/src/transport/flume.rs index 9e5f736..49280f9 100644 --- a/src/transport/flume.rs +++ b/src/transport/flume.rs @@ -5,13 +5,13 @@ use futures_lite::{Future, Stream}; use futures_sink::Sink; use crate::{ - transport::{Connection, ConnectionErrors, LocalAddr, ServerEndpoint}, + transport::{ConnectionErrors, Connector, Listener, LocalAddr}, RpcMessage, }; use core::fmt; use std::{error, fmt::Display, marker::PhantomData, pin::Pin, result, task::Poll}; -use super::ConnectionCommon; +use super::StreamTypes; /// Error when receiving from a channel /// @@ -100,12 +100,12 @@ impl error::Error for RecvError {} /// A flume based server endpoint. /// /// Created using [connection]. -pub struct FlumeServerEndpoint { +pub struct FlumeListener { #[allow(clippy::type_complexity)] stream: flume::Receiver<(SendSink, RecvStream)>, } -impl Clone for FlumeServerEndpoint { +impl Clone for FlumeListener { fn clone(&self) -> Self { Self { stream: self.stream.clone(), @@ -113,15 +113,15 @@ impl Clone for FlumeServerEndpoint { } } -impl fmt::Debug for FlumeServerEndpoint { +impl fmt::Debug for FlumeListener { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FlumeServerEndpoint") + f.debug_struct("FlumeListener") .field("stream", &self.stream) .finish() } } -impl ConnectionErrors for FlumeServerEndpoint { +impl ConnectionErrors for FlumeListener { type SendError = self::SendError; type RecvError = self::RecvError; type OpenError = self::OpenError; @@ -130,7 +130,7 @@ impl ConnectionErrors for FlumeServerEndpoint = (self::SendSink, self::RecvStream); -/// Future returned by [FlumeConnection::open] +/// Future returned by [FlumeConnector::open] pub struct OpenFuture { inner: flume::r#async::SendFut<'static, Socket>, res: Option>, @@ -170,7 +170,7 @@ impl Future for OpenFuture { } } -/// Future returned by [FlumeServerEndpoint::accept] +/// Future returned by [FlumeListener::accept] pub struct AcceptFuture { wrapped: flume::r#async::RecvFut<'static, (SendSink, RecvStream)>, _p: PhantomData<(In, Out)>, @@ -194,14 +194,14 @@ impl Future for AcceptFuture { } } -impl ConnectionCommon for FlumeServerEndpoint { +impl StreamTypes for FlumeListener { type In = In; type Out = Out; type SendSink = SendSink; type RecvStream = RecvStream; } -impl ServerEndpoint for FlumeServerEndpoint { +impl Listener for FlumeListener { #[allow(refining_impl_trait)] fn accept(&self) -> AcceptFuture { AcceptFuture { @@ -215,21 +215,21 @@ impl ServerEndpoint for FlumeServerEndpoint ConnectionErrors for FlumeConnection { +impl ConnectionErrors for FlumeConnector { type SendError = self::SendError; type RecvError = self::RecvError; type OpenError = self::OpenError; type AcceptError = self::AcceptError; } -impl ConnectionCommon for FlumeConnection { +impl StreamTypes for FlumeConnector { type In = In; type Out = Out; type SendSink = SendSink; type RecvStream = RecvStream; } -impl Connection for FlumeConnection { +impl Connector for FlumeConnector { #[allow(refining_impl_trait)] fn open(&self) -> OpenFuture { let (local_send, remote_recv) = flume::bounded::(128); @@ -249,12 +249,12 @@ impl Connection for FlumeConnection { /// A flume based connection to a server endpoint. /// /// Created using [connection]. -pub struct FlumeConnection { +pub struct FlumeConnector { #[allow(clippy::type_complexity)] sink: flume::Sender<(SendSink, RecvStream)>, } -impl Clone for FlumeConnection { +impl Clone for FlumeConnector { fn clone(&self) -> Self { Self { sink: self.sink.clone(), @@ -262,7 +262,7 @@ impl Clone for FlumeConnection { } } -impl fmt::Debug for FlumeConnection { +impl fmt::Debug for FlumeConnector { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FlumeClientChannel") .field("sink", &self.sink) @@ -339,9 +339,9 @@ impl std::error::Error for CreateChannelError {} /// `buffer` the size of the buffer for each channel. Keep this at a low value to get backpressure pub fn connection( buffer: usize, -) -> (FlumeServerEndpoint, FlumeConnection) { +) -> (FlumeListener, FlumeConnector) { let (sink, stream) = flume::bounded(buffer); - (FlumeServerEndpoint { stream }, FlumeConnection { sink }) + (FlumeListener { stream }, FlumeConnector { sink }) } /// Create a flume server endpoint and a connected flume client channel for a specific service. @@ -349,8 +349,8 @@ pub fn connection( pub fn service_connection( buffer: usize, ) -> ( - FlumeServerEndpoint, - FlumeConnection, + FlumeListener, + FlumeConnector, ) { connection(buffer) } diff --git a/src/transport/hyper.rs b/src/transport/hyper.rs index b0bba7f..129eb9b 100644 --- a/src/transport/hyper.rs +++ b/src/transport/hyper.rs @@ -6,7 +6,7 @@ use std::{ sync::Arc, task::Poll, }; -use crate::transport::{Connection, ConnectionErrors, LocalAddr, ServerEndpoint}; +use crate::transport::{ConnectionErrors, Connector, Listener, LocalAddr, StreamTypes}; use crate::RpcMessage; use bytes::Bytes; use flume::{Receiver, Sender}; @@ -22,8 +22,6 @@ use tokio::sync::mpsc; use tokio::task::JoinHandle; use tracing::{debug, event, trace, Level}; -use super::ConnectionCommon; - struct HyperConnectionInner { client: Box, config: Arc, @@ -31,12 +29,12 @@ struct HyperConnectionInner { } /// Hyper based connection to a server -pub struct HyperConnection { +pub struct HyperConnector { inner: Arc, _p: PhantomData<(In, Out)>, } -impl Clone for HyperConnection { +impl Clone for HyperConnector { fn clone(&self) -> Self { Self { inner: self.inner.clone(), @@ -56,7 +54,7 @@ impl Requester for Client { } } -impl HyperConnection { +impl HyperConnector { /// create a client given an uri and the default configuration pub fn new(uri: Uri) -> Self { Self::with_config(uri, ChannelConfig::default()) @@ -93,7 +91,7 @@ impl HyperConnection { } } -impl fmt::Debug for HyperConnection { +impl fmt::Debug for HyperConnector { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ClientChannel") .field("uri", &self.inner.uri) @@ -173,7 +171,7 @@ impl Default for ChannelConfig { /// Creating this spawns a tokio task which runs the server, once dropped this task is shut /// down: no new connections will be accepted and existing channels will stop. #[derive(Debug)] -pub struct HyperServerEndpoint { +pub struct HyperListener { /// The channel. channel: Receiver>, /// The configuration. @@ -192,7 +190,7 @@ pub struct HyperServerEndpoint { _p: PhantomData<(In, Out)>, } -impl HyperServerEndpoint { +impl HyperListener { /// Creates a server listening on the [`SocketAddr`], with the default configuration. pub fn serve(addr: &SocketAddr) -> hyper::Result { Self::serve_with_config(addr, Default::default()) @@ -365,7 +363,7 @@ fn spawn_recv_forwarder( // This does not want or need RpcMessage to be clone but still want to clone the // ServerChannel and it's containing channels itself. The derive macro can't cope with this // so this needs to be written by hand. -impl Clone for HyperServerEndpoint { +impl Clone for HyperListener { fn clone(&self) -> Self { Self { channel: self.channel.clone(), @@ -574,7 +572,7 @@ impl fmt::Display for AcceptError { impl error::Error for AcceptError {} -impl ConnectionErrors for HyperConnection { +impl ConnectionErrors for HyperConnector { type SendError = self::SendError; type RecvError = self::RecvError; @@ -584,14 +582,14 @@ impl ConnectionErrors for HyperConnection ConnectionCommon for HyperConnection { +impl StreamTypes for HyperConnector { type In = In; type Out = Out; type RecvStream = self::RecvStream; type SendSink = self::SendSink; } -impl Connection for HyperConnection { +impl Connector for HyperConnector { async fn open(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { let (out_tx, out_rx) = flume::bounded::>(32); let req: Request = Request::post(&self.inner.uri) @@ -612,21 +610,21 @@ impl Connection for HyperConnection { } } -impl ConnectionErrors for HyperServerEndpoint { +impl ConnectionErrors for HyperListener { type SendError = self::SendError; type RecvError = self::RecvError; type OpenError = AcceptError; type AcceptError = AcceptError; } -impl ConnectionCommon for HyperServerEndpoint { +impl StreamTypes for HyperListener { type In = In; type Out = Out; type RecvStream = self::RecvStream; type SendSink = self::SendSink; } -impl ServerEndpoint for HyperServerEndpoint { +impl Listener for HyperListener { fn local_addr(&self) -> &[LocalAddr] { &self.local_addr } diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index 857f59b..6a6abc7 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -11,7 +11,7 @@ use pin_project::pin_project; use crate::{RpcError, RpcMessage}; -use super::{Connection, ConnectionCommon, ConnectionErrors}; +use super::{ConnectionErrors, Connector, StreamTypes}; /// A connection that maps input and output types #[derive(Debug)] @@ -22,7 +22,7 @@ pub struct MappedConnection { impl MappedConnection where - C: Connection, + C: Connector, In: TryFrom, C::Out: From, { @@ -59,9 +59,9 @@ where type AcceptError = C::AcceptError; } -impl ConnectionCommon for MappedConnection +impl StreamTypes for MappedConnection where - C: ConnectionCommon, + C: StreamTypes, In: RpcMessage, Out: RpcMessage, In: TryFrom, @@ -73,9 +73,9 @@ where type SendSink = MappedSendSink; } -impl Connection for MappedConnection +impl Connector for MappedConnection where - C: Connection, + C: Connector, In: RpcMessage, Out: RpcMessage, In: TryFrom, @@ -231,9 +231,9 @@ where type AcceptError = C::AcceptError; } -impl ConnectionCommon for MappedConnectionTypes +impl StreamTypes for MappedConnectionTypes where - C: ConnectionCommon, + C: StreamTypes, In: RpcMessage, Out: RpcMessage, In: TryFrom, @@ -251,7 +251,7 @@ mod tests { use crate::{ server::{BoxedServiceChannel, RpcChannel}, - transport::boxed::BoxableServerEndpoint, + transport::boxed::BoxableListener, RpcClient, RpcServer, }; use serde::{Deserialize, Serialize}; diff --git a/src/transport/misc/mod.rs b/src/transport/misc/mod.rs index 53ea72f..d934978 100644 --- a/src/transport/misc/mod.rs +++ b/src/transport/misc/mod.rs @@ -3,23 +3,23 @@ use futures_lite::stream; use futures_sink::Sink; use crate::{ - transport::{ConnectionErrors, ServerEndpoint}, + transport::{ConnectionErrors, Listener}, RpcMessage, }; use std::convert::Infallible; -use super::ConnectionCommon; +use super::StreamTypes; /// A dummy server endpoint that does nothing /// /// This can be useful as a default if you want to configure /// an optional server endpoint. #[derive(Debug, Default)] -pub struct DummyServerEndpoint { +pub struct DummyListener { _p: std::marker::PhantomData<(In, Out)>, } -impl Clone for DummyServerEndpoint { +impl Clone for DummyListener { fn clone(&self) -> Self { Self { _p: std::marker::PhantomData, @@ -27,21 +27,21 @@ impl Clone for DummyServerEndpoint { } } -impl ConnectionErrors for DummyServerEndpoint { +impl ConnectionErrors for DummyListener { type RecvError = Infallible; type SendError = Infallible; type OpenError = Infallible; type AcceptError = Infallible; } -impl ConnectionCommon for DummyServerEndpoint { +impl StreamTypes for DummyListener { type In = In; type Out = Out; type RecvStream = stream::Pending>; type SendSink = Box + Unpin + Send + Sync>; } -impl ServerEndpoint for DummyServerEndpoint { +impl Listener for DummyListener { async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::AcceptError> { futures_lite::future::pending().await } diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 277ffb7..218fd0d 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -8,10 +8,10 @@ //! //! In the transport module, the message types are referred to as `In` and `Out`. //! -//! A [`Connection`] can be used to *open* bidirectional typed channels using -//! [`Connection::open`]. A [`ServerEndpoint`] can be used to *accept* bidirectional +//! A [`Connector`] can be used to *open* bidirectional typed channels using +//! [`Connector::open`]. A [`Listener`] can be used to *accept* bidirectional //! typed channels from any of the currently opened connections to clients, using -//! [`ServerEndpoint::accept`]. +//! [`Listener::accept`]. //! //! In both cases, the result is a tuple of a send side and a receive side. These //! types are defined by implementing the [`ConnectionCommon`] trait. @@ -26,23 +26,22 @@ use std::{ fmt::{self, Debug, Display}, net::SocketAddr, }; + pub mod boxed; pub mod combined; #[cfg(feature = "flume-transport")] pub mod flume; #[cfg(feature = "hyper-transport")] pub mod hyper; +pub mod mapped; +pub mod misc; #[cfg(feature = "quinn-transport")] pub mod quinn; -pub mod misc; - #[cfg(any(feature = "quinn-transport", feature = "hyper-transport"))] mod util; -pub mod mapped; - -/// Errors that can happen when creating and using a [`Connection`] or [`ServerEndpoint`]. +/// Errors that can happen when creating and using a [`Connector`] or [`Listener`]. pub trait ConnectionErrors: Debug + Clone + Send + Sync + 'static { /// Error when sending a message via a channel type SendError: RpcError; @@ -54,10 +53,10 @@ pub trait ConnectionErrors: Debug + Clone + Send + Sync + 'static { type AcceptError: RpcError; } -/// Types that are common to both [`Connection`] and [`ServerEndpoint`]. +/// Types that are common to both [`Connector`] and [`Listener`]. /// /// Having this as a separate trait is useful when writing generic code that works with both. -pub trait ConnectionCommon: ConnectionErrors { +pub trait StreamTypes: ConnectionErrors { /// The type of messages that can be received on the channel type In: RpcMessage; /// The type of messages that can be sent on the channel @@ -75,7 +74,7 @@ pub trait ConnectionCommon: ConnectionErrors { /// A connection to a specific remote machine /// /// A connection can be used to open bidirectional typed channels using [`Connection::open`]. -pub trait Connection: ConnectionCommon { +pub trait Connector: StreamTypes { /// Open a channel to the remote che fn open( &self, @@ -94,8 +93,8 @@ pub trait Connection: ConnectionCommon { /// A server endpoint that listens for connections /// /// A server endpoint can be used to accept bidirectional typed channels from any of the -/// currently opened connections to clients, using [`ServerEndpoint::accept`]. -pub trait ServerEndpoint: ConnectionCommon { +/// currently opened connections to clients, using [`Listener::accept`]. +pub trait Listener: StreamTypes { /// Accept a new typed bidirectional channel on any of the connections we /// have currently opened. fn accept( @@ -106,9 +105,9 @@ pub trait ServerEndpoint: ConnectionCommon { fn local_addr(&self) -> &[LocalAddr]; } -/// The kinds of local addresses a [ServerEndpoint] can be bound to. +/// The kinds of local addresses a [Listener] can be bound to. /// -/// Returned by [ServerEndpoint::local_addr]. +/// Returned by [Listener::local_addr]. /// /// [`Display`]: fmt::Display #[derive(Debug, Clone)] diff --git a/src/transport/quinn.rs b/src/transport/quinn.rs index 261f5a7..64b9f49 100644 --- a/src/transport/quinn.rs +++ b/src/transport/quinn.rs @@ -1,6 +1,6 @@ //! QUIC transport implementation based on [quinn](https://crates.io/crates/quinn) use crate::{ - transport::{Connection, ConnectionErrors, LocalAddr, ServerEndpoint}, + transport::{ConnectionErrors, Connector, Listener, LocalAddr}, RpcMessage, }; use futures_lite::{Future, Stream, StreamExt}; @@ -18,20 +18,20 @@ use tracing::{debug_span, Instrument}; use super::{ util::{FramedBincodeRead, FramedBincodeWrite}, - ConnectionCommon, + StreamTypes, }; const MAX_FRAME_LENGTH: usize = 1024 * 1024 * 16; #[derive(Debug)] -struct ServerEndpointInner { +struct ListenerInner { endpoint: Option, task: Option>, local_addr: [LocalAddr; 1], receiver: flume::Receiver, } -impl Drop for ServerEndpointInner { +impl Drop for ListenerInner { fn drop(&mut self) { tracing::debug!("Dropping server endpoint"); if let Some(endpoint) = self.endpoint.take() { @@ -56,12 +56,12 @@ impl Drop for ServerEndpointInner { /// A server endpoint using a quinn connection #[derive(Debug)] -pub struct QuinnServerEndpoint { - inner: Arc, +pub struct QuinnListener { + inner: Arc, _p: PhantomData<(In, Out)>, } -impl QuinnServerEndpoint { +impl QuinnListener { /// handles RPC requests from a connection /// /// to cleanly shutdown the handler, drop the receiver side of the sender. @@ -122,7 +122,7 @@ impl QuinnServerEndpoint { let (sender, receiver) = flume::bounded(16); let task = tokio::spawn(Self::endpoint_handler(endpoint.clone(), sender)); Ok(Self { - inner: Arc::new(ServerEndpointInner { + inner: Arc::new(ListenerInner { endpoint: Some(endpoint), task: Some(task), local_addr: [LocalAddr::Socket(local_addr)], @@ -148,7 +148,7 @@ impl QuinnServerEndpoint { } }); Self { - inner: Arc::new(ServerEndpointInner { + inner: Arc::new(ListenerInner { endpoint: None, task: Some(task), local_addr: [LocalAddr::Socket(local_addr)], @@ -167,7 +167,7 @@ impl QuinnServerEndpoint { local_addr: SocketAddr, ) -> Self { Self { - inner: Arc::new(ServerEndpointInner { + inner: Arc::new(ListenerInner { endpoint: None, task: None, local_addr: [LocalAddr::Socket(local_addr)], @@ -178,7 +178,7 @@ impl QuinnServerEndpoint { } } -impl Clone for QuinnServerEndpoint { +impl Clone for QuinnListener { fn clone(&self) -> Self { Self { inner: self.inner.clone(), @@ -187,21 +187,21 @@ impl Clone for QuinnServerEndpoint { } } -impl ConnectionErrors for QuinnServerEndpoint { +impl ConnectionErrors for QuinnListener { type SendError = io::Error; type RecvError = io::Error; type OpenError = quinn::ConnectionError; type AcceptError = quinn::ConnectionError; } -impl ConnectionCommon for QuinnServerEndpoint { +impl StreamTypes for QuinnListener { type In = In; type Out = Out; type SendSink = self::SendSink; type RecvStream = self::RecvStream; } -impl ServerEndpoint for QuinnServerEndpoint { +impl Listener for QuinnListener { async fn accept(&self) -> Result<(Self::SendSink, Self::RecvStream), AcceptError> { let (send, recv) = self .inner @@ -255,12 +255,12 @@ impl Drop for ClientConnectionInner { } /// A connection using a quinn connection -pub struct QuinnConnection { +pub struct QuinnConnector { inner: Arc, _p: PhantomData<(In, Out)>, } -impl QuinnConnection { +impl QuinnConnector { async fn single_connection_handler_inner( connection: quinn::Connection, requests: flume::Receiver>>, @@ -602,7 +602,7 @@ impl<'a, T> Stream for Receiver<'a, T> { } } -impl fmt::Debug for QuinnConnection { +impl fmt::Debug for QuinnConnector { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ClientChannel") .field("inner", &self.inner) @@ -610,7 +610,7 @@ impl fmt::Debug for QuinnConnection { } } -impl Clone for QuinnConnection { +impl Clone for QuinnConnector { fn clone(&self) -> Self { Self { inner: self.inner.clone(), @@ -619,21 +619,21 @@ impl Clone for QuinnConnection { } } -impl ConnectionErrors for QuinnConnection { +impl ConnectionErrors for QuinnConnector { type SendError = io::Error; type RecvError = io::Error; type OpenError = quinn::ConnectionError; type AcceptError = quinn::ConnectionError; } -impl ConnectionCommon for QuinnConnection { +impl StreamTypes for QuinnConnector { type In = In; type Out = Out; type SendSink = self::SendSink; type RecvStream = self::RecvStream; } -impl Connection for QuinnConnection { +impl Connector for QuinnConnector { async fn open(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { let (sender, receiver) = oneshot::channel(); self.inner diff --git a/tests/hyper.rs b/tests/hyper.rs index d085e97..0e5766d 100644 --- a/tests/hyper.rs +++ b/tests/hyper.rs @@ -7,7 +7,7 @@ use flume::Receiver; use quic_rpc::{ declare_rpc, server::RpcServerError, - transport::hyper::{self, HyperConnection, HyperServerEndpoint, RecvError}, + transport::hyper::{self, HyperConnector, HyperListener, RecvError}, RpcClient, RpcServer, Service, }; use serde::{Deserialize, Serialize}; @@ -18,7 +18,7 @@ use math::*; mod util; fn run_server(addr: &SocketAddr) -> JoinHandle> { - let channel = HyperServerEndpoint::serve(addr).unwrap(); + let channel = HyperListener::serve(addr).unwrap(); let server = RpcServer::new(channel); tokio::spawn(async move { loop { @@ -38,7 +38,7 @@ enum TestResponse { NoDeser(NoDeser), } -type SC = HyperServerEndpoint; +type SC = HyperListener; /// request that can be too big #[derive(Debug, Serialize, Deserialize)] @@ -134,7 +134,7 @@ async fn hyper_channel_bench() -> anyhow::Result<()> { let addr: SocketAddr = "127.0.0.1:3000".parse()?; let uri: Uri = "http://127.0.0.1:3000".parse()?; let server_handle = run_server(&addr); - let client = HyperConnection::new(uri); + let client = HyperConnector::new(uri); let client = RpcClient::new(client); bench(client, 50000).await?; println!("terminating server"); @@ -148,7 +148,7 @@ async fn hyper_channel_smoke() -> anyhow::Result<()> { let addr: SocketAddr = "127.0.0.1:3001".parse()?; let uri: Uri = "http://127.0.0.1:3001".parse()?; let server_handle = run_server(&addr); - let client = HyperConnection::new(uri); + let client = HyperConnector::new(uri); smoke_test(client).await?; server_handle.abort(); let _ = server_handle.await; @@ -171,7 +171,7 @@ async fn hyper_channel_errors() -> anyhow::Result<()> { JoinHandle>, Receiver>>, ) { - let channel = HyperServerEndpoint::serve(addr).unwrap(); + let channel = HyperListener::serve(addr).unwrap(); let server = RpcServer::new(channel); let (res_tx, res_rx) = flume::unbounded(); let handle = tokio::spawn(async move { @@ -214,7 +214,7 @@ async fn hyper_channel_errors() -> anyhow::Result<()> { let addr: SocketAddr = "127.0.0.1:3002".parse()?; let uri: Uri = "http://127.0.0.1:3002".parse()?; let (server_handle, server_results) = run_test_server(&addr); - let client = HyperConnection::new(uri); + let client = HyperConnector::new(uri); let client = RpcClient::new(client); macro_rules! assert_matches { diff --git a/tests/math.rs b/tests/math.rs index f1f890e..eefb8b5 100644 --- a/tests/math.rs +++ b/tests/math.rs @@ -15,7 +15,7 @@ use quic_rpc::{ ServerStreaming, ServerStreamingMsg, }, server::{RpcChannel, RpcServerError}, - transport::ConnectionCommon, + transport::StreamTypes, RpcClient, RpcServer, Service, ServiceConnection, ServiceEndpoint, }; use serde::{Deserialize, Serialize}; @@ -179,7 +179,7 @@ impl ComputeService { chan: RpcChannel, ) -> Result<(), RpcServerError> where - E: ConnectionCommon, + E: StreamTypes, { use ComputeRequest::*; #[rustfmt::skip] diff --git a/tests/quinn.rs b/tests/quinn.rs index b28c6da..be445b7 100644 --- a/tests/quinn.rs +++ b/tests/quinn.rs @@ -114,7 +114,7 @@ pub fn make_endpoints(port: u16) -> anyhow::Result { fn run_server(server: quinn::Endpoint) -> JoinHandle> { tokio::task::spawn(async move { - let connection = transport::quinn::QuinnServerEndpoint::new(server)?; + let connection = transport::quinn::QuinnListener::new(server)?; let server = RpcServer::new(connection); ComputeService::server(server).await?; anyhow::Ok(()) @@ -133,7 +133,7 @@ async fn quinn_channel_bench() -> anyhow::Result<()> { tracing::debug!("Starting server"); let server_handle = run_server(server); tracing::debug!("Starting client"); - let client = transport::quinn::QuinnConnection::new(client, server_addr, "localhost".into()); + let client = transport::quinn::QuinnConnector::new(client, server_addr, "localhost".into()); let client = RpcClient::new(client); tracing::debug!("Starting benchmark"); bench(client, 50000).await?; @@ -151,7 +151,7 @@ async fn quinn_channel_smoke() -> anyhow::Result<()> { } = make_endpoints(12346)?; let server_handle = run_server(server); let client_connection = - transport::quinn::QuinnConnection::new(client, server_addr, "localhost".into()); + transport::quinn::QuinnConnector::new(client, server_addr, "localhost".into()); smoke_test(client_connection).await?; server_handle.abort(); Ok(()) @@ -172,7 +172,7 @@ async fn server_away_and_back() -> anyhow::Result<()> { // create the RPC client let client = make_client_endpoint("0.0.0.0:0".parse()?, &[&server_cert])?; let client_connection = - transport::quinn::QuinnConnection::new(client, server_addr, "localhost".into()); + transport::quinn::QuinnConnector::new(client, server_addr, "localhost".into()); let client = RpcClient::new(client_connection); // send a request. No server available so it should fail @@ -180,7 +180,7 @@ async fn server_away_and_back() -> anyhow::Result<()> { // create the RPC Server let server = Endpoint::server(server_config.clone(), server_addr)?; - let connection = transport::quinn::QuinnServerEndpoint::new(server)?; + let connection = transport::quinn::QuinnListener::new(server)?; let server = RpcServer::new(connection); let server_handle = tokio::task::spawn(ComputeService::server_bounded(server, 1)); @@ -195,7 +195,7 @@ async fn server_away_and_back() -> anyhow::Result<()> { // make the server run again let server = Endpoint::server(server_config, server_addr)?; - let connection = transport::quinn::QuinnServerEndpoint::new(server)?; + let connection = transport::quinn::QuinnListener::new(server)?; let server = RpcServer::new(connection); let server_handle = tokio::task::spawn(ComputeService::server_bounded(server, 5)); diff --git a/tests/util.rs b/tests/util.rs index 47c560a..cd946e4 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -1,8 +1,8 @@ use anyhow::Context; -use quic_rpc::{server::RpcServerError, transport::Connection}; +use quic_rpc::{server::RpcServerError, transport::Connector}; #[allow(unused)] -pub async fn check_termination_anyhow( +pub async fn check_termination_anyhow( server_handle: tokio::task::JoinHandle>, ) -> anyhow::Result<()> { // dropping the client will cause the server to terminate From 1396e92fd7d8086cbd90525107d3f6ef75105e89 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 14:20:05 +0200 Subject: [PATCH 22/32] complete renaming --- examples/modularize.rs | 14 ++++---- examples/store.rs | 5 +-- src/client.rs | 26 +++++++-------- src/lib.rs | 23 ++++++------- src/macros.rs | 6 ++-- src/pattern/client_streaming.rs | 4 +-- src/pattern/rpc.rs | 4 +-- src/pattern/server_streaming.rs | 4 +-- src/pattern/try_server_streaming.rs | 12 +++---- src/server.rs | 43 +++++++++++------------- src/transport/boxed.rs | 52 ++++++++++++++--------------- src/transport/combined.rs | 15 ++++----- src/transport/flume.rs | 8 ++--- src/transport/hyper.rs | 2 +- src/transport/mapped.rs | 28 ++++++++-------- src/transport/misc/mod.rs | 4 +-- src/transport/mod.rs | 14 ++++---- src/transport/quinn.rs | 8 ++--- tests/math.rs | 12 +++---- tests/slow_math.rs | 4 +-- 20 files changed, 140 insertions(+), 148 deletions(-) diff --git a/examples/modularize.rs b/examples/modularize.rs index 2e0719c..db1ec54 100644 --- a/examples/modularize.rs +++ b/examples/modularize.rs @@ -10,9 +10,7 @@ use anyhow::Result; use futures_lite::StreamExt; use futures_util::SinkExt; -use quic_rpc::{ - client::BoxedServiceConnection, transport::flume, RpcClient, RpcServer, ServiceEndpoint, -}; +use quic_rpc::{client::BoxedConnector, transport::flume, Listener, RpcClient, RpcServer}; use tracing::warn; use app::AppService; @@ -28,12 +26,12 @@ async fn main() -> Result<()> { tokio::task::spawn(run_server(server_conn, handler)); // run a client demo - client_demo(BoxedServiceConnection::::new(client_conn)).await?; + client_demo(BoxedConnector::::new(client_conn)).await?; Ok(()) } -async fn run_server>(server_conn: C, handler: app::Handler) { +async fn run_server>(server_conn: C, handler: app::Handler) { let server = RpcServer::::new(server_conn); loop { let Ok(accepting) = server.accept().await else { @@ -52,7 +50,7 @@ async fn run_server>(server_conn: C, handler: app } } } -pub async fn client_demo(conn: BoxedServiceConnection) -> Result<()> { +pub async fn client_demo(conn: BoxedConnector) -> Result<()> { let rpc_client = RpcClient::::new(conn); let client = app::Client::new(rpc_client.clone()); @@ -104,7 +102,7 @@ mod app { use super::iroh; use anyhow::Result; use derive_more::{From, TryInto}; - use quic_rpc::{message::RpcMsg, server::RpcChannel, RpcClient, Service, ServiceEndpoint}; + use quic_rpc::{message::RpcMsg, server::RpcChannel, Listener, RpcClient, Service}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, From, TryInto)] @@ -152,7 +150,7 @@ mod app { } impl Handler { - pub async fn handle_rpc_request>( + pub async fn handle_rpc_request>( self, req: Request, chan: RpcChannel, diff --git a/examples/store.rs b/examples/store.rs index 23e53b4..3df9617 100644 --- a/examples/store.rs +++ b/examples/store.rs @@ -5,7 +5,7 @@ use futures_lite::{Stream, StreamExt}; use futures_util::SinkExt; use quic_rpc::{ server::RpcServerError, - transport::{flume, Connector, Listener}, + transport::{flume, Connector}, *, }; use serde::{Deserialize, Serialize}; @@ -162,7 +162,7 @@ impl Store { #[tokio::main] async fn main() -> anyhow::Result<()> { - async fn server_future>( + async fn server_future>( server: RpcServer, ) -> result::Result<(), RpcServerError> { let s = server; @@ -231,6 +231,7 @@ async fn main() -> anyhow::Result<()> { } async fn _main_unsugared() -> anyhow::Result<()> { + use transport::Listener; #[derive(Clone, Debug)] struct Service; impl crate::Service for Service { diff --git a/src/client.rs b/src/client.rs index 9205bdf..a88da1f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,8 +2,8 @@ //! //! The main entry point is [RpcClient]. use crate::{ - transport::{boxed::BoxableConnector, mapped::MappedConnection, StreamTypes}, - Service, ServiceConnection, + transport::{boxed::BoxableConnector, mapped::MappedConnector, StreamTypes}, + Connector, Service, }; use futures_lite::Stream; use futures_sink::Sink; @@ -19,23 +19,23 @@ use std::{ /// Type alias for a boxed connection to a specific service /// /// This is a convenience type alias for a boxed connection to a specific service. -pub type BoxedServiceConnection = - crate::transport::boxed::Connector<::Res, ::Req>; +pub type BoxedConnector = + crate::transport::boxed::BoxedConnector<::Res, ::Req>; /// Sync version of `future::stream::BoxStream`. pub type BoxStreamSync<'a, T> = Pin + Send + Sync + 'a>>; /// A client for a specific service /// -/// This is a wrapper around a [ServiceConnection] that serves as the entry point +/// This is a wrapper around a [`Connector`] that serves as the entry point /// for the client DSL. /// /// Type parameters: /// /// `S` is the service type that determines what interactions this client supports. -/// `C` is the substream source. +/// `C` is the connector that determines the transport. #[derive(Debug)] -pub struct RpcClient> { +pub struct RpcClient> { pub(crate) source: C, pub(crate) _p: PhantomData, } @@ -96,10 +96,10 @@ where impl RpcClient where S: Service, - C: ServiceConnection, + C: Connector, { /// Create a new rpc client for a specific [Service] given a compatible - /// [ServiceConnection]. + /// [Connector]. /// /// This is where a generic typed connection is converted into a client for a specific service. /// @@ -115,7 +115,7 @@ where impl RpcClient where S: Service, - C: ServiceConnection, + C: Connector, { /// Get the underlying connection pub fn into_inner(self) -> C { @@ -131,7 +131,7 @@ where /// Where SNext is the new service to map to and S is the current inner service. /// /// This method can be chained infintely. - pub fn map(self) -> RpcClient> + pub fn map(self) -> RpcClient> where SNext: Service, S::Req: From, @@ -141,7 +141,7 @@ where } /// box - pub fn boxed(self) -> RpcClient> + pub fn boxed(self) -> RpcClient> where C: BoxableConnector, { @@ -152,7 +152,7 @@ where impl AsRef for RpcClient where S: Service, - C: ServiceConnection, + C: Connector, { fn as_ref(&self) -> &C { &self.source diff --git a/src/lib.rs b/src/lib.rs index 4eda0bf..75341da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,6 @@ #![deny(rustdoc::broken_intra_doc_links)] use serde::{de::DeserializeOwned, Serialize}; use std::fmt::{Debug, Display}; -use transport::{Connector, Listener, StreamTypes}; pub mod client; pub mod message; pub mod server; @@ -160,25 +159,25 @@ pub trait Service: Send + Sync + Debug + Clone + 'static { type Res: RpcMessage; } -/// A connection to a specific service on a specific remote machine +/// A connector to a specific service /// -/// This is just a trait alias for a [Connection] with the right types. It is used -/// to make it easier to specify the bounds of a connection that matches a specific +/// This is just a trait alias for a [`transport::Connector`] with the right types. It is used +/// to make it easier to specify the bounds of a connector that matches a specific /// service. -pub trait ServiceConnection: transport::Connector {} +pub trait Connector: transport::Connector {} -impl, S: Service> ServiceConnection for T {} +impl, S: Service> Connector for T {} -/// A server endpoint for a specific service +/// A listener for a specific service /// /// This is just a trait alias for a [`transport::Listener`] with the right types. It is used -/// to make it easier to specify the bounds of a server endpoint that matches a specific +/// to make it easier to specify the bounds of a listener that matches a specific /// service. -pub trait ServiceEndpoint: transport::Listener {} +pub trait Listener: transport::Listener {} -impl, S: Service> ServiceEndpoint for T {} +impl, S: Service> Listener for T {} /// A channel for a specific service -pub trait ServiceChannel: transport::StreamTypes {} +pub trait ServerStreamTypes: transport::StreamTypes {} -impl, S: Service> ServiceChannel for T {} +impl, S: Service> ServerStreamTypes for T {} diff --git a/src/macros.rs b/src/macros.rs index 650e406..03cf475 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -198,7 +198,7 @@ macro_rules! __derive_create_dispatch { #[macro_export] macro_rules! $create_dispatch { ($target:ident, $handler:ident) => { - pub async fn $handler>( + pub async fn $handler>( mut chan: $crate::server::RpcChannel<$service, C>, msg: <$service as $crate::Service>::Req, target: $target, @@ -435,9 +435,9 @@ macro_rules! __derive_create_client{ macro_rules! $create_client { ($struct:ident) => { #[derive(::std::clone::Clone, ::std::fmt::Debug)] - pub struct $struct>(pub $crate::client::RpcClient<$service, C>); + pub struct $struct>(pub $crate::client::RpcClient<$service, C>); - impl> $struct { + impl> $struct { $( $crate::__rpc_method!($m_pattern, $service, $m_name, $m_input, $m_output, $m_update); )* diff --git a/src/pattern/client_streaming.rs b/src/pattern/client_streaming.rs index 1b8618b..729b8c7 100644 --- a/src/pattern/client_streaming.rs +++ b/src/pattern/client_streaming.rs @@ -8,7 +8,7 @@ use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError, UpdateStream}, transport::{ConnectionErrors, StreamTypes}, - RpcClient, Service, ServiceConnection, + Connector, RpcClient, Service, }; use std::{ @@ -78,7 +78,7 @@ impl error::Error for ItemError {} impl RpcClient where S: Service, - C: ServiceConnection, + C: Connector, { /// Call to the server that allows the client to stream, single response pub async fn client_streaming( diff --git a/src/pattern/rpc.rs b/src/pattern/rpc.rs index 70413f4..9337113 100644 --- a/src/pattern/rpc.rs +++ b/src/pattern/rpc.rs @@ -7,7 +7,7 @@ use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, transport::{ConnectionErrors, StreamTypes}, - RpcClient, Service, ServiceConnection, + Connector, RpcClient, Service, }; use std::{ @@ -65,7 +65,7 @@ impl error::Error for Error {} impl RpcClient where S: Service, - C: ServiceConnection, + C: Connector, { /// RPC call to the server, single request, single response pub async fn rpc(&self, msg: M) -> result::Result> diff --git a/src/pattern/server_streaming.rs b/src/pattern/server_streaming.rs index d7c983c..d1889e4 100644 --- a/src/pattern/server_streaming.rs +++ b/src/pattern/server_streaming.rs @@ -8,7 +8,7 @@ use crate::{ message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, transport::{ConnectionErrors, Connector, StreamTypes}, - RpcClient, Service, ServiceConnection, + RpcClient, Service, }; use std::{ @@ -68,7 +68,7 @@ impl error::Error for ItemError {} impl RpcClient where - C: ServiceConnection, + C: crate::Connector, S: Service, { /// Bidi call to the server, request opens a stream, response is a stream diff --git a/src/pattern/try_server_streaming.rs b/src/pattern/try_server_streaming.rs index 15e68fb..46d705d 100644 --- a/src/pattern/try_server_streaming.rs +++ b/src/pattern/try_server_streaming.rs @@ -8,8 +8,8 @@ use crate::{ client::{BoxStreamSync, DeferDrop}, message::{InteractionPattern, Msg}, server::{race2, RpcChannel, RpcServerError}, - transport::{ConnectionErrors, Connector, StreamTypes}, - RpcClient, Service, ServiceConnection, + transport::{self, ConnectionErrors, StreamTypes}, + Connector, RpcClient, Service, }; use std::{ @@ -53,7 +53,7 @@ where /// care about the exact nature of the error, but if you want to handle /// application errors differently, you can match on this enum. #[derive(Debug)] -pub enum Error { +pub enum Error { /// Unable to open a substream at all Open(C::OpenError), /// Unable to send the request to the server @@ -68,13 +68,13 @@ pub enum Error { Application(E), } -impl fmt::Display for Error { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } } -impl error::Error for Error {} +impl error::Error for Error {} /// Client error when handling responses from a server streaming request. /// @@ -170,7 +170,7 @@ where impl RpcClient where - C: ServiceConnection, + C: Connector, S: Service, { /// Bidi call to the server, request opens a stream, response is a stream diff --git a/src/server.rs b/src/server.rs index 28aa3b9..e638098 100644 --- a/src/server.rs +++ b/src/server.rs @@ -5,10 +5,10 @@ use crate::{ transport::{ self, boxed::BoxableListener, - mapped::{ErrorOrMapError, MappedConnectionTypes, MappedRecvStream, MappedSendSink}, + mapped::{ErrorOrMapError, MappedRecvStream, MappedSendSink, MappedStreamTypes}, ConnectionErrors, StreamTypes, }, - RpcMessage, Service, ServiceEndpoint, + Listener, RpcMessage, Service, }; use futures_lite::{Future, Stream, StreamExt}; use futures_util::{SinkExt, TryStreamExt}; @@ -24,23 +24,23 @@ use std::{ use tokio::sync::oneshot; /// Type alias for a boxed connection to a specific service -pub type BoxedServiceChannel = - crate::transport::boxed::Connector<::Req, ::Res>; +pub type BoxedConnector = + crate::transport::boxed::BoxedConnector<::Req, ::Res>; /// Type alias for a service endpoint -pub type BoxedServiceEndpoint = - crate::transport::boxed::Listener<::Req, ::Res>; +pub type BoxedListener = + crate::transport::boxed::BoxedListener<::Req, ::Res>; /// A server for a specific service. /// -/// This is a wrapper around a [ServiceEndpoint] that serves as the entry point for the server DSL. +/// This is a wrapper around a [`Listener`] that serves as the entry point for the server DSL. /// /// Type parameters: /// /// `S` is the service type. /// `C` is the channel type. #[derive(Debug)] -pub struct RpcServer> { +pub struct RpcServer> { /// The channel on which new requests arrive. /// /// Each new request is a receiver and channel pair on which messages for this request @@ -58,9 +58,9 @@ impl Clone for RpcServer { } } -impl> RpcServer { +impl> RpcServer { /// Create a new rpc server for a specific service for a [Service] given a compatible - /// [ServiceEndpoint]. + /// [Listener]. /// /// This is where a generic typed endpoint is converted into a server for a specific service. pub fn new(source: C) -> Self { @@ -74,7 +74,7 @@ impl> RpcServer { /// /// The boxed transport is the default for the `C` type parameter, so by boxing we can avoid /// having to specify the type parameter. - pub fn boxed(self) -> RpcServer> + pub fn boxed(self) -> RpcServer> where C: BoxableListener, { @@ -95,10 +95,7 @@ impl> RpcServer { /// `S` is the service type. /// `C` is the service endpoint from which the channel was created. #[derive(Debug)] -pub struct RpcChannel< - S: Service, - C: StreamTypes = BoxedServiceChannel, -> { +pub struct RpcChannel = BoxedConnector> { /// Sink to send responses to the client. pub send: C::SendSink, /// Stream to receive requests from the client. @@ -122,7 +119,7 @@ where } /// Convert this channel into a boxed channel. - pub fn boxed(self) -> RpcChannel> + pub fn boxed(self) -> RpcChannel> where C::SendError: Into + Send + Sync + 'static, C::RecvError: Into + Send + Sync + 'static, @@ -142,7 +139,7 @@ where /// Where SNext is the new service to map to and S is the current inner service. /// /// This method can be chained infintely. - pub fn map(self) -> RpcChannel> + pub fn map(self) -> RpcChannel> where SNext: Service, SNext::Req: TryFrom, @@ -156,13 +153,13 @@ where } /// The result of accepting a new connection. -pub struct Accepting> { +pub struct Accepting> { send: C::SendSink, recv: C::RecvStream, _p: PhantomData, } -impl> Accepting { +impl> Accepting { /// Read the first message from the client. /// /// The return value is a tuple of `(request, channel)`. Here `request` is the @@ -186,7 +183,7 @@ impl> Accepting { } } -impl> RpcServer { +impl> RpcServer { /// Accepts a new channel from a client. The result is an [Accepting] object that /// can be used to read the first request. pub async fn accept(&self) -> result::Result, RpcServerError> { @@ -204,7 +201,7 @@ impl> RpcServer { } } -impl> AsRef for RpcServer { +impl> AsRef for RpcServer { fn as_ref(&self) -> &C { &self.source } @@ -291,7 +288,7 @@ pub enum RpcServerError { } impl - RpcServerError> + RpcServerError> { /// For a mapped connection, map the error back to the original error type pub fn map_back(self) -> RpcServerError { @@ -383,7 +380,7 @@ pub async fn run_server_loop( ) -> Result<(), RpcServerError> where S: Service, - C: ServiceEndpoint, + C: Listener, T: Clone + Send + 'static, F: FnMut(RpcChannel, S::Req, T) -> Fut + Send + 'static, Fut: Future>> + Send + 'static, diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index df2421f..43b9e5e 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -224,54 +224,54 @@ pub trait BoxableConnector: Debug + Send + Sync fn open_boxed(&self) -> OpenFuture; /// Box the connection - fn boxed(self) -> self::Connector + fn boxed(self) -> self::BoxedConnector where Self: Sized + 'static, { - self::Connector::new(self) + self::BoxedConnector::new(self) } } /// A boxed connection #[derive(Debug)] -pub struct Connector(Box>); +pub struct BoxedConnector(Box>); -impl Connector { - /// Wrap a boxable server endpoint into a box, transforming all the types to concrete types +impl BoxedConnector { + /// Wrap a boxable connector into a box, transforming all the types to concrete types pub fn new(x: impl BoxableConnector) -> Self { Self(Box::new(x)) } } -impl Clone for Connector { +impl Clone for BoxedConnector { fn clone(&self) -> Self { Self(self.0.clone_box()) } } -impl StreamTypes for Connector { +impl StreamTypes for BoxedConnector { type In = In; type Out = Out; type RecvStream = RecvStream; type SendSink = SendSink; } -impl ConnectionErrors for Connector { +impl ConnectionErrors for BoxedConnector { type SendError = anyhow::Error; type RecvError = anyhow::Error; type OpenError = anyhow::Error; type AcceptError = anyhow::Error; } -impl super::Connector for Connector { +impl super::Connector for BoxedConnector { async fn open(&self) -> Result<(Self::SendSink, Self::RecvStream), Self::OpenError> { self.0.open_boxed().await } } -/// A boxable server endpoint +/// A boxable listener pub trait BoxableListener: Debug + Send + Sync + 'static { - /// Clone the server endpoint and box it + /// Clone the listener and box it fn clone_box(&self) -> Box>; /// Accept a channel from a remote client @@ -280,47 +280,47 @@ pub trait BoxableListener: Debug + Send + Sync /// Get the local address fn local_addr(&self) -> &[super::LocalAddr]; - /// Box the server endpoint - fn boxed(self) -> Listener + /// Box the listener + fn boxed(self) -> BoxedListener where Self: Sized + 'static, { - Listener::new(self) + BoxedListener::new(self) } } -/// A boxed server endpoint +/// A boxed listener #[derive(Debug)] -pub struct Listener(Box>); +pub struct BoxedListener(Box>); -impl Listener { - /// Wrap a boxable server endpoint into a box, transforming all the types to concrete types +impl BoxedListener { + /// Wrap a boxable listener into a box, transforming all the types to concrete types pub fn new(x: impl BoxableListener) -> Self { Self(Box::new(x)) } } -impl Clone for Listener { +impl Clone for BoxedListener { fn clone(&self) -> Self { Self(self.0.clone_box()) } } -impl StreamTypes for Listener { +impl StreamTypes for BoxedListener { type In = In; type Out = Out; type RecvStream = RecvStream; type SendSink = SendSink; } -impl ConnectionErrors for Listener { +impl ConnectionErrors for BoxedListener { type SendError = anyhow::Error; type RecvError = anyhow::Error; type OpenError = anyhow::Error; type AcceptError = anyhow::Error; } -impl super::Listener for Listener { +impl super::Listener for BoxedListener { fn accept( &self, ) -> impl Future> + Send @@ -332,7 +332,7 @@ impl super::Listener for Listener { self.0.local_addr() } } -impl BoxableConnector for Connector { +impl BoxableConnector for BoxedConnector { fn clone_box(&self) -> Box> { Box::new(self.clone()) } @@ -416,7 +416,7 @@ impl BoxableListener } } -impl BoxableConnector for super::mapped::MappedConnection +impl BoxableConnector for super::mapped::MappedConnector where In: RpcMessage, Out: RpcMessage, @@ -465,8 +465,8 @@ mod tests { use crate::transport::{Connector, Listener}; let (server, client) = crate::transport::flume::connection(1); - let server = super::Listener::new(server); - let client = super::Connector::new(client); + let server = super::BoxedListener::new(server); + let client = super::BoxedConnector::new(client); // spawn echo server tokio::spawn(async move { while let Ok((mut send, mut recv)) = server.accept().await { diff --git a/src/transport/combined.rs b/src/transport/combined.rs index 21c4cc4..1829a3f 100644 --- a/src/transport/combined.rs +++ b/src/transport/combined.rs @@ -40,12 +40,12 @@ pub struct CombinedListener { } impl> CombinedListener { - /// Create a combined server endpoint from two other server endpoints + /// Create a combined listener from two other listeners /// /// When listening for incoming connections with - /// [crate::Listener::accept], all configured channels will be listened on, + /// [`Listener::accept`], all configured channels will be listened on, /// and the first to receive a connection will be used. If no channels are configured, - /// accept_bi will not throw an error but wait forever. + /// accept will not throw an error but just wait forever. pub fn new(a: Option, b: Option) -> Self { let mut local_addr = Vec::with_capacity(2); if let Some(a) = &a { @@ -273,12 +273,9 @@ impl> Listener for CombinedLi #[cfg(test)] #[cfg(feature = "flume-transport")] mod tests { - use crate::{ - transport::{ - combined::{self, OpenError}, - flume, - }, - Connector, + use crate::transport::{ + combined::{self, OpenError}, + flume, Connector, }; #[tokio::test] diff --git a/src/transport/flume.rs b/src/transport/flume.rs index 49280f9..a18aaf4 100644 --- a/src/transport/flume.rs +++ b/src/transport/flume.rs @@ -97,7 +97,7 @@ impl Stream for RecvStream { impl error::Error for RecvError {} -/// A flume based server endpoint. +/// A flume based listener. /// /// Created using [connection]. pub struct FlumeListener { @@ -246,7 +246,7 @@ impl Connector for FlumeConnector { } } -/// A flume based connection to a server endpoint. +/// A flume based connector. /// /// Created using [connection]. pub struct FlumeConnector { @@ -334,7 +334,7 @@ impl Display for CreateChannelError { impl std::error::Error for CreateChannelError {} -/// Create a flume server endpoint and a connected flume client channel. +/// Create a flume listener and a connected flume connector. /// /// `buffer` the size of the buffer for each channel. Keep this at a low value to get backpressure pub fn connection( @@ -344,7 +344,7 @@ pub fn connection( (FlumeListener { stream }, FlumeConnector { sink }) } -/// Create a flume server endpoint and a connected flume client channel for a specific service. +/// Create a flume listener and a connected flume connector for a specific service. #[allow(clippy::type_complexity)] pub fn service_connection( buffer: usize, diff --git a/src/transport/hyper.rs b/src/transport/hyper.rs index 129eb9b..131c576 100644 --- a/src/transport/hyper.rs +++ b/src/transport/hyper.rs @@ -162,7 +162,7 @@ impl Default for ChannelConfig { } } -/// A server endpoint using a hyper server +/// A listener using a hyper server /// /// Each request made by the any client connection this channel will yield a `(recv, send)` /// pair which allows receiving the request and sending the response. Both these are diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index 6a6abc7..bc607e1 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -15,12 +15,12 @@ use super::{ConnectionErrors, Connector, StreamTypes}; /// A connection that maps input and output types #[derive(Debug)] -pub struct MappedConnection { +pub struct MappedConnector { inner: C, _p: std::marker::PhantomData<(In, Out)>, } -impl MappedConnection +impl MappedConnector where C: Connector, In: TryFrom, @@ -35,7 +35,7 @@ where } } -impl Clone for MappedConnection +impl Clone for MappedConnector where C: Clone, { @@ -47,7 +47,7 @@ where } } -impl ConnectionErrors for MappedConnection +impl ConnectionErrors for MappedConnector where In: RpcMessage, Out: RpcMessage, @@ -59,7 +59,7 @@ where type AcceptError = C::AcceptError; } -impl StreamTypes for MappedConnection +impl StreamTypes for MappedConnector where C: StreamTypes, In: RpcMessage, @@ -73,7 +73,7 @@ where type SendSink = MappedSendSink; } -impl Connector for MappedConnection +impl Connector for MappedConnector where C: Connector, In: RpcMessage, @@ -205,21 +205,21 @@ where } /// Connection types for a mapped connection -pub struct MappedConnectionTypes(PhantomData<(In, Out, C)>); +pub struct MappedStreamTypes(PhantomData<(In, Out, C)>); -impl Debug for MappedConnectionTypes { +impl Debug for MappedStreamTypes { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MappedConnectionTypes").finish() } } -impl Clone for MappedConnectionTypes { +impl Clone for MappedStreamTypes { fn clone(&self) -> Self { Self(PhantomData) } } -impl ConnectionErrors for MappedConnectionTypes +impl ConnectionErrors for MappedStreamTypes where In: RpcMessage, Out: RpcMessage, @@ -231,7 +231,7 @@ where type AcceptError = C::AcceptError; } -impl StreamTypes for MappedConnectionTypes +impl StreamTypes for MappedStreamTypes where C: StreamTypes, In: RpcMessage, @@ -250,7 +250,7 @@ where mod tests { use crate::{ - server::{BoxedServiceChannel, RpcChannel}, + server::{BoxedConnector, RpcChannel}, transport::boxed::BoxableListener, RpcClient, RpcServer, }; @@ -292,11 +292,11 @@ mod tests { async fn smoke() -> TestResult<()> { async fn handle_sub_request( _req: String, - _chan: RpcChannel>, + _chan: RpcChannel>, ) -> anyhow::Result<()> { Ok(()) } - // create a server endpoint / connection pair. Type will be inferred + // create a listener / connector pair. Type will be inferred let (s, c) = crate::transport::flume::connection(32); // wrap the server in a RpcServer, this is where the service type is specified let server = RpcServer::::new(s.clone()); diff --git a/src/transport/misc/mod.rs b/src/transport/misc/mod.rs index d934978..756d6c3 100644 --- a/src/transport/misc/mod.rs +++ b/src/transport/misc/mod.rs @@ -10,10 +10,10 @@ use std::convert::Infallible; use super::StreamTypes; -/// A dummy server endpoint that does nothing +/// A dummy listener that does nothing /// /// This can be useful as a default if you want to configure -/// an optional server endpoint. +/// an optional listener. #[derive(Debug, Default)] pub struct DummyListener { _p: std::marker::PhantomData<(In, Out)>, diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 218fd0d..5df0939 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -14,12 +14,12 @@ //! [`Listener::accept`]. //! //! In both cases, the result is a tuple of a send side and a receive side. These -//! types are defined by implementing the [`ConnectionCommon`] trait. +//! types are defined by implementing the [`StreamTypes`] trait. //! //! Errors for both sides are defined by implementing the [`ConnectionErrors`] trait. use futures_lite::{Future, Stream}; use futures_sink::Sink; -use mapped::MappedConnection; +use mapped::MappedConnector; use crate::{RpcError, RpcMessage}; use std::{ @@ -73,7 +73,7 @@ pub trait StreamTypes: ConnectionErrors { /// A connection to a specific remote machine /// -/// A connection can be used to open bidirectional typed channels using [`Connection::open`]. +/// A connection can be used to open bidirectional typed channels using [`Connector::open`]. pub trait Connector: StreamTypes { /// Open a channel to the remote che fn open( @@ -81,18 +81,18 @@ pub trait Connector: StreamTypes { ) -> impl Future> + Send; /// Map the input and output types of this connection - fn map(self) -> MappedConnection + fn map(self) -> MappedConnector where In1: TryFrom, Self::Out: From, { - MappedConnection::new(self) + MappedConnector::new(self) } } -/// A server endpoint that listens for connections +/// A listener that listens for connections /// -/// A server endpoint can be used to accept bidirectional typed channels from any of the +/// A listener can be used to accept bidirectional typed channels from any of the /// currently opened connections to clients, using [`Listener::accept`]. pub trait Listener: StreamTypes { /// Accept a new typed bidirectional channel on any of the connections we diff --git a/src/transport/quinn.rs b/src/transport/quinn.rs index 64b9f49..db5c3bb 100644 --- a/src/transport/quinn.rs +++ b/src/transport/quinn.rs @@ -33,13 +33,13 @@ struct ListenerInner { impl Drop for ListenerInner { fn drop(&mut self) { - tracing::debug!("Dropping server endpoint"); + tracing::debug!("Dropping listener"); if let Some(endpoint) = self.endpoint.take() { - endpoint.close(0u32.into(), b"server endpoint dropped"); + endpoint.close(0u32.into(), b"Listener dropped"); if let Ok(handle) = tokio::runtime::Handle::try_current() { // spawn a task to wait for the endpoint to notify peers that it is closing - let span = debug_span!("closing server endpoint"); + let span = debug_span!("closing listener"); handle.spawn( async move { endpoint.wait_idle().await; @@ -54,7 +54,7 @@ impl Drop for ListenerInner { } } -/// A server endpoint using a quinn connection +/// A listener using a quinn connection #[derive(Debug)] pub struct QuinnListener { inner: Arc, diff --git a/tests/math.rs b/tests/math.rs index eefb8b5..af224fe 100644 --- a/tests/math.rs +++ b/tests/math.rs @@ -16,7 +16,7 @@ use quic_rpc::{ }, server::{RpcChannel, RpcServerError}, transport::StreamTypes, - RpcClient, RpcServer, Service, ServiceConnection, ServiceEndpoint, + Connector, Listener, RpcClient, RpcServer, Service, }; use serde::{Deserialize, Serialize}; use std::{ @@ -161,7 +161,7 @@ impl ComputeService { } } - pub async fn server>( + pub async fn server>( server: RpcServer, ) -> result::Result<(), RpcServerError> { let s = server; @@ -195,7 +195,7 @@ impl ComputeService { } /// Runs the service until `count` requests have been received. - pub async fn server_bounded>( + pub async fn server_bounded>( server: RpcServer, count: usize, ) -> result::Result, RpcServerError> { @@ -226,7 +226,7 @@ impl ComputeService { Ok(s) } - pub async fn server_par>( + pub async fn server_par>( server: RpcServer, parallelism: usize, ) -> result::Result<(), RpcServerError> { @@ -267,7 +267,7 @@ impl ComputeService { } } -pub async fn smoke_test>(client: C) -> anyhow::Result<()> { +pub async fn smoke_test>(client: C) -> anyhow::Result<()> { let client = RpcClient::::new(client); // a rpc call tracing::debug!("calling rpc S(1234)"); @@ -319,7 +319,7 @@ fn clear_line() { pub async fn bench(client: RpcClient, n: u64) -> anyhow::Result<()> where C::SendError: std::error::Error, - C: ServiceConnection, + C: Connector, { // individual RPCs { diff --git a/tests/slow_math.rs b/tests/slow_math.rs index c453c68..858614a 100644 --- a/tests/slow_math.rs +++ b/tests/slow_math.rs @@ -15,7 +15,7 @@ use quic_rpc::{ ServerStreaming, ServerStreamingMsg, }, server::RpcServerError, - RpcServer, Service, ServiceEndpoint, + Listener, RpcServer, Service, }; #[derive(Debug, Clone)] @@ -107,7 +107,7 @@ impl ComputeService { } } - pub async fn server>( + pub async fn server>( server: RpcServer, ) -> result::Result<(), RpcServerError> { let s = server; From e42000af87a98769af1015bd41b776adfdf09ffa Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 14:46:10 +0200 Subject: [PATCH 23/32] Add BoxedConnectionTypes --- src/server.rs | 13 +++++++++---- src/transport/boxed.rs | 28 ++++++++++++++++++++++++++++ src/transport/mapped.rs | 4 ++-- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/server.rs b/src/server.rs index e638098..b71a60a 100644 --- a/src/server.rs +++ b/src/server.rs @@ -24,8 +24,10 @@ use std::{ use tokio::sync::oneshot; /// Type alias for a boxed connection to a specific service -pub type BoxedConnector = - crate::transport::boxed::BoxedConnector<::Req, ::Res>; +pub type BoxedServerStreamTypes = crate::transport::boxed::BoxedStreamTypes< + ::Req, + ::Res, +>; /// Type alias for a service endpoint pub type BoxedListener = @@ -95,7 +97,10 @@ impl> RpcServer { /// `S` is the service type. /// `C` is the service endpoint from which the channel was created. #[derive(Debug)] -pub struct RpcChannel = BoxedConnector> { +pub struct RpcChannel< + S: Service, + C: StreamTypes = BoxedServerStreamTypes, +> { /// Sink to send responses to the client. pub send: C::SendSink, /// Stream to receive requests from the client. @@ -119,7 +124,7 @@ where } /// Convert this channel into a boxed channel. - pub fn boxed(self) -> RpcChannel> + pub fn boxed(self) -> RpcChannel> where C::SendError: Into + Send + Sync + 'static, C::RecvError: Into + Send + Sync + 'static, diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index 43b9e5e..ee6fe61 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -269,6 +269,34 @@ impl super::Connector for BoxedConnector { + _p: std::marker::PhantomData<(In, Out)>, +} + +impl Clone for BoxedStreamTypes { + fn clone(&self) -> Self { + Self { + _p: std::marker::PhantomData, + } + } +} + +impl ConnectionErrors for BoxedStreamTypes { + type SendError = anyhow::Error; + type RecvError = anyhow::Error; + type OpenError = anyhow::Error; + type AcceptError = anyhow::Error; +} + +impl StreamTypes for BoxedStreamTypes { + type In = In; + type Out = Out; + type RecvStream = RecvStream; + type SendSink = SendSink; +} + /// A boxable listener pub trait BoxableListener: Debug + Send + Sync + 'static { /// Clone the listener and box it diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index bc607e1..e1981c5 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -250,7 +250,7 @@ where mod tests { use crate::{ - server::{BoxedConnector, RpcChannel}, + server::{BoxedServerStreamTypes, RpcChannel}, transport::boxed::BoxableListener, RpcClient, RpcServer, }; @@ -292,7 +292,7 @@ mod tests { async fn smoke() -> TestResult<()> { async fn handle_sub_request( _req: String, - _chan: RpcChannel>, + _chan: RpcChannel>, ) -> anyhow::Result<()> { Ok(()) } From b0fe95360b42682cd286e86f0c5ac8f3ca402b1c Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 14:48:48 +0200 Subject: [PATCH 24/32] Add docs for ServerStreamTypes --- src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 75341da..2c9b4e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -177,7 +177,10 @@ pub trait Listener: transport::Listener { impl, S: Service> Listener for T {} -/// A channel for a specific service +/// Stream types on the server side +/// +/// On the server side, we receive requests and send responses. +/// On the client side, we send requests and receive responses. pub trait ServerStreamTypes: transport::StreamTypes {} impl, S: Service> ServerStreamTypes for T {} From ccbc078bf93f3e92e197210b1fd1032ad8363d1a Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 14:51:30 +0200 Subject: [PATCH 25/32] Rename ServerStreamTypes to ListnerTypes --- src/lib.rs | 4 ++-- src/server.rs | 10 ++++------ src/transport/mapped.rs | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2c9b4e7..0d86116 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -181,6 +181,6 @@ impl, S: Service> Listener /// /// On the server side, we receive requests and send responses. /// On the client side, we send requests and receive responses. -pub trait ServerStreamTypes: transport::StreamTypes {} +pub trait ListenerTypes: transport::StreamTypes {} -impl, S: Service> ServerStreamTypes for T {} +impl, S: Service> ListenerTypes for T {} diff --git a/src/server.rs b/src/server.rs index b71a60a..50f5947 100644 --- a/src/server.rs +++ b/src/server.rs @@ -24,7 +24,7 @@ use std::{ use tokio::sync::oneshot; /// Type alias for a boxed connection to a specific service -pub type BoxedServerStreamTypes = crate::transport::boxed::BoxedStreamTypes< +pub type BoxedListenerTypes = crate::transport::boxed::BoxedStreamTypes< ::Req, ::Res, >; @@ -97,10 +97,8 @@ impl> RpcServer { /// `S` is the service type. /// `C` is the service endpoint from which the channel was created. #[derive(Debug)] -pub struct RpcChannel< - S: Service, - C: StreamTypes = BoxedServerStreamTypes, -> { +pub struct RpcChannel = BoxedListenerTypes> +{ /// Sink to send responses to the client. pub send: C::SendSink, /// Stream to receive requests from the client. @@ -124,7 +122,7 @@ where } /// Convert this channel into a boxed channel. - pub fn boxed(self) -> RpcChannel> + pub fn boxed(self) -> RpcChannel> where C::SendError: Into + Send + Sync + 'static, C::RecvError: Into + Send + Sync + 'static, diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index e1981c5..ade1df1 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -250,7 +250,7 @@ where mod tests { use crate::{ - server::{BoxedServerStreamTypes, RpcChannel}, + server::{BoxedListenerTypes, RpcChannel}, transport::boxed::BoxableListener, RpcClient, RpcServer, }; @@ -292,7 +292,7 @@ mod tests { async fn smoke() -> TestResult<()> { async fn handle_sub_request( _req: String, - _chan: RpcChannel>, + _chan: RpcChannel>, ) -> anyhow::Result<()> { Ok(()) } From 067ae4b04bad16036571225904cd6970decb040b Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 15:24:11 +0200 Subject: [PATCH 26/32] Make boxed first class --- src/transport/boxed.rs | 20 ++------------------ src/transport/mapped.rs | 2 +- src/transport/mod.rs | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index ee6fe61..94e9f74 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -215,24 +215,16 @@ impl<'a, In: RpcMessage, Out: RpcMessage> Future for AcceptFuture<'a, In, Out> { } } -/// A boxable connection +/// A boxable connector pub trait BoxableConnector: Debug + Send + Sync + 'static { /// Clone the connection and box it fn clone_box(&self) -> Box>; /// Open a channel to the remote che fn open_boxed(&self) -> OpenFuture; - - /// Box the connection - fn boxed(self) -> self::BoxedConnector - where - Self: Sized + 'static, - { - self::BoxedConnector::new(self) - } } -/// A boxed connection +/// A boxed connector #[derive(Debug)] pub struct BoxedConnector(Box>); @@ -307,14 +299,6 @@ pub trait BoxableListener: Debug + Send + Sync /// Get the local address fn local_addr(&self) -> &[super::LocalAddr]; - - /// Box the listener - fn boxed(self) -> BoxedListener - where - Self: Sized + 'static, - { - BoxedListener::new(self) - } } /// A boxed listener diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index ade1df1..ce1ff49 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -251,7 +251,7 @@ mod tests { use crate::{ server::{BoxedListenerTypes, RpcChannel}, - transport::boxed::BoxableListener, + transport::Listener, RpcClient, RpcServer, }; use serde::{Deserialize, Serialize}; diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 5df0939..75adc56 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -17,6 +17,7 @@ //! types are defined by implementing the [`StreamTypes`] trait. //! //! Errors for both sides are defined by implementing the [`ConnectionErrors`] trait. +use boxed::{BoxableConnector, BoxableListener, BoxedConnector, BoxedListener}; use futures_lite::{Future, Stream}; use futures_sink::Sink; use mapped::MappedConnector; @@ -88,6 +89,14 @@ pub trait Connector: StreamTypes { { MappedConnector::new(self) } + + /// Box the connection + fn boxed(self) -> BoxedConnector + where + Self: BoxableConnector + Sized + 'static, + { + self::BoxedConnector::new(self) + } } /// A listener that listens for connections @@ -103,6 +112,14 @@ pub trait Listener: StreamTypes { /// The local addresses this endpoint is bound to. fn local_addr(&self) -> &[LocalAddr]; + + /// Box the listener + fn boxed(self) -> BoxedListener + where + Self: BoxableListener + Sized + 'static, + { + BoxedListener::new(self) + } } /// The kinds of local addresses a [Listener] can be bound to. From d9637d1982e90c1ee6fb65a62f354fb319ebfb37 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 15:47:06 +0200 Subject: [PATCH 27/32] Rename ListenerTypes to ChannelTypes and move it into server --- src/lib.rs | 8 -------- src/server.rs | 17 ++++++++++++----- src/transport/mapped.rs | 4 ++-- src/transport/mod.rs | 2 +- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0d86116..a29bedc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -176,11 +176,3 @@ impl, S: Service> Connector: transport::Listener {} impl, S: Service> Listener for T {} - -/// Stream types on the server side -/// -/// On the server side, we receive requests and send responses. -/// On the client side, we send requests and receive responses. -pub trait ListenerTypes: transport::StreamTypes {} - -impl, S: Service> ListenerTypes for T {} diff --git a/src/server.rs b/src/server.rs index 50f5947..1d35425 100644 --- a/src/server.rs +++ b/src/server.rs @@ -23,8 +23,16 @@ use std::{ }; use tokio::sync::oneshot; -/// Type alias for a boxed connection to a specific service -pub type BoxedListenerTypes = crate::transport::boxed::BoxedStreamTypes< +/// Stream types on the server side +/// +/// On the server side, we receive requests and send responses. +/// On the client side, we send requests and receive responses. +pub trait ChannelTypes: transport::StreamTypes {} + +impl, S: Service> ChannelTypes for T {} + +/// Type alias for when you want to require a boxed channel +pub type BoxedChannelTypes = crate::transport::boxed::BoxedStreamTypes< ::Req, ::Res, >; @@ -97,8 +105,7 @@ impl> RpcServer { /// `S` is the service type. /// `C` is the service endpoint from which the channel was created. #[derive(Debug)] -pub struct RpcChannel = BoxedListenerTypes> -{ +pub struct RpcChannel = BoxedChannelTypes> { /// Sink to send responses to the client. pub send: C::SendSink, /// Stream to receive requests from the client. @@ -122,7 +129,7 @@ where } /// Convert this channel into a boxed channel. - pub fn boxed(self) -> RpcChannel> + pub fn boxed(self) -> RpcChannel> where C::SendError: Into + Send + Sync + 'static, C::RecvError: Into + Send + Sync + 'static, diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index ce1ff49..0029552 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -250,7 +250,7 @@ where mod tests { use crate::{ - server::{BoxedListenerTypes, RpcChannel}, + server::{BoxedChannelTypes, RpcChannel}, transport::Listener, RpcClient, RpcServer, }; @@ -292,7 +292,7 @@ mod tests { async fn smoke() -> TestResult<()> { async fn handle_sub_request( _req: String, - _chan: RpcChannel>, + _chan: RpcChannel>, ) -> anyhow::Result<()> { Ok(()) } diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 75adc56..95c17c8 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -1,4 +1,4 @@ -//! Transports for quic-rpc +//! Built in transports for quic-rpc //! //! There are two sides to a transport, a server side where connections are //! accepted and a client side where connections are initiated. From eb55692b249db16b809d79a06c87df8a1b50233f Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 16:08:07 +0200 Subject: [PATCH 28/32] remove all in-memory transports from default --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 208dc6e..e4e467e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ hyper-transport = ["dep:flume", "dep:hyper", "dep:bincode", "dep:bytes", "dep:to quinn-transport = ["dep:flume", "dep:quinn", "dep:bincode", "dep:tokio-serde", "dep:tokio-util"] flume-transport = ["dep:flume"] macros = [] -default = ["flume-transport", "quinn-transport", "hyper-transport"] +default = ["flume-transport"] [package.metadata.docs.rs] all-features = true From f10a4d6587b8add16e9fee62a685649cfb5f7e7f Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 16:08:49 +0200 Subject: [PATCH 29/32] remove all in-memory transports from default # Conflicts: # Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 48dd2f8..e4e467e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ hyper-transport = ["dep:flume", "dep:hyper", "dep:bincode", "dep:bytes", "dep:to quinn-transport = ["dep:flume", "dep:quinn", "dep:bincode", "dep:tokio-serde", "dep:tokio-util"] flume-transport = ["dep:flume"] macros = [] -default = ["flume-transport", "quinn-transport"] +default = ["flume-transport"] [package.metadata.docs.rs] all-features = true From 1839b2bd324b94f13920fa4fb773a80b9a687a06 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 17:24:42 +0200 Subject: [PATCH 30/32] rename connection to channel and remove service_connection --- examples/errors.rs | 2 +- examples/macro.rs | 2 +- examples/modularize.rs | 2 +- examples/store.rs | 4 ++-- src/lib.rs | 2 +- src/transport/boxed.rs | 2 +- src/transport/flume.rs | 17 +++-------------- src/transport/mapped.rs | 2 +- tests/flume.rs | 6 +++--- tests/try.rs | 2 +- 10 files changed, 15 insertions(+), 26 deletions(-) diff --git a/examples/errors.rs b/examples/errors.rs index 4f9a069..fabf864 100644 --- a/examples/errors.rs +++ b/examples/errors.rs @@ -55,7 +55,7 @@ impl Fs { #[tokio::main] async fn main() -> anyhow::Result<()> { let fs = Fs; - let (server, client) = quic_rpc::transport::flume::connection(1); + let (server, client) = quic_rpc::transport::flume::channel(1); let client = RpcClient::::new(client); let server = RpcServer::new(server); let handle = tokio::task::spawn(async move { diff --git a/examples/macro.rs b/examples/macro.rs index 7492ec0..88e76d2 100644 --- a/examples/macro.rs +++ b/examples/macro.rs @@ -105,7 +105,7 @@ create_store_dispatch!(Store, dispatch_store_request); #[tokio::main] async fn main() -> anyhow::Result<()> { - let (server, client) = flume::connection(1); + let (server, client) = flume::channel(1); let server_handle = tokio::task::spawn(async move { let target = Store; run_server_loop(StoreService, server, target, dispatch_store_request).await diff --git a/examples/modularize.rs b/examples/modularize.rs index db1ec54..e574c1b 100644 --- a/examples/modularize.rs +++ b/examples/modularize.rs @@ -19,7 +19,7 @@ use app::AppService; async fn main() -> Result<()> { // Spawn an inmemory connection. // Could use quic equally (all code in this example is generic over the transport) - let (server_conn, client_conn) = flume::connection(1); + let (server_conn, client_conn) = flume::channel(1); // spawn the server let handler = app::Handler::default(); diff --git a/examples/store.rs b/examples/store.rs index 3df9617..6339218 100644 --- a/examples/store.rs +++ b/examples/store.rs @@ -184,7 +184,7 @@ async fn main() -> anyhow::Result<()> { } } - let (server, client) = flume::connection(1); + let (server, client) = flume::channel(1); let client = RpcClient::::new(client); let server = RpcServer::::new(server); let server_handle = tokio::task::spawn(server_future(server)); @@ -238,7 +238,7 @@ async fn _main_unsugared() -> anyhow::Result<()> { type Req = u64; type Res = String; } - let (server, client) = flume::connection::(1); + let (server, client) = flume::channel::(1); let to_string_service = tokio::spawn(async move { let (mut send, mut recv) = server.accept().await?; while let Some(item) = recv.next().await { diff --git a/src/lib.rs b/src/lib.rs index a29bedc..89ebc29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ //! } //! //! // create a transport channel, here a memory channel for testing -//! let (server, client) = quic_rpc::transport::flume::connection(1); +//! let (server, client) = quic_rpc::transport::flume::channel(1); //! //! // client side //! // create the rpc client given the channel and the service type diff --git a/src/transport/boxed.rs b/src/transport/boxed.rs index 94e9f74..3304bd1 100644 --- a/src/transport/boxed.rs +++ b/src/transport/boxed.rs @@ -476,7 +476,7 @@ mod tests { use crate::transport::{Connector, Listener}; - let (server, client) = crate::transport::flume::connection(1); + let (server, client) = crate::transport::flume::channel(1); let server = super::BoxedListener::new(server); let client = super::BoxedConnector::new(client); // spawn echo server diff --git a/src/transport/flume.rs b/src/transport/flume.rs index a18aaf4..2671953 100644 --- a/src/transport/flume.rs +++ b/src/transport/flume.rs @@ -99,7 +99,7 @@ impl error::Error for RecvError {} /// A flume based listener. /// -/// Created using [connection]. +/// Created using [channel]. pub struct FlumeListener { #[allow(clippy::type_complexity)] stream: flume::Receiver<(SendSink, RecvStream)>, @@ -248,7 +248,7 @@ impl Connector for FlumeConnector { /// A flume based connector. /// -/// Created using [connection]. +/// Created using [channel]. pub struct FlumeConnector { #[allow(clippy::type_complexity)] sink: flume::Sender<(SendSink, RecvStream)>, @@ -337,20 +337,9 @@ impl std::error::Error for CreateChannelError {} /// Create a flume listener and a connected flume connector. /// /// `buffer` the size of the buffer for each channel. Keep this at a low value to get backpressure -pub fn connection( +pub fn channel( buffer: usize, ) -> (FlumeListener, FlumeConnector) { let (sink, stream) = flume::bounded(buffer); (FlumeListener { stream }, FlumeConnector { sink }) } - -/// Create a flume listener and a connected flume connector for a specific service. -#[allow(clippy::type_complexity)] -pub fn service_connection( - buffer: usize, -) -> ( - FlumeListener, - FlumeConnector, -) { - connection(buffer) -} diff --git a/src/transport/mapped.rs b/src/transport/mapped.rs index 0029552..fbdee41 100644 --- a/src/transport/mapped.rs +++ b/src/transport/mapped.rs @@ -297,7 +297,7 @@ mod tests { Ok(()) } // create a listener / connector pair. Type will be inferred - let (s, c) = crate::transport::flume::connection(32); + let (s, c) = crate::transport::flume::channel(32); // wrap the server in a RpcServer, this is where the service type is specified let server = RpcServer::::new(s.clone()); // when using a boxed transport, we can omit the transport type and use the default diff --git a/tests/flume.rs b/tests/flume.rs index e9e1097..d0b14c8 100644 --- a/tests/flume.rs +++ b/tests/flume.rs @@ -11,7 +11,7 @@ use quic_rpc::{ #[tokio::test] async fn flume_channel_bench() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); - let (server, client) = flume::connection(1); + let (server, client) = flume::channel(1); let server = RpcServer::::new(server); let server_handle = tokio::task::spawn(ComputeService::server(server)); @@ -60,7 +60,7 @@ async fn flume_channel_mapped_bench() -> anyhow::Result<()> { type Req = InnerRequest; type Res = InnerResponse; } - let (server, client) = flume::connection(1); + let (server, client) = flume::channel(1); let server = RpcServer::::new(server); let server_handle: tokio::task::JoinHandle>> = @@ -98,7 +98,7 @@ async fn flume_channel_mapped_bench() -> anyhow::Result<()> { #[tokio::test] async fn flume_channel_smoke() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); - let (server, client) = flume::connection(1); + let (server, client) = flume::channel(1); let server = RpcServer::::new(server); let server_handle = tokio::task::spawn(ComputeService::server(server)); diff --git a/tests/try.rs b/tests/try.rs index 66cabcd..b11f633 100644 --- a/tests/try.rs +++ b/tests/try.rs @@ -72,7 +72,7 @@ impl Handler { #[tokio::test] async fn try_server_streaming() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); - let (server, client) = flume::connection(1); + let (server, client) = flume::channel(1); let server = RpcServer::::new(server); let server_handle = tokio::task::spawn(async move { From 16b7c4942365b96fc750627459261e52e1190f6c Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 5 Nov 2024 17:26:34 +0200 Subject: [PATCH 31/32] increase version numbers --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- quic-rpc-derive/Cargo.toml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63934af..d7eef6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -902,7 +902,7 @@ dependencies = [ [[package]] name = "quic-rpc" -version = "0.14.0" +version = "0.15.0" dependencies = [ "anyhow", "async-stream", @@ -937,7 +937,7 @@ dependencies = [ [[package]] name = "quic-rpc-derive" -version = "0.14.0" +version = "0.15.0" dependencies = [ "derive_more", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index e4e467e..6471559 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quic-rpc" -version = "0.14.0" +version = "0.15.0" edition = "2021" authors = ["RĂ¼diger Klaehn ", "n0 team"] keywords = ["api", "protocol", "network", "rpc"] diff --git a/quic-rpc-derive/Cargo.toml b/quic-rpc-derive/Cargo.toml index 98dea91..131985e 100644 --- a/quic-rpc-derive/Cargo.toml +++ b/quic-rpc-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quic-rpc-derive" -version = "0.14.0" +version = "0.15.0" edition = "2021" authors = ["RĂ¼diger Klaehn "] keywords = ["api", "protocol", "network", "rpc", "macro"] @@ -16,7 +16,7 @@ proc-macro = true syn = { version = "1.0", features = ["full"] } quote = "1.0" proc-macro2 = "1.0" -quic-rpc = { version = "0.14", path = ".." } +quic-rpc = { version = "0.15", path = ".." } [dev-dependencies] derive_more = "1.0.0-beta.6" From 72faad1011fba08fd23e875916555ddc1023041b Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Wed, 6 Nov 2024 11:00:41 +0200 Subject: [PATCH 32/32] Update cargo.lock to get rid of yanked futures-util v0.3.30 --- Cargo.lock | 367 +++++++++++++++++++++++++++-------------------------- 1 file changed, 187 insertions(+), 180 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7eef6c..c39e148 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aho-corasick" @@ -28,15 +28,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -45,34 +45,34 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -110,15 +110,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cc" -version = "1.1.11" +version = "1.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb8dd288a69fc53a1996d7ecfbf4a20d59065bff137ce7e56bbd620de191189" +checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" dependencies = [ "shlex", ] @@ -160,6 +160,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "cordyceps" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec10f0a762d93c4498d2e97a333805cb6250d60bead623f71d8034f9a4152ba3" +dependencies = [ + "loom", + "tracing", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -202,19 +212,15 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", "unicode-xid", ] [[package]] name = "diatomic-waker" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a510eb4dc7fa435297888c00e0f999aa2ee3e920a357221c35ab615a80bbcf" -dependencies = [ - "loom", - "waker-fn", -] +checksum = "ab03c107fafeb3ee9f5925686dbb7a73bc76e3932abb0d2b365cb64b169cf04c" [[package]] name = "educe" @@ -238,7 +244,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -259,15 +265,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", @@ -283,9 +289,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -298,10 +304,11 @@ dependencies = [ [[package]] name = "futures-buffered" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fa130f3777d0d4b0993653c20bc433026d3290627693c4ed1b18dd237357ab" +checksum = "34acda8ae8b63fbe0b2195c998b180cff89a8212fb2622a78b572a9f1c6f7684" dependencies = [ + "cordyceps", "diatomic-waker", "futures-core", "pin-project-lite", @@ -309,9 +316,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -319,15 +326,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -336,15 +343,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210" dependencies = [ "fastrand", "futures-core", @@ -355,32 +362,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -422,9 +429,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -453,9 +460,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" [[package]] name = "hermit-abi" @@ -493,9 +500,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -505,9 +512,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -529,9 +536,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", @@ -575,9 +582,9 @@ dependencies = [ [[package]] name = "iroh-quinn-udp" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0619b59471fdd393ac8a6c047f640171119c1c8b41f7d2927db91776dcdbc5f" +checksum = "bfcfc0abc2fdf8cf18a6c72893b7cbebeac2274a3b1306c1760c48c0e10ac5e0" dependencies = [ "libc", "once_cell", @@ -614,9 +621,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -629,9 +636,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "linux-raw-sys" @@ -685,11 +692,11 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -771,18 +778,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl-probe" @@ -798,9 +805,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -837,29 +844,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -893,9 +900,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -950,9 +957,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1001,23 +1008,23 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -1031,13 +1038,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -1048,9 +1055,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ring" @@ -1081,9 +1088,9 @@ checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" dependencies = [ "bitflags", "errno", @@ -1094,9 +1101,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "once_cell", "ring", @@ -1108,9 +1115,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -1121,25 +1128,24 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-platform-verifier" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93bda3f493b9abe5b93b3e7e3ecde0df292f2bd28c0296b90586ee0055ff5123" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" dependencies = [ "core-foundation", "core-foundation-sys", @@ -1164,9 +1170,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -1175,9 +1181,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -1196,11 +1202,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1231,9 +1237,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -1241,29 +1247,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.207" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.207" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -1273,9 +1279,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -1374,20 +1380,26 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.74" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "target-triple" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" + [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -1413,22 +1425,22 @@ checksum = "614b328ff036a4ef882c61570f72918f7e9c5bee1da33f8e7f91e01daee7e56c" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1483,9 +1495,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", @@ -1507,7 +1519,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1527,9 +1539,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -1561,9 +1573,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", @@ -1598,7 +1610,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1648,14 +1660,15 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" +checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4" dependencies = [ "glob", "serde", "serde_derive", "serde_json", + "target-triple", "termcolor", "toml", ] @@ -1672,15 +1685,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -1694,12 +1707,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "walkdir" version = "2.5.0" @@ -1727,9 +1734,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -1738,24 +1745,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1763,28 +1770,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -1970,9 +1977,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -2004,7 +2011,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]]