acktor_ipc/ipc_method.rs
1//! Traits for Inter-Process Communication (IPC) and some pre-implemented IPC methods.
2//!
3
4use std::io::Error;
5use std::pin::Pin;
6use std::sync::Arc;
7
8use bytes::Bytes;
9
10#[cfg(feature = "pipe")]
11#[cfg_attr(docsrs, doc(cfg(feature = "pipe")))]
12pub mod pipe;
13
14#[cfg(feature = "websocket")]
15#[cfg_attr(docsrs, doc(cfg(feature = "websocket")))]
16pub mod websocket;
17
18/// A boxed `Send` future returning `Result<T, std::io::Error>`, used as the return type
19/// of dyn-compatible trait methods in this module.
20pub type IoFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, Error>> + Send + 'a>>;
21
22/// Describes the behavior of an IPC listener which accepts incoming IPC connections.
23///
24/// A [`Node`][crate::node::Node] uses a listener to accept inbound connections. Outbound
25/// connections are initiated by calling [`IpcConnection::connect`] on a concrete connection
26/// type directly.
27pub trait IpcListener: Send + Sync + 'static {
28 /// Returns the local endpoint the listener is bound to.
29 fn local_endpoint(&self) -> &str;
30
31 /// Accepts an incoming IPC connection.
32 ///
33 /// # Cancel safety
34 ///
35 /// This method is **not** guaranteed to be cancel safe. If the returned future is dropped
36 /// before it completes, it may leave a peer-side connection in a partially-initialized state
37 /// (e.g. mid-handshake).
38 fn accept(&self) -> IoFuture<'_, Box<dyn IpcConnection>>;
39}
40
41/// Describes the behavior of an IPC connection.
42///
43/// An IPC connection should be a duplex communication channel between two end points. If the
44/// underlying protocol is not duplex, the implementation should simulate the duplex behavior,
45/// e.g., by using two separate connections.
46///
47/// Implementations are responsible for message framing: one call to [`send`](Self::send) must
48/// correspond to exactly one call to [`recv`](Self::recv) on the remote end, regardless of how
49/// the underlying transport delivers bytes.
50pub trait IpcConnection: Send + Sync + 'static {
51 /// Connects to an IPC listener at a specific endpoint.
52 ///
53 /// This is a constructor-style method that returns a concrete connection, so it requires
54 /// `Self: Sized`.
55 fn connect(endpoint: &str) -> impl Future<Output = Result<Self, Error>> + Send
56 where
57 Self: Sized;
58
59 /// Returns the peer endpoint of the IPC connection.
60 fn peer_endpoint(&self) -> &str;
61
62 /// Closes the IPC connection.
63 fn close(&mut self) -> IoFuture<'_, ()>;
64
65 /// Sends a message to the other end of the connection.
66 ///
67 /// The entire `buf` is delivered as a single framed message.
68 fn send(&mut self, buf: Bytes) -> IoFuture<'_, ()>;
69
70 /// Receives the next message from the other end of the connection.
71 ///
72 /// Returns the message payload as a [`Bytes`] value; implementations should return a slice
73 /// of their internal read buffer whenever possible to avoid copying.
74 ///
75 /// # Cancel safety
76 ///
77 /// The implementation should be cancel safe. If the method is used as the event in a
78 /// [`tokio::select!`](tokio::select) statement and some other branch completes first, then
79 /// it is guaranteed that no data was read from the underlying connection.
80 fn recv(&mut self) -> IoFuture<'_, Bytes>;
81}
82
83impl<T> IpcListener for Box<T>
84where
85 T: IpcListener + ?Sized,
86{
87 fn local_endpoint(&self) -> &str {
88 (**self).local_endpoint()
89 }
90
91 fn accept(&self) -> IoFuture<'_, Box<dyn IpcConnection>> {
92 (**self).accept()
93 }
94}
95
96impl<T> IpcListener for Arc<T>
97where
98 T: IpcListener + ?Sized,
99{
100 fn local_endpoint(&self) -> &str {
101 (**self).local_endpoint()
102 }
103
104 fn accept(&self) -> IoFuture<'_, Box<dyn IpcConnection>> {
105 (**self).accept()
106 }
107}