rsrs_core/
header.rs

1use derive_more::Display;
2use recode::RawDecoder;
3
4/// An enum to represent supported frame types.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
6#[from_to_repr::from_to_other(base_type = u8)]
7pub enum FrameType {
8    /// Setup: Sent by client to initiate protocol processing.
9    Setup           = 0x01,
10
11    /// Lease: Sent by Responder to grant the ability to send requests.
12    Lease           = 0x02,
13
14    /// Keepalive: Connection keepalive.
15    Keepalive       = 0x03,
16
17    /// Request Response: Request single response.
18    RequestResponse = 0x04,
19
20    /// Fire And Forget: A single one-way message.
21    RequestFNF      = 0x05,
22
23    /// Request Stream: Request a completable stream.
24    RequestStream   = 0x06,
25
26    /// Request Channel: Request a completable stream in both directions.
27    RequestChannel  = 0x07,
28
29    /// Request N: Request N more items with Reactive Streams semantics.
30    RequestN        = 0x08,
31
32    /// Cancel Request: Cancel outstanding request.
33    Cancel          = 0x09,
34
35    /// Payload: Payload on a stream. For example, response to a request, or
36    /// message on a channel.
37    Payload         = 0x0A,
38
39    /// Error: Error at connection or application level.
40    Error           = 0x0B,
41
42    /// Metadata: Asynchronous Metadata frame
43    MetadataPush    = 0x0C,
44
45    /// Resume: Replaces SETUP for Resuming Operation (optional)
46    Resume          = 0x0D,
47
48    /// Resume OK : Sent in response to a RESUME if resuming operation possible
49    /// (optional)
50    ResumeOk        = 0x0E,
51
52    /// Extension Header: Used To Extend more frame types as well as
53    /// extensions.
54    Ext             = 0x3F,
55
56    /// Unknown frame type.
57    Unknown(u8),
58}
59
60bitflags::bitflags! {
61    /// A flags structure to represent possible frams flags.
62    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Display)]
63    pub struct FrameFlags: u16 {
64        /// (N)ext: bit to indicate Next (Payload Data and/or Metadata present).
65        ///
66        /// If set, onNext(Payload) or equivalent will be invoked on
67        /// Subscriber/Observer.
68        const NEXT = 1 << 5;
69
70        /// (C)omplete: bit to indicate stream completion.
71        ///
72        /// If set, `onComplete()` or equivalent will be invoked on
73        /// Subscriber/Observer.
74        const COMPLETE = 1 << 6;
75
76        /// (F)ollows: More fragments follow this fragment.
77        const FOLLOW = 1 << 7;
78
79        /// (M)etadata: Metadata present.
80        const METADATA = 1 << 8;
81
82        /// (I)gnore: Ignore invalid frames.
83        const IGNORE = 1 << 9;
84
85        /// (L)ease: Will honor LEASE (or not).
86        const LEASE = Self::COMPLETE.bits();
87
88        /// (R)esume Enable: Client requests resume capability if possible.
89        /// Resume Identification Token present.
90        const RESUME = Self::FOLLOW.bits();
91
92        /// (R)espond with KEEPALIVE or not.
93        const RESPOND = Self::FOLLOW.bits();
94    }
95}
96
97/// A type to represent an rsocket frame header.
98#[derive(Debug, Clone, Copy, recode::Recode)]
99#[recode(error = "crate::Error")]
100pub struct FrameHeader {
101    inner: u16,
102}
103
104impl FrameHeader {
105    const FLAGS_MASK: u16 = 0x03FF;
106    const FRAME_TYPE_OFFSET: u16 = 10;
107
108    /// Creates a new frame header.
109    ///
110    /// # Parameters
111    /// * `frame_type` - A frame type.
112    /// * `flags` - Frame flags.
113    ///
114    /// # Returns
115    /// A new frame header.
116    pub(crate) const fn new(frame_type: FrameType, flags: FrameFlags) -> Self {
117        let frame_type =
118            (frame_type.to_base_type() as u16) << Self::FRAME_TYPE_OFFSET;
119
120        Self {
121            inner: frame_type | flags.bits(),
122        }
123    }
124
125    /// Gets frame type.
126    pub const fn frame_type(&self) -> FrameType {
127        FrameType::from_base_type((self.inner >> Self::FRAME_TYPE_OFFSET) as u8)
128    }
129
130    /// Gets frame flags.
131    pub const fn flags(&self) -> FrameFlags {
132        FrameFlags::from_bits_truncate(self.inner & Self::FLAGS_MASK)
133    }
134
135    /// A shorthand for `self.flags().contains(flag)`.
136    #[inline]
137    pub const fn has(&self, flag: FrameFlags) -> bool {
138        self.flags().contains(flag)
139    }
140
141    #[inline]
142    pub(crate) fn set(&mut self, flag: FrameFlags, value: bool) {
143        let mut flags = FrameFlags::from_bits_truncate(self.inner);
144
145        flags.set(flag, value);
146
147        self.inner = (self.inner & !Self::FLAGS_MASK) | flags.bits();
148    }
149}
150
151impl RawDecoder for FrameHeader {
152    type Error = crate::Error;
153
154    #[inline]
155    fn raw_decode<'a>(buf: &'a [u8]) -> Result<(Self, usize), Self::Error>
156    where
157        Self: 'a,
158    {
159        let (inner, rx): (u16, usize) = u16::raw_decode(buf)?;
160
161        Ok((Self { inner }, rx))
162    }
163}
164
165/// Creates a value of type [`FrameFlags`] at compile time.
166///
167/// This macro removes the boilerplate required to create constant
168/// [`FrameFlags`] values at compile time.
169///
170/// # Example
171/// ```rust
172/// #[macro_use]
173/// use rsocket_proto::frame::Flags;
174/// use rsocket_proto::const_flags;
175///
176/// struct MyType;
177///
178/// impl MyType {
179///     const FLAGS_MASK: Flags = const_flags![METADATA | RESUME | LEASE];
180/// }
181/// ```
182#[macro_export]
183macro_rules! const_flags {
184    ($($expr:tt)*) => {
185        $crate::process_flags_expr!(@entry: [ $($expr)* ] [] )
186    };
187}
188
189/// Recursively Converts an expression that uses [`FrameFlags`] constants into
190/// an expression that uses the backing value of [`FrameFlags`] ([`u16`]).
191#[macro_export]
192macro_rules! process_flags_expr {
193    (@entry: [ ] [ ]) => {
194        $crate::FrameFlags::empty()
195    };
196
197    (@entry: [ $($lhs:tt)+ ] [ ]) => {
198        $crate::process_flags_expr! {
199            @process:
200                [ $($lhs)+ ]
201                []
202        }
203    };
204
205    (@process: [ $flag:ident $($lhs:tt)* ] [ $($rhs:tt)* ]) => {
206        $crate::process_flags_expr! {
207            @process:
208                [ $($lhs)* ]
209                [ $($rhs)* $crate::FrameFlags::$flag.bits() ]
210        }
211    };
212
213    (@process: [ ( $($expr:tt)+ ) $($lhs:tt)* ] [ $($rhs:tt)* ]) => {
214        $crate::process_flags_expr! {
215            @process:
216                [ $($lhs)* ]
217                [ $($rhs)* $crate::const_flags!($($expr)+).bits() ]
218        }
219    };
220
221    (@process: [ $other:tt $($lhs:tt)* ] [ $($rhs:tt)* ]) => {
222        $crate::process_flags_expr! {
223            @process:
224                [ $($lhs)* ]
225                [ $($rhs)* $other ]
226        }
227    };
228
229    (@process: [ ] [ $($lhs:tt)+ ]) => {
230        $crate::FrameFlags::from_bits_truncate($($lhs)+)
231    };
232}
233
234#[doc(inline)]
235pub use const_flags;