Skip to main content

pushwire_core/
channel.rs

1use serde::{Serialize, de::DeserializeOwned};
2use std::fmt::Debug;
3use std::hash::Hash;
4
5/// Trait for defining multiplexed channel types.
6///
7/// Consumers implement this trait to define their own channel taxonomy.
8/// Each channel has a priority, a wire ID for binary encoding, and
9/// string representations for JSON/SSE serialization.
10///
11/// # Example
12///
13/// ```rust
14/// use pushwire_core::ChannelKind;
15///
16/// #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
17/// #[serde(rename_all = "lowercase")]
18/// enum MyChannel { Events, Control, System }
19///
20/// impl ChannelKind for MyChannel {
21///     fn priority(&self) -> u8 {
22///         match self {
23///             MyChannel::System | MyChannel::Events => 0,
24///             MyChannel::Control => 1,
25///         }
26///     }
27///     fn wire_id(&self) -> u8 {
28///         match self {
29///             MyChannel::Events => 0x01,
30///             MyChannel::Control => 0x02,
31///             MyChannel::System => 0x05,
32///         }
33///     }
34///     fn from_wire_id(id: u8) -> Option<Self> {
35///         match id {
36///             0x01 => Some(MyChannel::Events),
37///             0x02 => Some(MyChannel::Control),
38///             0x05 => Some(MyChannel::System),
39///             _ => None,
40///         }
41///     }
42///     fn from_name(s: &str) -> Option<Self> {
43///         match s {
44///             "events" => Some(MyChannel::Events),
45///             "control" => Some(MyChannel::Control),
46///             "system" => Some(MyChannel::System),
47///             _ => None,
48///         }
49///     }
50///     fn name(&self) -> &'static str {
51///         match self {
52///             MyChannel::Events => "events",
53///             MyChannel::Control => "control",
54///             MyChannel::System => "system",
55///         }
56///     }
57///     fn is_system(&self) -> bool { matches!(self, MyChannel::System) }
58///     fn all() -> &'static [Self] { &[Self::Events, Self::Control, Self::System] }
59/// }
60/// ```
61pub trait ChannelKind:
62    Debug + Clone + Copy + Hash + Eq + Send + Sync + Serialize + DeserializeOwned + 'static
63{
64    /// Priority for outbound queue ordering. Lower values = higher priority.
65    /// Typical mapping: 0 = high (system, critical UI), 1 = normal, 2 = low (telemetry).
66    fn priority(&self) -> u8;
67
68    /// Numeric ID for the binary wire format. Must be unique per channel.
69    fn wire_id(&self) -> u8;
70
71    /// Decode from binary wire ID. Returns `None` for unknown IDs.
72    fn from_wire_id(id: u8) -> Option<Self>;
73
74    /// Parse from canonical string name (for SSE query params, JSON fields).
75    fn from_name(s: &str) -> Option<Self>;
76
77    /// Canonical string name for this channel.
78    fn name(&self) -> &'static str;
79
80    /// Whether this channel is the system/control channel.
81    /// The system channel handles auth, ping/pong, ACK, and subscription management.
82    /// Exactly one channel should return `true`.
83    fn is_system(&self) -> bool;
84
85    /// All valid channel variants. Used for cursor initialization and enumeration.
86    fn all() -> &'static [Self];
87}
88
89/// Parse a comma-separated channel list (e.g. from SSE query params).
90pub fn parse_channels<C: ChannelKind>(raw: Option<&str>) -> Vec<C> {
91    raw.map(|list| {
92        list.split(',')
93            .filter_map(|s| C::from_name(s.trim()))
94            .collect()
95    })
96    .unwrap_or_default()
97}