pub struct Connection<S: Socket> { /* private fields */ }Expand description
A connection.
The low-level API to send and receive messages.
Each connection gets a unique identifier when created that can be queried using
Connection::id. This ID is shared between the read and write halves of the connection. It
can be used to associate the read and write halves of the same connection.
§Cancel safety
All async methods of this type are cancel safe unless explicitly stated otherwise in its documentation.
Implementations§
Source§impl<S> Connection<S>where
S: Socket,
impl<S> Connection<S>where
S: Socket,
Sourcepub fn read(&self) -> &ReadConnection<S::ReadHalf>
pub fn read(&self) -> &ReadConnection<S::ReadHalf>
The reference to the read half of the connection.
Sourcepub fn read_mut(&mut self) -> &mut ReadConnection<S::ReadHalf>
pub fn read_mut(&mut self) -> &mut ReadConnection<S::ReadHalf>
The mutable reference to the read half of the connection.
Sourcepub fn write(&self) -> &WriteConnection<S::WriteHalf>
pub fn write(&self) -> &WriteConnection<S::WriteHalf>
The reference to the write half of the connection.
Sourcepub fn write_mut(&mut self) -> &mut WriteConnection<S::WriteHalf>
pub fn write_mut(&mut self) -> &mut WriteConnection<S::WriteHalf>
The mutable reference to the write half of the connection.
Sourcepub fn split(
self,
) -> (ReadConnection<S::ReadHalf>, WriteConnection<S::WriteHalf>)
pub fn split( self, ) -> (ReadConnection<S::ReadHalf>, WriteConnection<S::WriteHalf>)
Split the connection into read and write halves.
Note: This consumes any cached credentials. If you need the credentials after splitting,
call Connection::peer_credentials before splitting.
Sourcepub fn join(
read: ReadConnection<S::ReadHalf>,
write: WriteConnection<S::WriteHalf>,
) -> Self
pub fn join( read: ReadConnection<S::ReadHalf>, write: WriteConnection<S::WriteHalf>, ) -> Self
Join the read and write halves into a connection (the opposite of Connection::split).
Sourcepub async fn send_call<Method>(
&mut self,
call: &Call<Method>,
fds: Vec<OwnedFd>,
) -> Result<()>
pub async fn send_call<Method>( &mut self, call: &Call<Method>, fds: Vec<OwnedFd>, ) -> Result<()>
Sends a method call.
Convenience wrapper around WriteConnection::send_call.
Sourcepub async fn receive_reply<'r, ReplyParams, ReplyError>(
&'r mut self,
) -> Result<(Result<ReplyParams, ReplyError>, Vec<OwnedFd>)>
pub async fn receive_reply<'r, ReplyParams, ReplyError>( &'r mut self, ) -> Result<(Result<ReplyParams, ReplyError>, Vec<OwnedFd>)>
Receives a method call reply.
Convenience wrapper around ReadConnection::receive_reply.
Sourcepub async fn call_method<'r, Method, ReplyParams, ReplyError>(
&'r mut self,
call: &Call<Method>,
fds: Vec<OwnedFd>,
) -> Result<(Result<ReplyParams, ReplyError>, Vec<OwnedFd>)>where
Method: Serialize + Debug,
ReplyParams: Deserialize<'r> + Debug,
ReplyError: Deserialize<'r> + Debug,
pub async fn call_method<'r, Method, ReplyParams, ReplyError>(
&'r mut self,
call: &Call<Method>,
fds: Vec<OwnedFd>,
) -> Result<(Result<ReplyParams, ReplyError>, Vec<OwnedFd>)>where
Method: Serialize + Debug,
ReplyParams: Deserialize<'r> + Debug,
ReplyError: Deserialize<'r> + Debug,
Call a method and receive a reply.
This is a convenience method that combines Connection::send_call and
Connection::receive_reply.
Sourcepub async fn receive_call<'m, Method>(
&'m mut self,
) -> Result<(Call<Method>, Vec<OwnedFd>)>where
Method: Deserialize<'m> + Debug,
pub async fn receive_call<'m, Method>(
&'m mut self,
) -> Result<(Call<Method>, Vec<OwnedFd>)>where
Method: Deserialize<'m> + Debug,
Receive a method call over the socket.
Convenience wrapper around ReadConnection::receive_call.
Sourcepub async fn send_reply<ReplyParams>(
&mut self,
reply: &Reply<ReplyParams>,
fds: Vec<OwnedFd>,
) -> Result<()>
pub async fn send_reply<ReplyParams>( &mut self, reply: &Reply<ReplyParams>, fds: Vec<OwnedFd>, ) -> Result<()>
Send a reply over the socket.
Convenience wrapper around WriteConnection::send_reply.
Sourcepub async fn send_error<ReplyError>(
&mut self,
error: &ReplyError,
fds: Vec<OwnedFd>,
) -> Result<()>
pub async fn send_error<ReplyError>( &mut self, error: &ReplyError, fds: Vec<OwnedFd>, ) -> Result<()>
Send an error reply over the socket.
Convenience wrapper around WriteConnection::send_error.
Sourcepub fn enqueue_call<Method>(&mut self, method: &Call<Method>) -> Result<()>
pub fn enqueue_call<Method>(&mut self, method: &Call<Method>) -> Result<()>
Enqueue a call to the server.
Convenience wrapper around WriteConnection::enqueue_call.
Sourcepub async fn flush(&mut self) -> Result<()>
pub async fn flush(&mut self) -> Result<()>
Flush the connection.
Convenience wrapper around WriteConnection::flush.
Sourcepub fn chain_call<'c, Method>(
&'c mut self,
call: &Call<Method>,
fds: Vec<OwnedFd>,
) -> Result<Chain<'c, S>>
pub fn chain_call<'c, Method>( &'c mut self, call: &Call<Method>, fds: Vec<OwnedFd>, ) -> Result<Chain<'c, S>>
Start a chain of method calls.
This allows batching multiple calls together and sending them in a single write operation.
§Examples
§Basic Usage with Sequential Access
use zlink_core::{Connection, Call, reply};
use serde::{Serialize, Deserialize};
use serde_prefix_all::prefix_all;
use futures_util::{pin_mut, stream::StreamExt};
#[prefix_all("org.example.")]
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "method", content = "parameters")]
enum Methods {
GetUser { id: u32 },
GetProject { id: u32 },
}
#[derive(Debug, Deserialize)]
struct User { name: String }
#[derive(Debug, Deserialize)]
struct Project { title: String }
#[derive(Debug, zlink_core::ReplyError)]
#[zlink(
interface = "org.example",
// Not needed in the real code because you'll use `ReplyError` through `zlink` crate.
crate = "zlink_core",
)]
enum ApiError {
UserNotFound { code: i32 },
ProjectNotFound { code: i32 },
}
let get_user = Call::new(Methods::GetUser { id: 1 });
let get_project = Call::new(Methods::GetProject { id: 2 });
// Chain calls and send them in a batch
let replies = conn
.chain_call::<Methods>(&get_user, vec![])?
.append(&get_project, vec![])?
.send::<User, ApiError>().await?;
pin_mut!(replies);
// Access replies sequentially.
let (user_reply, _fds) = replies.next().await.unwrap()?;
let (project_reply, _fds) = replies.next().await.unwrap()?;
match user_reply {
Ok(user) => println!("User: {}", user.parameters().unwrap().name),
Err(error) => println!("User error: {:?}", error),
}§Arbitrary Number of Calls
#[zlink(
interface = "org.example",
// Not needed in the real code because you'll use `ReplyError` through `zlink` crate.
crate = "zlink_core",
)]
// Chain many calls (no upper limit)
let mut chain = conn.chain_call::<Methods>(&get_user, vec![])?;
for i in 2..100 {
chain = chain.append(&Call::new(Methods::GetUser { id: i }), vec![])?;
}
let replies = chain.send::<User, ApiError>().await?;
pin_mut!(replies);
// Process all replies sequentially.
while let Some(result) = replies.next().await {
let (user_reply, _fds) = result?;
// Handle each reply...
match user_reply {
Ok(user) => println!("User: {}", user.parameters().unwrap().name),
Err(error) => println!("Error: {:?}", error),
}
}§Performance Benefits
Instead of multiple write operations, the chain sends all calls in a single write operation, reducing context switching and therefore minimizing latency.
Sourcepub fn chain_from_iter<'c, Method, MethodCall, MethodCalls>(
&'c mut self,
calls: MethodCalls,
) -> Result<Chain<'c, S>>where
Method: Serialize + Debug,
MethodCall: Into<Call<Method>>,
MethodCalls: IntoIterator<Item = MethodCall>,
pub fn chain_from_iter<'c, Method, MethodCall, MethodCalls>(
&'c mut self,
calls: MethodCalls,
) -> Result<Chain<'c, S>>where
Method: Serialize + Debug,
MethodCall: Into<Call<Method>>,
MethodCalls: IntoIterator<Item = MethodCall>,
Create a chain from an iterator of method calls.
This allows creating a chain from any iterator yielding method types or calls. Each item
is automatically converted to a Call via Into<Call<Method>>. Unlike
Connection::chain_call, this method allows building chains from dynamically-sized
collections.
§Errors
Returns Error::EmptyChain if the iterator is empty.
§Examples
use zlink_core::Connection;
use serde::{Serialize, Deserialize};
use serde_prefix_all::prefix_all;
use futures_util::{pin_mut, stream::StreamExt};
#[prefix_all("org.example.")]
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "method", content = "parameters")]
enum Methods {
GetUser { id: u32 },
}
#[derive(Debug, Deserialize)]
struct User { name: String }
#[derive(Debug, zlink_core::ReplyError)]
#[zlink(interface = "org.example", crate = "zlink_core")]
enum ApiError {
UserNotFound { code: i32 },
}
let user_ids = [1, 2, 3, 4, 5];
let replies = conn
.chain_from_iter::<Methods, _, _>(
user_ids.iter().map(|&id| Methods::GetUser { id })
)?
.send::<User, ApiError>()
.await?;
pin_mut!(replies);
while let Some(result) = replies.next().await {
let (user_reply, _fds) = result?;
// Handle each reply...
}Sourcepub fn chain_from_iter_with_fds<'c, Method, MethodCall, MethodCalls>(
&'c mut self,
calls: MethodCalls,
) -> Result<Chain<'c, S>>
pub fn chain_from_iter_with_fds<'c, Method, MethodCall, MethodCalls>( &'c mut self, calls: MethodCalls, ) -> Result<Chain<'c, S>>
Create a chain from an iterator of method calls with file descriptors.
Similar to Connection::chain_from_iter, but allows passing file descriptors with each
call. Each item in the iterator is a tuple of a method type (or Call) and its
associated file descriptors.
§Errors
Returns Error::EmptyChain if the iterator is empty.
§Examples
use zlink_core::Connection;
use serde::{Serialize, Deserialize};
use serde_prefix_all::prefix_all;
use std::os::fd::OwnedFd;
#[prefix_all("org.example.")]
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "method", content = "parameters")]
enum Methods {
SendFile { name: String },
}
#[derive(Debug, Deserialize)]
struct FileResult { success: bool }
#[derive(Debug, zlink_core::ReplyError)]
#[zlink(interface = "org.example", crate = "zlink_core")]
enum ApiError {
SendFailed { reason: String },
}
let calls_with_fds: Vec<(Methods, Vec<OwnedFd>)> = vec![
(Methods::SendFile { name: "file1.txt".into() }, vec![/* fd1 */]),
(Methods::SendFile { name: "file2.txt".into() }, vec![/* fd2 */]),
];
let replies = conn
.chain_from_iter_with_fds::<Methods, _, _>(calls_with_fds)?
.send::<FileResult, ApiError>()
.await?;Sourcepub async fn peer_credentials(&mut self) -> Result<&Arc<Credentials>>where
S::ReadHalf: FetchPeerCredentials,
pub async fn peer_credentials(&mut self) -> Result<&Arc<Credentials>>where
S::ReadHalf: FetchPeerCredentials,
Get the peer credentials.
This method caches the credentials on the first call.