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;