Skip to main content

zlink_core/server/
service.rs

1//! Service-related API.
2
3use core::{fmt::Debug, future::Future};
4
5use futures_util::Stream;
6use serde::{Deserialize, Serialize};
7
8pub use super::infallible::Infallible;
9use crate::{Call, Connection, Reply, connection::Socket};
10
11/// The item type that a [`Service::ReplyStream`] yields.
12///
13/// Each item is either an [`Ok`] success [`Reply`] or an [`Err`] error reply. Services whose
14/// streaming methods never fail should set [`Service::ReplyStreamError`] to [`Infallible`], in
15/// which case the `Err` arm is statically unreachable.
16///
17/// On `std`, the alias additionally pairs the result with the file descriptors to send. On
18/// `no_std`, it is just the result.
19#[cfg(feature = "std")]
20pub type ReplyStreamItem<Params, Error> = (
21    core::result::Result<Reply<Params>, Error>,
22    Vec<std::os::fd::OwnedFd>,
23);
24/// The item type that a [`Service::ReplyStream`] yields.
25///
26/// Each item is either an [`Ok`] success [`Reply`] or an [`Err`] error reply. Services whose
27/// streaming methods never fail should set [`Service::ReplyStreamError`] to [`Infallible`], in
28/// which case the `Err` arm is statically unreachable.
29///
30/// On `std`, the alias additionally pairs the result with the file descriptors to send. On
31/// `no_std`, it is just the result.
32#[cfg(not(feature = "std"))]
33pub type ReplyStreamItem<Params, Error> = core::result::Result<Reply<Params>, Error>;
34
35/// Service trait for handling method calls.
36///
37/// Instead of implementing this trait manually, prefer using the [`service`] attribute macro which
38/// generates the implementation for you. The macro provides a more ergonomic API and handles the
39/// boilerplate of method dispatching, error handling, and streaming replies.
40///
41/// See the [`service`] macro documentation for details and examples.
42///
43/// [`service`]: macro@crate::service
44pub trait Service<Sock>
45where
46    Sock: Socket,
47{
48    /// The type of method call that this service handles.
49    ///
50    /// This should be a type that can deserialize itself from a complete method call message: i-e
51    /// an object containing `method` and `parameter` fields. This can be easily achieved using the
52    /// `serde::Deserialize` derive (See the code snippet in
53    /// [`crate::connection::WriteConnection::send_call`] documentation for an example).
54    type MethodCall<'de>: Deserialize<'de> + Debug;
55    /// The type of the successful reply.
56    ///
57    /// This should be a type that can serialize itself as the `parameters` field of the reply.
58    type ReplyParams<'ser>: Serialize + Debug
59    where
60        Self: 'ser;
61    /// The type of the item that [`Service::ReplyStream`] will be expected to yield.
62    ///
63    /// This should be a type that can serialize itself as the `parameters` field of the reply.
64    type ReplyStreamParams: Serialize + Debug;
65    /// The type of an error reply produced by a streaming method.
66    ///
67    /// Unlike [`Self::ReplyError`], this type cannot borrow from `&self` (the stream outlives the
68    /// `handle` call). Services whose streaming methods never fail should set this to
69    /// [`Infallible`] — the `Err` arm of [`ReplyStreamItem`] then becomes statically unreachable.
70    type ReplyStreamError: Serialize + Debug;
71    /// The type of the multi-reply stream.
72    ///
73    /// If the client asks for multiple replies, this stream will be used to send them. Each
74    /// stream item is either a success [`Reply`] or an error of type [`Self::ReplyStreamError`].
75    type ReplyStream: Stream<Item = ReplyStreamItem<Self::ReplyStreamParams, Self::ReplyStreamError>>
76        + Unpin;
77    /// The type of the error reply.
78    ///
79    /// This should be a type that can serialize itself to the whole reply object, containing
80    /// `error` and `parameter` fields. This can be easily achieved using the `serde::Serialize`
81    /// derive (See the code snippet in [`crate::connection::ReadConnection::receive_reply`]
82    /// documentation for an example).
83    ///
84    /// Services whose methods never fail can use [`Infallible`] for this type as well.
85    type ReplyError<'ser>: Serialize + Debug
86    where
87        Self: 'ser;
88
89    /// Handle a method call.
90    fn handle<'ser>(
91        &'ser mut self,
92        method: &'ser Call<Self::MethodCall<'_>>,
93        conn: &mut Connection<Sock>,
94        #[cfg(feature = "std")] fds: Vec<std::os::fd::OwnedFd>,
95    ) -> impl Future<
96        Output = HandleResult<Self::ReplyParams<'ser>, Self::ReplyStream, Self::ReplyError<'ser>>,
97    >;
98}
99
100/// The result of a [`Service::handle`] call.
101///
102/// On `std`, this is a tuple of the method reply and the file descriptors to send with it. On
103/// `no_std`, this is just the method reply.
104#[cfg(feature = "std")]
105pub type HandleResult<Params, ReplyStream, ReplyError> = (
106    MethodReply<Params, ReplyStream, ReplyError>,
107    Vec<std::os::fd::OwnedFd>,
108);
109/// The result of a [`Service::handle`] call.
110///
111/// On `std`, this is a tuple of the method reply and the file descriptors to send with it. On
112/// `no_std`, this is just the method reply.
113#[cfg(not(feature = "std"))]
114pub type HandleResult<Params, ReplyStream, ReplyError> =
115    MethodReply<Params, ReplyStream, ReplyError>;
116
117/// A service method call reply.
118#[derive(Debug)]
119pub enum MethodReply<Params, ReplyStream, ReplyError> {
120    /// A single reply.
121    Single(Option<Params>),
122    /// An error reply.
123    Error(ReplyError),
124    /// A multi-reply stream.
125    Multi(ReplyStream),
126}