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
8use crate::{connection::Socket, Call, Connection, Reply};
9
10/// The item type that a [`Service::ReplyStream`] yields.
11///
12/// On `std`, this is a tuple of the reply and the file descriptors to send with it. On `no_std`,
13/// this is just the reply.
14#[cfg(feature = "std")]
15pub type ReplyStreamItem<Params> = (Reply<Params>, Vec<std::os::fd::OwnedFd>);
16/// The item type that a [`Service::ReplyStream`] yields.
17///
18/// On `std`, this is a tuple of the reply and the file descriptors to send with it. On `no_std`,
19/// this is just the reply.
20#[cfg(not(feature = "std"))]
21pub type ReplyStreamItem<Params> = Reply<Params>;
22
23/// Service trait for handling method calls.
24///
25/// Instead of implementing this trait manually, prefer using the [`service`] attribute macro which
26/// generates the implementation for you. The macro provides a more ergonomic API and handles the
27/// boilerplate of method dispatching, error handling, and streaming replies.
28///
29/// See the [`service`] macro documentation for details and examples.
30///
31/// [`service`]: macro@crate::service
32pub trait Service<Sock>
33where
34 Sock: Socket,
35{
36 /// The type of method call that this service handles.
37 ///
38 /// This should be a type that can deserialize itself from a complete method call message: i-e
39 /// an object containing `method` and `parameter` fields. This can be easily achieved using the
40 /// `serde::Deserialize` derive (See the code snippet in
41 /// [`crate::connection::WriteConnection::send_call`] documentation for an example).
42 type MethodCall<'de>: Deserialize<'de> + Debug;
43 /// The type of the successful reply.
44 ///
45 /// This should be a type that can serialize itself as the `parameters` field of the reply.
46 type ReplyParams<'ser>: Serialize + Debug
47 where
48 Self: 'ser;
49 /// The type of the item that [`Service::ReplyStream`] will be expected to yield.
50 ///
51 /// This should be a type that can serialize itself as the `parameters` field of the reply.
52 type ReplyStreamParams: Serialize + Debug;
53 /// The type of the multi-reply stream.
54 ///
55 /// If the client asks for multiple replies, this stream will be used to send them.
56 type ReplyStream: Stream<Item = ReplyStreamItem<Self::ReplyStreamParams>> + Unpin;
57 /// The type of the error reply.
58 ///
59 /// This should be a type that can serialize itself to the whole reply object, containing
60 /// `error` and `parameter` fields. This can be easily achieved using the `serde::Serialize`
61 /// derive (See the code snippet in [`crate::connection::ReadConnection::receive_reply`]
62 /// documentation for an example).
63 type ReplyError<'ser>: Serialize + Debug
64 where
65 Self: 'ser;
66
67 /// Handle a method call.
68 fn handle<'ser>(
69 &'ser mut self,
70 method: &'ser Call<Self::MethodCall<'_>>,
71 conn: &mut Connection<Sock>,
72 #[cfg(feature = "std")] fds: Vec<std::os::fd::OwnedFd>,
73 ) -> impl Future<
74 Output = HandleResult<Self::ReplyParams<'ser>, Self::ReplyStream, Self::ReplyError<'ser>>,
75 >;
76}
77
78/// The result of a [`Service::handle`] call.
79///
80/// On `std`, this is a tuple of the method reply and the file descriptors to send with it. On
81/// `no_std`, this is just the method reply.
82#[cfg(feature = "std")]
83pub type HandleResult<Params, ReplyStream, ReplyError> = (
84 MethodReply<Params, ReplyStream, ReplyError>,
85 Vec<std::os::fd::OwnedFd>,
86);
87/// The result of a [`Service::handle`] call.
88///
89/// On `std`, this is a tuple of the method reply and the file descriptors to send with it. On
90/// `no_std`, this is just the method reply.
91#[cfg(not(feature = "std"))]
92pub type HandleResult<Params, ReplyStream, ReplyError> =
93 MethodReply<Params, ReplyStream, ReplyError>;
94
95/// A service method call reply.
96#[derive(Debug)]
97pub enum MethodReply<Params, ReplyStream, ReplyError> {
98 /// A single reply.
99 Single(Option<Params>),
100 /// An error reply.
101 Error(ReplyError),
102 /// A multi-reply stream.
103 Multi(ReplyStream),
104}