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
38impl MessageId {
39    /// The message id for [`ErrorMessage`].
40    pub const ERROR_MESSAGE: Self = unsafe { Self::new_unchecked((i16::MAX as u16) + 1) };
41
42    /// The message id for an empty packet constructed using [`Packet::empty`]
43    /// or [`RawPacket::empty`].
44    ///
45    /// [`Packet::empty`]: crate::web::Packet::empty
46    /// [`RawPacket::empty`]: crate::web::RawPacket::empty
47    ///
48    /// # Examples
49    ///
50    /// ```
51    /// use musli_web::api::MessageId;
52    /// use musli_web::web::{RawPacket, Packet};
53    ///
54    /// let packet = RawPacket::empty();
55    /// assert_eq!(packet.id(), MessageId::EMPTY);
56    ///
57    /// let packet = Packet::<()>::empty();
58    /// assert_eq!(packet.id(), MessageId::EMPTY);
59    /// ```
60    pub const EMPTY: Self = unsafe { Self::new_unchecked(u16::MAX) };
61
62    /// Try to construct a message id.
63    #[doc(hidden)]
64    #[inline]
65    pub const fn new(id: u16) -> Option<Self> {
66        if id > i16::MAX as u16 {
67            return None;
68        }
69
70        let Some(value) = NonZeroU16::new(id) else {
71            return None;
72        };
73
74        Some(Self(value))
75    }
76
77    /// Get a raw message identifier.
78    #[doc(hidden)]
79    #[inline]
80    pub const fn get(&self) -> u16 {
81        self.0.get()
82    }
83
84    /// Construct a new message ID.
85    ///
86    /// # Panics
87    ///
88    /// Panics if `id` is zero.
89    #[doc(hidden)]
90    #[inline]
91    pub const unsafe fn new_unchecked(id: u16) -> Self {
92        Self(unsafe { NonZeroU16::new_unchecked(id) })
93    }
94}
95
96/// A trait implemented for types which can be decoded into something.
97///
98/// Do not implement manually, instead use the [`define!`] macro.
99pub trait Decodable {
100    /// The decodable type related to this.
101    type Type<'de>: Decode<'de, Binary, Global>;
102
103    #[doc(hidden)]
104    fn __do_not_implement_decodable();
105}
106
107/// An endpoint marker trait.
108///
109/// Do not implement manually, instead use the [`define!`] macro.
110pub trait Endpoint
111where
112    Self: 'static,
113    for<'de> Self: Decodable<Type<'de> = Self::Response<'de>>,
114{
115    /// The kind of the endpoint.
116    const ID: MessageId;
117
118    /// The primary response type related to the endpoint.
119    type Response<'de>: Decode<'de, Binary, Global>;
120
121    #[doc(hidden)]
122    fn __do_not_implement_endpoint();
123}
124
125/// The marker trait used for broadcasts.
126///
127/// Do not implement manually, instead use the [`define!`] macro.
128pub trait Broadcast
129where
130    Self: 'static,
131{
132    /// The kind of the broadcast.
133    const ID: MessageId;
134
135    #[doc(hidden)]
136    fn __do_not_implement_broadcast();
137}
138
139/// Trait implemented for broadcasts which have a primary event.
140pub trait BroadcastWithEvent
141where
142    Self: Broadcast,
143    for<'de> Self: Decodable<Type<'de> = Self::Event<'de>>,
144{
145    /// The event type related to the broadcast.
146    type Event<'de>: Event<Broadcast = Self> + Decode<'de, Binary, Global>
147    where
148        Self: 'de;
149
150    #[doc(hidden)]
151    fn __do_not_implement_broadcast_with_event();
152}
153
154/// A marker indicating a request type.
155///
156/// Do not implement manually, instead use the [`define!`] macro.
157pub trait Request
158where
159    Self: Encode<Binary>,
160{
161    /// The endpoint related to the request.
162    type Endpoint: Endpoint;
163
164    #[doc(hidden)]
165    fn __do_not_implement_request();
166}
167
168/// The event of a broadcast.
169///
170/// Do not implement manually, instead use the [`define!`] macro.
171pub trait Event
172where
173    Self: Encode<Binary>,
174{
175    /// The endpoint related to the broadcast.
176    type Broadcast: Broadcast;
177
178    #[doc(hidden)]
179    fn __do_not_implement_event();
180}
181
182/// A request header.
183#[derive(Debug, Clone, Copy, Encode, Decode)]
184#[doc(hidden)]
185#[musli(packed)]
186pub struct RequestHeader {
187    /// The serial of the request.
188    pub serial: u32,
189    /// The kind of the request.
190    pub id: u16,
191}
192
193/// The header of a response.
194#[derive(Debug, Clone, Encode, Decode)]
195#[doc(hidden)]
196#[musli(packed)]
197pub struct ResponseHeader {
198    /// The serial request this is a response to.
199    pub serial: u32,
200    /// This is a broadcast over the specified type. If this is non-empty the
201    /// serial is 0.
202    pub broadcast: u16,
203    /// If non-zero, the response contains an error of the given type.
204    pub error: u16,
205}
206
207/// An error response.
208#[derive(Debug, Clone, Encode, Decode)]
209#[doc(hidden)]
210#[musli(packed)]
211pub struct ErrorMessage<'de> {
212    /// The error message.
213    pub message: &'de str,
214}