Skip to main content

musli_web/
api.rs

1//! Shared traits for defining API types.
2//!
3//! # Wire format
4//!
5//! Every websocket message consists of a fixed *envelope* followed by an
6//! optional *body*:
7//!
8//! ```text
9//! +--------------------------+--------------------------------+
10//! | envelope (api::Mode)     | body (negotiated api::Format)  |
11//! +--------------------------+--------------------------------+
12//! ```
13//!
14//! The envelope is a block of *headers*: a [`RequestHeader`] for messages sent
15//! by the client and a [`ResponseHeader`] for messages sent by the server. How
16//! it is spelled is decided by the [`Mode`] the socket runs in and never
17//! changes with the negotiated format. This is what makes the format negotiable
18//! at all, since both peers can always read the envelope regardless of what
19//! they have agreed on for bodies.
20//!
21//! The body is encoded with the [`Format`] identified by the `format` header of
22//! the envelope, so every message is self-describing in this respect. A `format`
23//! of zero means the message carries no body.
24//!
25//! # The protocol version
26//!
27//! Every envelope states the version of the wire protocol it was written
28//! against in its `version` header, and a peer refuses an envelope which states
29//! anything other than [`VERSION`]. The very first message each side sees
30//! carries it — [`MessageId::SERVER_HELLO`] for the client and
31//! [`MessageId::NEGOTIATE`] for the server — so a session between peers which
32//! do not speak the same protocol is rejected before either of them has acted
33//! on anything the other said.
34//!
35//! This is what a header being unknown is measured against. A version bump is
36//! the deliberate way to change what the envelope may contain, so an unknown
37//! header arriving under a version we do accept means something has gone wrong
38//! that neither peer planned for, which is why it is refused outright rather
39//! than skipped.
40//!
41//! # Headers
42//!
43//! Every header carries an unsigned integer and is addressed by a name. A
44//! header which is absent reads as zero, and headers may arrive in any order,
45//! so a message which has no use for a header simply does not write one.
46//!
47//! Both spellings are *self-delimiting*: a reader can find the end of a header
48//! it has never seen without understanding what it means. That is deliberate,
49//! and it is what makes the next rule possible.
50//!
51//! **A header which this build does not know about is refused.** It is read,
52//! stepped over so that the position of everything after it is still known, and
53//! then reported as an error which tears the connection down. A peer writing a
54//! header we have never seen is a peer speaking a protocol we do not have, and
55//! acting on the part of the message we happen to recognize would mean acting
56//! on a message we have not actually understood.
57//!
58//! A version which does not match is reported ahead of an unknown header, since
59//! the version is what explains the header.
60//!
61//! # The binary envelope
62//!
63//! In [`Mode::Binary`] each header is a tag byte followed by its value, and a
64//! tag byte of zero ends the block:
65//!
66//! ```text
67//! +-----+---------------+     +-----+
68//! | tag | value (1/2/4) | ... |  0  |
69//! +-----+---------------+     +-----+
70//! ```
71//!
72//! The low six bits of the tag are the header's id, which is never zero. The
73//! top two bits say how wide the value is — `0` for one byte, `1` for two and
74//! `2` for four, little endian — which is what lets an unknown header be
75//! stepped over. A value is written in the narrowest of those which holds it,
76//! so a small value costs no more than it has to. The remaining class is
77//! reserved, and a header which uses it cannot be skipped, so it is refused.
78//!
79//! # The text envelope
80//!
81//! In [`Mode::Text`] the envelope is instead a block of `<key>: <value>` lines
82//! terminated by an empty line, carried in a text frame:
83//!
84//! ```text
85//! version: 2
86//! serial: 1
87//! id: 1
88//! format: 5
89//! channel: 0
90//! app: 0
91//!
92//! {"message":"Hello!"}
93//! ```
94//!
95//! Every header is written, in the order it is declared, with its value in
96//! decimal. Being explicit is worth more than being terse in a spelling meant
97//! to be read by people, so a header which is zero is written out too.
98//!
99//! Nothing about the message is otherwise different, which means the mode only
100//! decides how the frame is *spelled*. Since a text frame has to be valid UTF-8
101//! in its entirety the body has to be human readable too, so [`Mode::Text`]
102//! requires a [`Format`] for which [`Format::is_human_readable`] holds. This is
103//! what [`Mode::accepts`] tests.
104//!
105//! # Negotiating the mode
106//!
107//! Unlike the format, the mode is never carried in a field. The frame type
108//! *is* the mode, so a peer can always tell which envelope it is looking at,
109//! and a message can be read before anything has been agreed on.
110//!
111//! A client sends its [`MessageId::NEGOTIATE`] request in the mode it wants,
112//! and the server replies in the mode it settled on. A server which is asked
113//! for [`Mode::Text`] together with a format it cannot carry that way settles
114//! on [`Mode::DEFAULT`], exactly like it does for a format it does not support.
115//! The client adopts whichever mode the reply arrived in, and the mode is then
116//! fixed for the lifetime of the connection.
117//!
118//! The one message which precedes all of this is
119//! [`MessageId::SERVER_HELLO`], which is always sent in [`Mode::DEFAULT`] since
120//! the server has not heard from the client yet.
121//!
122//! # Negotiating the format
123//!
124//! A client picks the [`Format`] it wants to use, defaulting to
125//! [`Format::DEFAULT`]. The exchange is:
126//!
127//! 1. The server sends [`MessageId::SERVER_HELLO`] as soon as the connection is
128//!    established. This carries no body.
129//! 2. The client responds with a [`MessageId::NEGOTIATE`] request whose
130//!    envelope carries the desired [`Format`]. This carries no body.
131//! 3. If the server supports that format it records it for the connection and
132//!    replies with an empty response whose envelope carries the format that was
133//!    accepted. If it does not, it replies with an error listing the formats it
134//!    does support, and the connection settles on [`Format::DEFAULT`].
135//!
136//! Both peers are forced through this before anything else can happen:
137//!
138//! * A client only reports itself as connected once step 3 has resolved.
139//! * A server has no way to write a message until then either, since
140//!   [`ws::Connect::connect`] is what produces the [`ws::Server`] which can, and
141//!   it does not resolve until step 3 has been flushed. Any other message
142//!   arriving in place of step 2 is a protocol violation which closes the
143//!   connection.
144//!
145//! Together this guarantees that server-initiated messages such as broadcasts
146//! are encoded with a format the client understands. The format is fixed for
147//! the lifetime of a connection, so a second negotiation is refused — a client
148//! which wants a different one reconnects.
149//!
150//! Requests additionally carry their own format in the envelope, so the server
151//! decodes each request body with the format that request declares and replies
152//! in the same format. Negotiation therefore only matters for messages the
153//! server sends on its own initiative.
154//!
155//! Since formats are gated behind [features], a server may genuinely be unable
156//! to speak a format a client asks for, which is why step 3 can fail.
157//!
158//! # Application versions
159//!
160//! [`VERSION`] only covers the envelope. The requests and broadcasts an
161//! application defines with [`define!`] are its own protocol, and a page which
162//! was loaded before the server was upgraded keeps speaking the old one for as
163//! long as it stays open. An upgrade safe [`Format`] tolerates added and
164//! missing fields, but not every change is like that.
165//!
166//! To find out, both peers can state an *application version* in the
167//! handshake: a number the application bumps whenever its API changes in a
168//! way an older peer cannot cope with, kept in a crate both sides depend on.
169//! The server states it with [`ws::Connect::app_version`] and a client with
170//! `ServiceBuilder::app_version`, in [`web`] or in [`client`].
171//!
172//! 1. The server states its version in the `app` header of
173//!    [`MessageId::SERVER_HELLO`].
174//! 2. The client compares it with its own. It always sends its
175//!    [`MessageId::NEGOTIATE`] request, stating its own version in the same
176//!    header, so that the server can tell why it goes away.
177//! 3. If the two differ the client closes the connection and reports it as
178//!    incompatible, with both versions, instead of opening it. It does not
179//!    reconnect, since that reaches the same server. A page usually responds
180//!    by reloading, which fetches the page the server is built with.
181//! 4. A server which is negotiated with by a client stating another version
182//!    refuses it with a close frame, and [`ws::Connect::connect`] fails with an
183//!    error for which [`ws::Error::is_incompatible`] holds.
184//!
185//! Zero means that no version is stated, and is what both sides default to.
186//! Versions are only compared when both peers state one, so a peer which does
187//! not opt in behaves exactly as it would without this, whatever the other
188//! one does. Every other message leaves the header at zero, which a binary
189//! envelope does not write at all.
190//!
191//! [`web`]: <https://docs.rs/musli-web/latest/musli_web/web/>
192//! [`client`]: <https://docs.rs/musli-web/latest/musli_web/client/>
193//! [`ws::Connect::app_version`]: <https://docs.rs/musli-web/latest/musli_web/ws/struct.Connect.html#method.app_version>
194//! [`ws::Error::is_incompatible`]: <https://docs.rs/musli-web/latest/musli_web/ws/struct.Error.html#method.is_incompatible>
195//!
196//! # Error responses
197//!
198//! A request which fails is answered with a response whose `error` header is
199//! non-zero, and whose body is encoded with the format the connection
200//! negotiated (rather than the one the request declared, since the request
201//! might have failed precisely because its format is not supported):
202//!
203//! * [`MessageId::ERROR_MESSAGE`] - the body is an [`ErrorMessage`], which
204//!   carries a human readable message and nothing else. This is what the server
205//!   sends when it fails a request on its own, such as one it does not support,
206//!   and for a handler error which is plain text.
207//! * [`MessageId::TYPED_ERROR_MESSAGE`] - the body is an [`ErrorMessage`]
208//!   followed by a second value, the *payload*, which is the error the handler
209//!   returned encoded the same way a response body would be. The message is
210//!   still there so that a client which does not know the type of the payload
211//!   can show something.
212//!
213//! Any other non-zero value is an error the client has no message for, which
214//! it reports as an unsupported request (or broadcast).
215//!
216//! On the server a handler opts into the typed form by failing with a
217//! [`ws::TypedError`]. A client reads the payload back with
218//! `web::Error::server_error` or `client::Error::server_error`.
219//!
220//! [features]: <https://docs.rs/musli-web/latest/musli_web/#features>
221//! [`ws::Connect::connect`]: <https://docs.rs/musli-web/latest/musli_web/ws/struct.Connect.html#method.connect>
222//! [`ws::TypedError`]: <https://docs.rs/musli-web/latest/musli_web/ws/struct.TypedError.html>
223//! [`ws::Server`]: <https://docs.rs/musli-web/latest/musli_web/ws/struct.Server.html>
224
225use core::fmt;
226use core::num::NonZeroU16;
227use core::str::FromStr;
228use core::sync::atomic::{AtomicU16, Ordering};
229
230use musli::alloc::Global;
231use musli::mode::{Binary, Text};
232use musli::{Decode, Encode};
233
234#[doc(inline)]
235pub use musli_web_macros::define;
236
237/// The version of the wire protocol this build speaks.
238///
239/// It is stated by every envelope and checked by every peer, see [the protocol
240/// version]. A peer which states anything else is refused, since there is no
241/// way to know which parts of what it said still mean what they used to.
242///
243/// [the protocol version]: crate::api#the-protocol-version
244///
245/// # History
246///
247/// * `2` - a request may fail with a typed error, see [error responses], and
248///   the handshake carries an [application version].
249/// * `1` - the first versioned protocol.
250///
251/// [error responses]: crate::api#error-responses
252/// [application version]: crate::api#application-versions
253///
254/// # Examples
255///
256/// ```
257/// use musli_web::api::VERSION;
258///
259/// assert_eq!(VERSION, 2);
260/// ```
261pub const VERSION: u32 = 2;
262
263/// The serialization format used for message bodies.
264///
265/// The format is negotiated per connection, see the [negotiation protocol] for the
266/// details of how. Message *headers* are never affected by this and always use
267/// a fixed envelope, which is what makes negotiation possible in the first
268/// place.
269///
270/// The variants are ordered from least to most capable. Each capability that is
271/// dropped makes the encoding more compact:
272///
273/// | | `reorder` | `missing` | `unknown` | `self` |
274/// |-|-|-|-|-|
275/// | [`Packed`] | ✗ | ✗ | ✗ | ✗ |
276/// | [`Storage`] | ✔ | ✔ | ✗ | ✗ |
277/// | [`Wire`] | ✔ | ✔ | ✔ | ✗ |
278/// | [`Descriptive`] | ✔ | ✔ | ✔ | ✔ |
279/// | [`Json`] | ✔ | ✔ | ✔ | ✔ |
280///
281/// * `reorder` determines whether fields may be reordered in the model.
282/// * `missing` determines whether decoding tolerates missing fields, which is
283///   what allows new optional fields to be added.
284/// * `unknown` determines whether decoding can skip fields it does not know
285///   about. A format which can do this is *fully upgrade safe*, since an old
286///   peer can talk to a new one.
287/// * `self` determines whether the format is self-descriptive, so that the data
288///   can be decoded without the model.
289///
290/// [`Packed`]: Format::Packed
291/// [`Storage`]: Format::Storage
292/// [`Wire`]: Format::Wire
293/// [`Descriptive`]: Format::Descriptive
294/// [`Json`]: Format::Json
295///
296/// # Examples
297///
298/// ```
299/// use musli_web::api::Format;
300///
301/// assert_eq!(Format::default(), Format::Wire);
302/// assert!(Format::Wire.is_upgrade_safe());
303/// assert!(!Format::Storage.is_upgrade_safe());
304/// assert!(Format::Json.is_human_readable());
305/// ```
306#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
307#[non_exhaustive]
308pub enum Format {
309    /// The [`musli::packed`] format.
310    ///
311    /// The most compact format, but it requires that both peers use exactly the
312    /// same model. Suitable when client and server are deployed together.
313    Packed,
314    /// The [`musli::storage`] format.
315    ///
316    /// Tolerates missing fields, but cannot skip fields it does not know about.
317    Storage,
318    /// The [`musli::wire`] format.
319    ///
320    /// Fully upgrade safe, so peers built against different versions of the
321    /// model can talk to each other. This is the default.
322    Wire,
323    /// The [`musli::descriptive`] format.
324    ///
325    /// Fully upgrade safe and self-descriptive, at the cost of a larger
326    /// payload.
327    Descriptive,
328    /// The [`musli::json`] format.
329    ///
330    /// Human readable, which is useful when the traffic has to be inspected by
331    /// hand. Encoded using the [`Text`] mode so that fields are keyed by name.
332    ///
333    /// [`Text`]: musli::mode::Text
334    Json,
335}
336
337impl Format {
338    /// The default format, which is [`Format::Wire`].
339    ///
340    /// This is used by a client which has not picked a format, and by a server
341    /// for a connection which has not negotiated one.
342    ///
343    /// # Examples
344    ///
345    /// ```
346    /// use musli_web::api::Format;
347    ///
348    /// assert_eq!(Format::DEFAULT, Format::Wire);
349    /// ```
350    pub const DEFAULT: Self = Self::Wire;
351
352    /// Every format in order of increasing capability.
353    ///
354    /// Note that this includes formats which the crate might not have been
355    /// built with support for, see [`Format::is_supported`].
356    ///
357    /// # Examples
358    ///
359    /// ```
360    /// use musli_web::api::Format;
361    ///
362    /// assert!(Format::ALL.contains(&Format::Json));
363    /// ```
364    pub const ALL: &'static [Format] = &[
365        Format::Packed,
366        Format::Storage,
367        Format::Wire,
368        Format::Descriptive,
369        Format::Json,
370    ];
371
372    /// Get the stable identifier used for this format on the wire.
373    ///
374    /// Zero is never used, so it is available to indicate an absent format.
375    ///
376    /// # Examples
377    ///
378    /// ```
379    /// use musli_web::api::Format;
380    ///
381    /// assert_eq!(Format::Wire.to_u8(), 3);
382    /// assert_eq!(Format::from_u8(3), Some(Format::Wire));
383    /// ```
384    #[inline]
385    pub const fn to_u8(self) -> u8 {
386        match self {
387            Format::Packed => 1,
388            Format::Storage => 2,
389            Format::Wire => 3,
390            Format::Descriptive => 4,
391            Format::Json => 5,
392        }
393    }
394
395    /// Construct a format from the stable identifier used on the wire.
396    ///
397    /// Returns `None` if the identifier is not known, which is how a peer
398    /// built against an older version of this crate reports a format it has
399    /// never heard of.
400    ///
401    /// # Examples
402    ///
403    /// ```
404    /// use musli_web::api::Format;
405    ///
406    /// assert_eq!(Format::from_u8(1), Some(Format::Packed));
407    /// assert_eq!(Format::from_u8(0), None);
408    /// assert_eq!(Format::from_u8(200), None);
409    /// ```
410    #[inline]
411    pub const fn from_u8(id: u8) -> Option<Self> {
412        match id {
413            1 => Some(Format::Packed),
414            2 => Some(Format::Storage),
415            3 => Some(Format::Wire),
416            4 => Some(Format::Descriptive),
417            5 => Some(Format::Json),
418            _ => None,
419        }
420    }
421
422    /// The name of the format.
423    ///
424    /// # Examples
425    ///
426    /// ```
427    /// use musli_web::api::Format;
428    ///
429    /// assert_eq!(Format::Wire.name(), "wire");
430    /// ```
431    #[inline]
432    pub const fn name(self) -> &'static str {
433        match self {
434            Format::Packed => "packed",
435            Format::Storage => "storage",
436            Format::Wire => "wire",
437            Format::Descriptive => "descriptive",
438            Format::Json => "json",
439        }
440    }
441
442    /// Test if the format can skip over unknown fields, making it fully upgrade
443    /// safe.
444    ///
445    /// # Examples
446    ///
447    /// ```
448    /// use musli_web::api::Format;
449    ///
450    /// assert!(Format::Wire.is_upgrade_safe());
451    /// assert!(!Format::Packed.is_upgrade_safe());
452    /// ```
453    #[inline]
454    pub const fn is_upgrade_safe(self) -> bool {
455        matches!(self, Format::Wire | Format::Descriptive | Format::Json)
456    }
457
458    /// Test if the format is self-descriptive, so that data can be decoded
459    /// without access to the model.
460    ///
461    /// # Examples
462    ///
463    /// ```
464    /// use musli_web::api::Format;
465    ///
466    /// assert!(Format::Descriptive.is_self_descriptive());
467    /// assert!(!Format::Wire.is_self_descriptive());
468    /// ```
469    #[inline]
470    pub const fn is_self_descriptive(self) -> bool {
471        matches!(self, Format::Descriptive | Format::Json)
472    }
473
474    /// Test if the format produces output which is meant to be read by humans.
475    ///
476    /// # Examples
477    ///
478    /// ```
479    /// use musli_web::api::Format;
480    ///
481    /// assert!(Format::Json.is_human_readable());
482    /// assert!(!Format::Wire.is_human_readable());
483    /// ```
484    #[inline]
485    pub const fn is_human_readable(self) -> bool {
486        matches!(self, Format::Json)
487    }
488}
489
490impl Default for Format {
491    /// Construct the default format, which is [`Format::DEFAULT`].
492    ///
493    /// # Examples
494    ///
495    /// ```
496    /// use musli_web::api::Format;
497    ///
498    /// assert_eq!(Format::default(), Format::Wire);
499    /// ```
500    #[inline]
501    fn default() -> Self {
502        Self::DEFAULT
503    }
504}
505
506impl fmt::Display for Format {
507    #[inline]
508    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509        f.write_str(self.name())
510    }
511}
512
513/// The error returned when parsing a [`Format`] from a string which is not the
514/// [`name`] of any format.
515///
516/// [`name`]: Format::name
517///
518/// # Examples
519///
520/// ```
521/// use musli_web::api::Format;
522///
523/// let error = "yaml".parse::<Format>().unwrap_err();
524/// assert_eq!(error.to_string(), "unknown format, expected one of: packed, storage, wire, descriptive, json");
525/// ```
526#[derive(Debug, Clone, Copy, PartialEq, Eq)]
527#[non_exhaustive]
528pub struct ParseFormatError;
529
530impl fmt::Display for ParseFormatError {
531    #[inline]
532    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533        f.write_str("unknown format, expected one of: packed, storage, wire, descriptive, json")
534    }
535}
536
537impl core::error::Error for ParseFormatError {}
538
539impl FromStr for Format {
540    type Err = ParseFormatError;
541
542    /// Parse a format from exactly what its [`Display`] implementation and
543    /// [`Format::name`] produce.
544    ///
545    /// Matching is case sensitive and does not trim whitespace.
546    ///
547    /// [`Display`]: fmt::Display
548    ///
549    /// # Examples
550    ///
551    /// ```
552    /// use musli_web::api::Format;
553    ///
554    /// assert_eq!("wire".parse::<Format>(), Ok(Format::Wire));
555    /// assert!("Wire".parse::<Format>().is_err());
556    ///
557    /// for format in Format::ALL {
558    ///     assert_eq!(format.to_string().parse::<Format>(), Ok(*format));
559    /// }
560    /// ```
561    fn from_str(s: &str) -> Result<Self, Self::Err> {
562        for &format in Self::ALL {
563            if format.name() == s {
564                return Ok(format);
565            }
566        }
567
568        Err(ParseFormatError)
569    }
570}
571
572/// How a socket frames the messages it carries.
573///
574/// This picks between the two shapes a message can have on the wire. It is
575/// orthogonal to the [`Format`] which bodies are encoded with, except that
576/// [`Mode::Text`] requires a human readable one, see the [text envelope].
577///
578/// [text envelope]: crate::api#the-text-envelope
579///
580/// # Examples
581///
582/// ```
583/// use musli_web::api::Mode;
584///
585/// assert_eq!(Mode::default(), Mode::Binary);
586/// assert!(Mode::Text.is_text());
587/// ```
588#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
589#[non_exhaustive]
590pub enum Mode {
591    /// Messages are binary frames whose envelope is encoded with
592    /// [`musli::packed`].
593    ///
594    /// This is the compact representation and the default.
595    Binary,
596    /// Messages are text frames whose envelope is a block of
597    /// `<key>: <value>` lines.
598    ///
599    /// The whole frame is human readable, which is what makes it possible to
600    /// read the traffic in a browser inspector or a proxy. Since the body is
601    /// part of that frame it has to be human readable too, so this requires a
602    /// [`Format`] for which [`Format::is_human_readable`] holds.
603    Text,
604}
605
606impl Mode {
607    /// The default mode, which is [`Mode::Binary`].
608    ///
609    /// This is used by a client which has not picked a mode, and by a server
610    /// for a connection which has not negotiated one.
611    ///
612    /// # Examples
613    ///
614    /// ```
615    /// use musli_web::api::Mode;
616    ///
617    /// assert_eq!(Mode::DEFAULT, Mode::Binary);
618    /// ```
619    pub const DEFAULT: Self = Self::Binary;
620
621    /// Every mode a socket can run in.
622    ///
623    /// # Examples
624    ///
625    /// ```
626    /// use musli_web::api::Mode;
627    ///
628    /// assert!(Mode::ALL.contains(&Mode::Text));
629    /// ```
630    pub const ALL: &'static [Mode] = &[Mode::Binary, Mode::Text];
631
632    /// The name of the mode.
633    ///
634    /// # Examples
635    ///
636    /// ```
637    /// use musli_web::api::Mode;
638    ///
639    /// assert_eq!(Mode::Text.name(), "text");
640    /// ```
641    #[inline]
642    pub const fn name(self) -> &'static str {
643        match self {
644            Mode::Binary => "binary",
645            Mode::Text => "text",
646        }
647    }
648
649    /// Test if the mode uses text frames.
650    ///
651    /// # Examples
652    ///
653    /// ```
654    /// use musli_web::api::Mode;
655    ///
656    /// assert!(Mode::Text.is_text());
657    /// assert!(!Mode::Binary.is_text());
658    /// ```
659    #[inline]
660    pub const fn is_text(self) -> bool {
661        matches!(self, Mode::Text)
662    }
663
664    /// Test if `format` can be used for message bodies in this mode.
665    ///
666    /// A text frame has to be valid UTF-8 in its entirety, so a mode which
667    /// uses them can only carry bodies which are human readable.
668    ///
669    /// # Examples
670    ///
671    /// ```
672    /// use musli_web::api::{Format, Mode};
673    ///
674    /// assert!(Mode::Binary.accepts(Format::Wire));
675    /// assert!(Mode::Text.accepts(Format::Json));
676    /// assert!(!Mode::Text.accepts(Format::Wire));
677    /// ```
678    #[inline]
679    pub const fn accepts(self, format: Format) -> bool {
680        match self {
681            Mode::Binary => true,
682            Mode::Text => format.is_human_readable(),
683        }
684    }
685
686    /// A dense index for the mode, so that it can be kept in an atomic.
687    ///
688    /// This is not a wire representation, the frame type is what carries the
689    /// mode between peers.
690    #[inline]
691    #[cfg_attr(not(feature = "client"), allow(dead_code))]
692    pub(crate) const fn to_index(self) -> u8 {
693        match self {
694            Mode::Binary => 0,
695            Mode::Text => 1,
696        }
697    }
698
699    /// Recover a mode from [`Mode::to_index`].
700    #[inline]
701    #[cfg_attr(not(feature = "client"), allow(dead_code))]
702    pub(crate) const fn from_index(index: u8) -> Option<Self> {
703        match index {
704            0 => Some(Mode::Binary),
705            1 => Some(Mode::Text),
706            _ => None,
707        }
708    }
709}
710
711impl Default for Mode {
712    /// Construct the default mode, which is [`Mode::DEFAULT`].
713    ///
714    /// # Examples
715    ///
716    /// ```
717    /// use musli_web::api::Mode;
718    ///
719    /// assert_eq!(Mode::default(), Mode::Binary);
720    /// ```
721    #[inline]
722    fn default() -> Self {
723        Self::DEFAULT
724    }
725}
726
727impl fmt::Display for Mode {
728    #[inline]
729    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
730        f.write_str(self.name())
731    }
732}
733
734/// The error returned when parsing a [`Mode`] from a string which is not the
735/// [`name`] of any mode.
736///
737/// [`name`]: Mode::name
738///
739/// # Examples
740///
741/// ```
742/// use musli_web::api::Mode;
743///
744/// let error = "both".parse::<Mode>().unwrap_err();
745/// assert_eq!(error.to_string(), "unknown mode, expected one of: binary, text");
746/// ```
747#[derive(Debug, Clone, Copy, PartialEq, Eq)]
748#[non_exhaustive]
749pub struct ParseModeError;
750
751impl fmt::Display for ParseModeError {
752    #[inline]
753    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
754        f.write_str("unknown mode, expected one of: binary, text")
755    }
756}
757
758impl core::error::Error for ParseModeError {}
759
760impl FromStr for Mode {
761    type Err = ParseModeError;
762
763    /// Parse a mode from exactly what its [`Display`] implementation and
764    /// [`Mode::name`] produce.
765    ///
766    /// Matching is case sensitive and does not trim whitespace.
767    ///
768    /// [`Display`]: fmt::Display
769    ///
770    /// # Examples
771    ///
772    /// ```
773    /// use musli_web::api::Mode;
774    ///
775    /// assert_eq!("text".parse::<Mode>(), Ok(Mode::Text));
776    /// assert!("Text".parse::<Mode>().is_err());
777    ///
778    /// for mode in Mode::ALL {
779    ///     assert_eq!(mode.to_string().parse::<Mode>(), Ok(*mode));
780    /// }
781    /// ```
782    fn from_str(s: &str) -> Result<Self, Self::Err> {
783        for &mode in Self::ALL {
784            if mode.name() == s {
785                return Ok(mode);
786            }
787        }
788
789        Err(ParseModeError)
790    }
791}
792
793/// Types which can be encoded in every mode that this crate supports.
794///
795/// This is a blanket trait covering [`Encode`] in both the [`Binary`] and
796/// [`Text`] modes, which is what allows a message body to be encoded with any
797/// [`Format`] including [`Format::Json`].
798///
799/// Deriving [`Encode`] implements every mode, so this is implemented
800/// automatically unless the type has been restricted to a specific mode.
801pub trait EncodeBody
802where
803    Self: Encode<Binary> + Encode<Text>,
804{
805}
806
807impl<T> EncodeBody for T where T: ?Sized + Encode<Binary> + Encode<Text> {}
808
809/// Types which can be decoded in every mode that this crate supports.
810///
811/// This is a blanket trait covering [`Decode`] in both the [`Binary`] and
812/// [`Text`] modes, which is what allows a message body to be decoded with any
813/// [`Format`] including [`Format::Json`].
814///
815/// Deriving [`Decode`] implements every mode, so this is implemented
816/// automatically unless the type has been restricted to a specific mode.
817pub trait DecodeBody<'de>
818where
819    Self: Decode<'de, Binary, Global> + Decode<'de, Text, Global>,
820{
821}
822
823impl<'de, T> DecodeBody<'de> for T where T: Decode<'de, Binary, Global> + Decode<'de, Text, Global> {}
824
825/// A trait for constructing identifiers.
826///
827/// This is implemented by the `Request` and `Event` enums generated by
828/// [`define!`], and by [`ws::Either`] for a [`ws::Or`] handler.
829///
830/// [`ws::Either`]: <https://docs.rs/musli-web/latest/musli_web/ws/enum.Either.html>
831/// [`ws::Or`]: <https://docs.rs/musli-web/latest/musli_web/ws/struct.Or.html>
832pub trait Id
833where
834    Self: 'static + Send + Sized + fmt::Debug,
835{
836    /// The message ids this type knows.
837    ///
838    /// For a `Request` enum generated by [`define!`] these are the ids of its
839    /// endpoints, and for an `Event` enum those of its broadcasts, in both
840    /// cases along with those of every list it [includes]. An id outside of
841    /// this set is what [`Id::from_id`] constructs an unknown identifier for.
842    ///
843    /// [includes]: define#including-other-lists
844    ///
845    /// # Examples
846    ///
847    /// ```
848    /// use musli::{Decode, Encode};
849    /// use musli_web::api::{self, Id};
850    ///
851    /// #[derive(Encode, Decode)]
852    /// pub struct HelloRequest;
853    ///
854    /// #[derive(Encode, Decode)]
855    /// pub struct TickEvent;
856    ///
857    /// api::define! {
858    ///     pub type Hello;
859    ///
860    ///     impl Endpoint for Hello {
861    ///         impl Request for HelloRequest;
862    ///         type Response<'de> = ();
863    ///     }
864    ///
865    ///     pub type Tick;
866    ///
867    ///     impl Broadcast for Tick {
868    ///         impl Event for TickEvent;
869    ///     }
870    /// }
871    ///
872    /// assert!(Request::IDS.contains(Hello::ID));
873    /// assert!(!Request::IDS.contains(Tick::ID));
874    /// assert!(Event::IDS.contains(Tick::ID));
875    /// ```
876    const IDS: IdSet;
877
878    /// Get the raw message identifier for this type.
879    fn id(&self) -> MessageId;
880
881    /// Construct an identifier from a raw message identifier.
882    ///
883    /// An id which is not in [`Id::IDS`] constructs an unknown identifier,
884    /// such as the `Unknown` variant of a `Request` enum generated by
885    /// [`define!`].
886    fn from_id(id: MessageId) -> Self;
887
888    /// Construct an identifier from a raw message identifier, or `None` if
889    /// the id is not in [`Id::IDS`].
890    ///
891    /// # Examples
892    ///
893    /// ```
894    /// use musli::{Decode, Encode};
895    /// use musli_web::api::{self, Id, MessageId};
896    ///
897    /// #[derive(Encode, Decode)]
898    /// pub struct HelloRequest;
899    ///
900    /// api::define! {
901    ///     pub type Hello;
902    ///
903    ///     impl Endpoint for Hello {
904    ///         impl Request for HelloRequest;
905    ///         type Response<'de> = ();
906    ///     }
907    /// }
908    ///
909    /// assert_eq!(Request::try_from_id(Hello::ID), Some(Request::Hello));
910    ///
911    /// let unknown = MessageId::new(1000).unwrap();
912    /// assert_eq!(Request::try_from_id(unknown), None);
913    /// assert_eq!(Request::from_id(unknown), Request::Unknown(unknown));
914    /// ```
915    fn try_from_id(id: MessageId) -> Option<Self>;
916
917    #[doc(hidden)]
918    fn __do_not_implement_id();
919}
920
921/// A set of message ids, such as the ids an [`Id`] type knows, see
922/// [`Id::IDS`].
923///
924/// A set is built at compile time out of the ids of one [`define!`] list and
925/// the sets of the lists it includes, so it is cheap to construct but looking
926/// an id up in it is a linear scan. It is used to check, at compile time, that
927/// two lists which share a connection never use the same id.
928///
929/// # Examples
930///
931/// Checking in a test (or a `const` item) that two lists which are never
932/// included into one another, but are carried on the same connection, do not
933/// share an id:
934///
935/// ```
936/// use musli::{Decode, Encode};
937/// use musli_web::api::Id;
938///
939/// mod app {
940///     # use musli::{Decode, Encode};
941///     # use musli_web::api;
942///     #[derive(Encode, Decode)]
943///     pub struct HelloRequest;
944///
945///     api::define! {
946///         pub type Hello;
947///
948///         impl Endpoint for Hello {
949///             impl Request for HelloRequest;
950///             type Response<'de> = ();
951///         }
952///     }
953/// }
954///
955/// mod lib {
956///     # use musli::{Decode, Encode};
957///     # use musli_web::api;
958///     #[derive(Encode, Decode)]
959///     pub struct LoginRequest;
960///
961///     api::define! {
962///         #[musli(id = 32000)]
963///         pub type Login;
964///
965///         impl Endpoint for Login {
966///             impl Request for LoginRequest;
967///             type Response<'de> = ();
968///         }
969///     }
970/// }
971///
972/// const _: () = assert!(app::Request::IDS.is_disjoint(&lib::Request::IDS));
973/// assert_eq!(app::Request::IDS.first_shared(&lib::Request::IDS), None);
974/// ```
975#[derive(Clone, Copy)]
976pub struct IdSet {
977    #[doc(hidden)]
978    pub __ids: &'static [MessageId],
979    #[doc(hidden)]
980    pub __includes: &'static [&'static IdSet],
981}
982
983impl IdSet {
984    /// The empty set.
985    pub const EMPTY: Self = Self {
986        __ids: &[],
987        __includes: &[],
988    };
989
990    /// Test if the set contains `id`.
991    pub const fn contains(&self, id: MessageId) -> bool {
992        let mut n = 0;
993
994        while n < self.__ids.len() {
995            if self.__ids[n].get() == id.get() {
996                return true;
997            }
998
999            n += 1;
1000        }
1001
1002        let mut n = 0;
1003
1004        while n < self.__includes.len() {
1005            if self.__includes[n].contains(id) {
1006                return true;
1007            }
1008
1009            n += 1;
1010        }
1011
1012        false
1013    }
1014
1015    /// Test if the set has no id in common with `other`.
1016    #[inline]
1017    pub const fn is_disjoint(&self, other: &IdSet) -> bool {
1018        self.first_shared(other).is_none()
1019    }
1020
1021    /// Find the first id in this set which is also in `other`, if any.
1022    pub const fn first_shared(&self, other: &IdSet) -> Option<MessageId> {
1023        let mut n = 0;
1024
1025        while n < self.__ids.len() {
1026            let id = self.__ids[n];
1027
1028            if other.contains(id) {
1029                return Some(id);
1030            }
1031
1032            n += 1;
1033        }
1034
1035        let mut n = 0;
1036
1037        while n < self.__includes.len() {
1038            if let Some(id) = self.__includes[n].first_shared(other) {
1039                return Some(id);
1040            }
1041
1042            n += 1;
1043        }
1044
1045        None
1046    }
1047
1048    /// Test if the set is empty.
1049    pub const fn is_empty(&self) -> bool {
1050        if !self.__ids.is_empty() {
1051            return false;
1052        }
1053
1054        let mut n = 0;
1055
1056        while n < self.__includes.len() {
1057            if !self.__includes[n].is_empty() {
1058                return false;
1059            }
1060
1061            n += 1;
1062        }
1063
1064        true
1065    }
1066}
1067
1068impl fmt::Debug for IdSet {
1069    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1070        fn entries(set: &IdSet, list: &mut fmt::DebugSet<'_, '_>) {
1071            list.entries(set.__ids.iter().map(MessageId::get));
1072
1073            for include in set.__includes {
1074                entries(include, list);
1075            }
1076        }
1077
1078        let mut list = f.debug_set();
1079        entries(self, &mut list);
1080        list.finish()
1081    }
1082}
1083
1084/// A unique and opaque identifier for a channel over the websocket.
1085#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
1086#[musli(transparent)]
1087pub struct ChannelId {
1088    repr: u16,
1089}
1090
1091impl ChannelId {
1092    /// The channel id used for an invalid channel.
1093    pub const NONE: Self = Self::from_u16(0);
1094
1095    /// Construct a new channel id from a raw `u16` representation.
1096    ///
1097    /// Note that this does not guarantee that the internal representation of a
1098    /// channel identifier is exactly a `u16`, only that at least `u16` unique
1099    /// identifiers can be constructed.
1100    ///
1101    /// Using `0` is equivalent to [`ChannelId::NONE`]. When implementing a
1102    /// custom [`ChannelAllocator`] the allocator must avoid constructor
1103    /// identifiers with this value since it is equivalent to no channel.
1104    ///
1105    /// [`ChannelAllocator`]: crate::ws::ChannelAllocator
1106    ///
1107    /// # Examples
1108    ///
1109    /// ```
1110    /// use musli_web::api::ChannelId;
1111    /// let id = ChannelId::from_u16(0);
1112    /// assert_eq!(id, ChannelId::NONE);
1113    /// ```
1114    #[inline]
1115    pub const fn from_u16(repr: u16) -> Self {
1116        Self { repr }
1117    }
1118
1119    /// Get the raw channel identifier.
1120    #[inline]
1121    #[cfg_attr(
1122        not(any(feature = "ws", feature = "client", feature = "web03")),
1123        allow(dead_code)
1124    )]
1125    pub(crate) const fn raw(&self) -> u16 {
1126        self.repr
1127    }
1128}
1129
1130impl fmt::Debug for ChannelId {
1131    #[inline]
1132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1133        if self.repr == 0 {
1134            f.write_str("NONE")
1135        } else {
1136            write!(f, "{:04x}", self.repr)
1137        }
1138    }
1139}
1140
1141/// A [`ChannelId`] which can be shared and updated atomically.
1142///
1143/// This behaves like an atomic variable holding a [`ChannelId`], where the
1144/// value can be read, set, replaced, or taken. Each operation takes an
1145/// [`Ordering`] which is passed through to the underlying atomic.
1146///
1147/// [`Ordering`]: core::sync::atomic::Ordering
1148///
1149/// # Examples
1150///
1151/// ```
1152/// use core::sync::atomic::Ordering;
1153///
1154/// use musli_web::api::{AtomicChannelId, ChannelId};
1155///
1156/// let channel = AtomicChannelId::NONE;
1157/// assert_eq!(channel.load(Ordering::Acquire), ChannelId::NONE);
1158///
1159/// channel.store(ChannelId::from_u16(42), Ordering::Release);
1160/// assert_eq!(channel.load(Ordering::Acquire), ChannelId::from_u16(42));
1161///
1162/// assert_eq!(channel.take(Ordering::AcqRel), ChannelId::from_u16(42));
1163/// assert_eq!(channel.load(Ordering::Acquire), ChannelId::NONE);
1164/// ```
1165#[repr(transparent)]
1166pub struct AtomicChannelId {
1167    repr: AtomicU16,
1168}
1169
1170impl AtomicChannelId {
1171    /// An atomic channel id which contains [`ChannelId::NONE`].
1172    ///
1173    /// Since this is a constant every use of it constructs a new value, to
1174    /// share one it has to be bound to a `static` or a variable.
1175    ///
1176    /// # Examples
1177    ///
1178    /// ```
1179    /// use core::sync::atomic::Ordering;
1180    ///
1181    /// use musli_web::api::{AtomicChannelId, ChannelId};
1182    ///
1183    /// let channel = AtomicChannelId::NONE;
1184    /// assert_eq!(channel.load(Ordering::Acquire), ChannelId::NONE);
1185    /// ```
1186    #[allow(clippy::declare_interior_mutable_const)]
1187    pub const NONE: Self = Self::new(ChannelId::NONE);
1188
1189    /// Construct a new atomic channel id containing `id`.
1190    ///
1191    /// # Examples
1192    ///
1193    /// ```
1194    /// use core::sync::atomic::Ordering;
1195    ///
1196    /// use musli_web::api::{AtomicChannelId, ChannelId};
1197    ///
1198    /// let channel = AtomicChannelId::new(ChannelId::from_u16(1));
1199    /// assert_eq!(channel.load(Ordering::Acquire), ChannelId::from_u16(1));
1200    /// ```
1201    #[inline]
1202    pub const fn new(id: ChannelId) -> Self {
1203        Self {
1204            repr: AtomicU16::new(id.repr),
1205        }
1206    }
1207
1208    /// Read the current channel id.
1209    ///
1210    /// `ordering` describes the memory ordering of this operation. Possible
1211    /// values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
1212    ///
1213    /// [`SeqCst`]: Ordering::SeqCst
1214    /// [`Acquire`]: Ordering::Acquire
1215    /// [`Relaxed`]: Ordering::Relaxed
1216    ///
1217    /// # Panics
1218    ///
1219    /// Panics if `ordering` is [`Release`] or [`AcqRel`].
1220    ///
1221    /// [`Release`]: Ordering::Release
1222    /// [`AcqRel`]: Ordering::AcqRel
1223    ///
1224    /// # Examples
1225    ///
1226    /// ```
1227    /// use core::sync::atomic::Ordering;
1228    ///
1229    /// use musli_web::api::{AtomicChannelId, ChannelId};
1230    ///
1231    /// let channel = AtomicChannelId::new(ChannelId::from_u16(1));
1232    /// assert_eq!(channel.load(Ordering::Acquire), ChannelId::from_u16(1));
1233    /// ```
1234    #[inline]
1235    pub fn load(&self, ordering: Ordering) -> ChannelId {
1236        ChannelId::from_u16(self.repr.load(ordering))
1237    }
1238
1239    /// Set the current channel id to `id`, discarding the old value.
1240    ///
1241    /// `ordering` describes the memory ordering of this operation. Possible
1242    /// values are [`SeqCst`], [`Release`] and [`Relaxed`].
1243    ///
1244    /// [`SeqCst`]: Ordering::SeqCst
1245    /// [`Release`]: Ordering::Release
1246    /// [`Relaxed`]: Ordering::Relaxed
1247    ///
1248    /// # Panics
1249    ///
1250    /// Panics if `ordering` is [`Acquire`] or [`AcqRel`].
1251    ///
1252    /// [`Acquire`]: Ordering::Acquire
1253    /// [`AcqRel`]: Ordering::AcqRel
1254    ///
1255    /// # Examples
1256    ///
1257    /// ```
1258    /// use core::sync::atomic::Ordering;
1259    ///
1260    /// use musli_web::api::{AtomicChannelId, ChannelId};
1261    ///
1262    /// let channel = AtomicChannelId::NONE;
1263    /// channel.store(ChannelId::from_u16(1), Ordering::Release);
1264    /// assert_eq!(channel.load(Ordering::Acquire), ChannelId::from_u16(1));
1265    /// ```
1266    #[inline]
1267    pub fn store(&self, id: ChannelId, ordering: Ordering) {
1268        self.repr.store(id.repr, ordering);
1269    }
1270
1271    /// Replace the current channel id with `id`, returning the old value.
1272    ///
1273    /// `ordering` describes the memory ordering of this operation. All
1274    /// orderings are possible. Note that using [`Acquire`] makes the store part
1275    /// of this operation [`Relaxed`], and using [`Release`] makes the load part
1276    /// [`Relaxed`].
1277    ///
1278    /// [`Acquire`]: Ordering::Acquire
1279    /// [`Release`]: Ordering::Release
1280    /// [`Relaxed`]: Ordering::Relaxed
1281    ///
1282    /// # Examples
1283    ///
1284    /// ```
1285    /// use core::sync::atomic::Ordering;
1286    ///
1287    /// use musli_web::api::{AtomicChannelId, ChannelId};
1288    ///
1289    /// let channel = AtomicChannelId::new(ChannelId::from_u16(1));
1290    ///
1291    /// let old = channel.replace(ChannelId::from_u16(2), Ordering::AcqRel);
1292    /// assert_eq!(old, ChannelId::from_u16(1));
1293    /// assert_eq!(channel.load(Ordering::Acquire), ChannelId::from_u16(2));
1294    /// ```
1295    #[inline]
1296    pub fn replace(&self, id: ChannelId, ordering: Ordering) -> ChannelId {
1297        ChannelId::from_u16(self.repr.swap(id.repr, ordering))
1298    }
1299
1300    /// Take the current channel id, leaving [`ChannelId::NONE`] in its place.
1301    ///
1302    /// `ordering` describes the memory ordering of this operation. All
1303    /// orderings are possible, see [`replace`] for details.
1304    ///
1305    /// [`replace`]: AtomicChannelId::replace
1306    ///
1307    /// # Examples
1308    ///
1309    /// ```
1310    /// use core::sync::atomic::Ordering;
1311    ///
1312    /// use musli_web::api::{AtomicChannelId, ChannelId};
1313    ///
1314    /// let channel = AtomicChannelId::new(ChannelId::from_u16(1));
1315    ///
1316    /// assert_eq!(channel.take(Ordering::AcqRel), ChannelId::from_u16(1));
1317    /// assert_eq!(channel.load(Ordering::Acquire), ChannelId::NONE);
1318    /// assert_eq!(channel.take(Ordering::AcqRel), ChannelId::NONE);
1319    /// ```
1320    #[inline]
1321    pub fn take(&self, ordering: Ordering) -> ChannelId {
1322        self.replace(ChannelId::NONE, ordering)
1323    }
1324
1325    /// Consume the atomic channel id, returning the contained value.
1326    ///
1327    /// Since this takes ownership no synchronization is needed.
1328    ///
1329    /// # Examples
1330    ///
1331    /// ```
1332    /// use musli_web::api::{AtomicChannelId, ChannelId};
1333    ///
1334    /// let channel = AtomicChannelId::new(ChannelId::from_u16(1));
1335    /// assert_eq!(channel.into_inner(), ChannelId::from_u16(1));
1336    /// ```
1337    #[inline]
1338    pub fn into_inner(self) -> ChannelId {
1339        ChannelId::from_u16(self.repr.into_inner())
1340    }
1341}
1342
1343impl Default for AtomicChannelId {
1344    /// Construct an atomic channel id containing [`ChannelId::NONE`].
1345    ///
1346    /// # Examples
1347    ///
1348    /// ```
1349    /// use core::sync::atomic::Ordering;
1350    ///
1351    /// use musli_web::api::{AtomicChannelId, ChannelId};
1352    ///
1353    /// let channel = AtomicChannelId::default();
1354    /// assert_eq!(channel.load(Ordering::Acquire), ChannelId::NONE);
1355    /// ```
1356    #[inline]
1357    fn default() -> Self {
1358        Self::NONE
1359    }
1360}
1361
1362impl From<ChannelId> for AtomicChannelId {
1363    #[inline]
1364    fn from(id: ChannelId) -> Self {
1365        Self::new(id)
1366    }
1367}
1368
1369impl fmt::Debug for AtomicChannelId {
1370    #[inline]
1371    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1372        self.load(Ordering::Relaxed).fmt(f)
1373    }
1374}
1375
1376/// A raw identifier for a message.
1377#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
1378#[repr(transparent)]
1379#[musli(transparent)]
1380pub struct MessageId(NonZeroU16);
1381
1382impl fmt::Display for MessageId {
1383    #[inline]
1384    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1385        self.0.fmt(f)
1386    }
1387}
1388
1389impl MessageId {
1390    /// The error id of a response whose body is an [`ErrorMessage`].
1391    ///
1392    /// See [error responses](crate::api#error-responses).
1393    pub const ERROR_MESSAGE: Self = unsafe { Self::new_unchecked((i16::MAX as u16) + 1) };
1394
1395    /// A connect of a channel.
1396    pub const CONNECT: Self = unsafe { Self::new_unchecked((i16::MAX as u16) + 2) };
1397
1398    /// A clean disconnect of a channel.
1399    pub const DISCONNECT: Self = unsafe { Self::new_unchecked((i16::MAX as u16) + 3) };
1400
1401    /// The first message the server sends to indicat that a connection is open.
1402    pub const SERVER_HELLO: Self = unsafe { Self::new_unchecked((i16::MAX as u16) + 4) };
1403
1404    /// A request from the client to use a particular [`Format`] for the
1405    /// remainder of the connection.
1406    ///
1407    /// See the [negotiation protocol] for how this is used.
1408    pub const NEGOTIATE: Self = unsafe { Self::new_unchecked((i16::MAX as u16) + 5) };
1409
1410    /// The error id of a response whose body is an [`ErrorMessage`] followed by
1411    /// a typed payload.
1412    ///
1413    /// See [error responses](crate::api#error-responses).
1414    pub const TYPED_ERROR_MESSAGE: Self = unsafe { Self::new_unchecked((i16::MAX as u16) + 6) };
1415
1416    /// The message id for an empty packet constructed using [`Packet::empty`]
1417    /// or [`RawPacket::empty`].
1418    ///
1419    /// [`Packet::empty`]: crate::web::Packet::empty
1420    /// [`RawPacket::empty`]: crate::web::RawPacket::empty
1421    ///
1422    /// # Examples
1423    ///
1424    /// ```
1425    /// use musli_web::api::MessageId;
1426    /// use musli_web::web::{RawPacket, Packet};
1427    ///
1428    /// let packet = RawPacket::empty();
1429    /// assert_eq!(packet.id(), MessageId::EMPTY);
1430    ///
1431    /// let packet = Packet::<()>::empty();
1432    /// assert_eq!(packet.id(), MessageId::EMPTY);
1433    /// ```
1434    pub const EMPTY: Self = unsafe { Self::new_unchecked(u16::MAX) };
1435
1436    /// Construct a raw message id.
1437    #[inline]
1438    pub const fn new(id: u16) -> Option<Self> {
1439        let Some(value) = NonZeroU16::new(id) else {
1440            return None;
1441        };
1442
1443        Some(Self(value))
1444    }
1445
1446    /// Get a raw message identifier.
1447    #[inline]
1448    pub const fn get(&self) -> u16 {
1449        self.0.get()
1450    }
1451
1452    /// Construct a new message ID.
1453    ///
1454    /// # Safety
1455    ///
1456    /// The caller must ensure that the provided `id` is non-zero.
1457    #[inline]
1458    pub const unsafe fn new_unchecked(id: u16) -> Self {
1459        Self(unsafe { NonZeroU16::new_unchecked(id) })
1460    }
1461}
1462
1463/// A trait implemented for types which can be decoded into something.
1464///
1465/// Do not implement manually, instead use the [`define!`] macro.
1466pub trait Decodable {
1467    /// The decodable type related to this.
1468    type Type<'de>: DecodeBody<'de>;
1469
1470    #[doc(hidden)]
1471    fn __do_not_implement_decodable();
1472}
1473
1474/// An endpoint marker trait.
1475///
1476/// Do not implement manually, instead use the [`define!`] macro.
1477pub trait Endpoint
1478where
1479    Self: 'static,
1480    for<'de> Self: Decodable<Type<'de> = Self::Response<'de>>,
1481{
1482    /// The kind of the endpoint.
1483    const ID: MessageId;
1484
1485    /// The primary response type related to the endpoint.
1486    type Response<'de>: DecodeBody<'de>;
1487
1488    #[doc(hidden)]
1489    fn __do_not_implement_endpoint();
1490}
1491
1492/// The marker trait used for broadcasts.
1493///
1494/// Do not implement manually, instead use the [`define!`] macro.
1495pub trait Broadcast
1496where
1497    Self: 'static,
1498{
1499    /// The kind of the broadcast.
1500    const ID: MessageId;
1501
1502    #[doc(hidden)]
1503    fn __do_not_implement_broadcast();
1504}
1505
1506/// Trait implemented for broadcasts which have a primary event.
1507pub trait BroadcastWithEvent
1508where
1509    Self: Broadcast,
1510    for<'de> Self: Decodable<Type<'de> = Self::Event<'de>>,
1511{
1512    /// The event type related to the broadcast.
1513    type Event<'de>: Event<Broadcast = Self> + DecodeBody<'de>
1514    where
1515        Self: 'de;
1516
1517    #[doc(hidden)]
1518    fn __do_not_implement_broadcast_with_event();
1519}
1520
1521/// A marker indicating a request type.
1522///
1523/// Do not implement manually, instead use the [`define!`] macro.
1524pub trait Request
1525where
1526    Self: EncodeBody,
1527{
1528    /// The endpoint related to the request.
1529    type Endpoint: Endpoint;
1530
1531    #[doc(hidden)]
1532    fn __do_not_implement_request();
1533}
1534
1535/// The event of a broadcast.
1536///
1537/// Do not implement manually, instead use the [`define!`] macro.
1538pub trait Event
1539where
1540    Self: EncodeBody,
1541{
1542    /// The endpoint related to the broadcast.
1543    type Broadcast: Broadcast;
1544
1545    #[doc(hidden)]
1546    fn __do_not_implement_event();
1547}
1548
1549/// A request to connect.
1550#[derive(Debug, Clone, Copy, Encode, Decode)]
1551#[doc(hidden)]
1552#[musli(packed)]
1553pub struct Connect;
1554
1555/// The header of a response.
1556///
1557/// This is the envelope of every message the server sends, see the [wire
1558/// format].
1559///
1560/// [wire format]: crate::api#wire-format
1561#[derive(Debug, Clone)]
1562#[doc(hidden)]
1563pub struct ResponseHeader {
1564    /// The version of the protocol this envelope was written against, which is
1565    /// always [`VERSION`].
1566    pub version: u32,
1567    /// The serial request this is a response to.
1568    pub serial: u32,
1569    /// This is a broadcast over the specified type. If this is non-empty the
1570    /// serial is 0.
1571    pub broadcast: u16,
1572    /// If non-zero, the response is an error and this says what its body
1573    /// carries, see [error responses](crate::api#error-responses).
1574    pub error: u16,
1575    /// The [`Format`] the body of this response is encoded with, as given by
1576    /// [`Format::to_u8`]. Zero if the response carries no body.
1577    pub format: u8,
1578    /// The channel over which the response will be sent.
1579    pub channel: ChannelId,
1580    /// The application version the server states, see [application
1581    /// versions]. Only [`MessageId::SERVER_HELLO`] carries it, and zero means
1582    /// that none is stated.
1583    ///
1584    /// [application versions]: crate::api#application-versions
1585    pub app: u32,
1586}
1587
1588/// The body of an error response.
1589///
1590/// When the response carries [`MessageId::TYPED_ERROR_MESSAGE`] the typed
1591/// payload follows it in the same body, see [error
1592/// responses](crate::api#error-responses).
1593#[derive(Debug, Clone, Encode, Decode)]
1594#[doc(hidden)]
1595#[musli(packed)]
1596pub struct ErrorMessage<'de> {
1597    /// The error message.
1598    pub message: &'de str,
1599}
1600
1601/// A request header.
1602///
1603/// This is the envelope of every message the client sends, see the [wire
1604/// format].
1605///
1606/// [wire format]: crate::api#wire-format
1607#[derive(Debug, Clone, Copy)]
1608#[doc(hidden)]
1609pub struct RequestHeader {
1610    /// The version of the protocol this envelope was written against, which is
1611    /// always [`VERSION`].
1612    pub version: u32,
1613    /// The serial of the request.
1614    pub serial: u32,
1615    /// The kind of the request.
1616    pub id: u16,
1617    /// The [`Format`] the body of this request is encoded with, as given by
1618    /// [`Format::to_u8`]. Zero if the request carries no body.
1619    pub format: u8,
1620    /// The channel over which the request was received.
1621    pub channel: ChannelId,
1622    /// The application version the client states, see [application
1623    /// versions]. Only [`MessageId::NEGOTIATE`] carries it, and zero means
1624    /// that none is stated.
1625    ///
1626    /// [application versions]: crate::api#application-versions
1627    pub app: u32,
1628}
1629
1630#[cfg(test)]
1631mod from_str_tests {
1632    use crate::std::string::ToString;
1633
1634    use super::{Format, Mode, ParseFormatError, ParseModeError};
1635
1636    #[test]
1637    fn format_round_trips() {
1638        for &format in Format::ALL {
1639            assert_eq!(format.name().parse::<Format>(), Ok(format));
1640            assert_eq!(format.to_string().parse::<Format>(), Ok(format));
1641        }
1642    }
1643
1644    #[test]
1645    fn mode_round_trips() {
1646        for &mode in Mode::ALL {
1647            assert_eq!(mode.name().parse::<Mode>(), Ok(mode));
1648            assert_eq!(mode.to_string().parse::<Mode>(), Ok(mode));
1649        }
1650    }
1651
1652    #[test]
1653    fn format_rejects() {
1654        for s in [
1655            "", " wire", "wire ", "Wire", "WIRE", "json\n", "binary", "w", "wire\0",
1656        ] {
1657            assert_eq!(s.parse::<Format>(), Err(ParseFormatError), "{s:?}");
1658        }
1659    }
1660
1661    #[test]
1662    fn mode_rejects() {
1663        for s in [
1664            "", " text", "text ", "Text", "BINARY", "wire", "bin", "text\0",
1665        ] {
1666            assert_eq!(s.parse::<Mode>(), Err(ParseModeError), "{s:?}");
1667        }
1668    }
1669}