musli_web/
api.rs

1//! Shared traits for defining API types.
2
3use core::fmt;
4use core::num::NonZeroU16;
5
6use musli::alloc::Global;
7use musli::mode::Binary;
8use musli::{Decode, Encode};
9
10#[doc(inline)]
11pub use musli_web_macros::define;
12
13/// A trait for constructing identifiers.
14pub trait Id
15where
16    Self: 'static + fmt::Debug,
17{
18    /// Construct an identifier from a raw `u16`.
19    #[doc(hidden)]
20    fn from_raw(id: u16) -> Option<Self>
21    where
22        Self: Sized;
23}
24
25/// The identifier of a message.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
27#[repr(transparent)]
28#[musli(transparent)]
29pub struct MessageId(NonZeroU16);
30
31impl fmt::Display for MessageId {
32    #[inline]
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        self.0.fmt(f)
35    }
36}
37
38/// Start of special identifiers.
39const START: u16 = i16::MAX as u16;
40
41impl MessageId {
42    /// The message id for [`ErrorMessage`].
43    pub const ERROR_MESSAGE: Self = unsafe { Self::new_unchecked(START) };
44
45    /// Try to construct a message id.
46    #[doc(hidden)]
47    #[inline]
48    pub const fn new(id: u16) -> Option<Self> {
49        let Some(value) = NonZeroU16::new(id) else {
50            return None;
51        };
52
53        Some(Self(value))
54    }
55
56    /// Get a raw message identifier.
57    #[doc(hidden)]
58    #[inline]
59    pub const fn get(&self) -> u16 {
60        self.0.get()
61    }
62
63    /// Construct a new message ID.
64    ///
65    /// # Panics
66    ///
67    /// Panics if `id` is zero.
68    #[doc(hidden)]
69    #[inline]
70    pub const unsafe fn new_unchecked(id: u16) -> Self {
71        Self(unsafe { NonZeroU16::new_unchecked(id) })
72    }
73}
74
75pub trait Endpoint
76where
77    Self: 'static,
78{
79    /// The kind of the endpoint.
80    const ID: MessageId;
81
82    /// The primary response type related to the endpoint.
83    type Response<'de>: Decode<'de, Binary, Global>;
84
85    #[doc(hidden)]
86    fn __do_not_implement_endpoint();
87}
88
89/// The marker trait used for broadcasts.
90///
91/// Do not implement manually, instead use the [`define!`] macro.
92pub trait Broadcast
93where
94    Self: 'static,
95{
96    /// The kind of the broadcast.
97    const ID: MessageId;
98
99    /// The primary event related to the broadcast.
100    type Event<'de>: Event<Broadcast = Self> + Decode<'de, Binary, Global>;
101
102    #[doc(hidden)]
103    fn __do_not_implement_broadcast();
104}
105
106/// A marker indicating a request type.
107///
108/// Do not implement manually, instead use the [`define!`] macro.
109pub trait Request
110where
111    Self: Encode<Binary>,
112{
113    /// The endpoint related to the request.
114    type Endpoint: Endpoint;
115
116    #[doc(hidden)]
117    fn __do_not_implement_request();
118}
119
120/// The event of a broadcast.
121///
122/// Do not implement manually, instead use the [`define!`] macro.
123pub trait Event
124where
125    Self: Encode<Binary>,
126{
127    /// The endpoint related to the broadcast.
128    type Broadcast: Broadcast;
129
130    #[doc(hidden)]
131    fn __do_not_implement_event();
132}
133
134/// A request header.
135#[derive(Debug, Clone, Copy, Encode, Decode)]
136#[doc(hidden)]
137#[musli(packed)]
138pub struct RequestHeader {
139    /// The serial of the request.
140    pub serial: u32,
141    /// The kind of the request.
142    pub id: u16,
143}
144
145/// The header of a response.
146#[derive(Debug, Clone, Encode, Decode)]
147#[doc(hidden)]
148#[musli(packed)]
149pub struct ResponseHeader {
150    /// The serial request this is a response to.
151    pub serial: u32,
152    /// This is a broadcast over the specified type. If this is non-empty the
153    /// serial is 0.
154    pub broadcast: u16,
155    /// If non-zero, the response contains an error of the given type.
156    pub error: u16,
157}
158
159/// An error response.
160#[derive(Debug, Clone, Encode, Decode)]
161#[doc(hidden)]
162#[musli(packed)]
163pub struct ErrorMessage<'de> {
164    /// The error message.
165    pub message: &'de str,
166}