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}