coap_lite/
header.rs

1use alloc::{
2    string::{String, ToString},
3    vec::Vec,
4};
5use core::{convert::TryFrom, fmt};
6
7use crate::error::MessageError;
8
9/// The raw byte header representation, useful for encoding/decoding directly.
10#[derive(Debug, Clone)]
11pub struct HeaderRaw {
12    ver_type_tkl: u8,
13    code: u8,
14    message_id: u16,
15}
16
17impl HeaderRaw {
18    /// Writes the header into the given buffer, which must have a capacity of
19    /// at least 4.
20    pub fn serialize_into(
21        &self,
22        buf: &mut Vec<u8>,
23    ) -> Result<(), MessageError> {
24        if buf.capacity() < 4 {
25            return Err(MessageError::InvalidPacketLength);
26        }
27
28        buf.push(self.ver_type_tkl);
29        buf.push(self.code);
30        let id_bytes = self.message_id.to_be_bytes();
31        buf.extend(&id_bytes);
32
33        Ok(())
34    }
35}
36
37impl Default for HeaderRaw {
38    fn default() -> HeaderRaw {
39        HeaderRaw {
40            ver_type_tkl: 0x40, // version: 1, type: Confirmable, TKL: 0
41            code: 0x01,         // GET
42            message_id: 0,
43        }
44    }
45}
46
47impl TryFrom<&[u8]> for HeaderRaw {
48    type Error = MessageError;
49
50    fn try_from(buf: &[u8]) -> Result<HeaderRaw, MessageError> {
51        if buf.len() < 4 {
52            return Err(MessageError::InvalidPacketLength);
53        }
54
55        let mut id_bytes = [0; 2];
56        id_bytes.copy_from_slice(&buf[2..4]);
57
58        Ok(HeaderRaw {
59            ver_type_tkl: buf[0],
60            code: buf[1],
61            message_id: u16::from_be_bytes(id_bytes),
62        })
63    }
64}
65
66/// The detailed class (request/response) of a message with the code.
67#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
68pub enum MessageClass {
69    Empty,
70    Request(RequestType),
71    Response(ResponseType),
72    Reserved(u8),
73}
74
75impl From<u8> for MessageClass {
76    fn from(number: u8) -> MessageClass {
77        match number {
78            0x00 => MessageClass::Empty,
79
80            0x01 => MessageClass::Request(RequestType::Get),
81            0x02 => MessageClass::Request(RequestType::Post),
82            0x03 => MessageClass::Request(RequestType::Put),
83            0x04 => MessageClass::Request(RequestType::Delete),
84            0x05 => MessageClass::Request(RequestType::Fetch),
85            0x06 => MessageClass::Request(RequestType::Patch),
86            0x07 => MessageClass::Request(RequestType::IPatch),
87
88            0x41 => MessageClass::Response(ResponseType::Created),
89            0x42 => MessageClass::Response(ResponseType::Deleted),
90            0x43 => MessageClass::Response(ResponseType::Valid),
91            0x44 => MessageClass::Response(ResponseType::Changed),
92            0x45 => MessageClass::Response(ResponseType::Content),
93            0x5F => MessageClass::Response(ResponseType::Continue),
94
95            0x80 => MessageClass::Response(ResponseType::BadRequest),
96            0x81 => MessageClass::Response(ResponseType::Unauthorized),
97            0x82 => MessageClass::Response(ResponseType::BadOption),
98            0x83 => MessageClass::Response(ResponseType::Forbidden),
99            0x84 => MessageClass::Response(ResponseType::NotFound),
100            0x85 => MessageClass::Response(ResponseType::MethodNotAllowed),
101            0x86 => MessageClass::Response(ResponseType::NotAcceptable),
102            0x89 => MessageClass::Response(ResponseType::Conflict),
103            0x8C => MessageClass::Response(ResponseType::PreconditionFailed),
104            0x8D => {
105                MessageClass::Response(ResponseType::RequestEntityTooLarge)
106            }
107            0x8F => {
108                MessageClass::Response(ResponseType::UnsupportedContentFormat)
109            }
110            0x88 => {
111                MessageClass::Response(ResponseType::RequestEntityIncomplete)
112            }
113            0x96 => MessageClass::Response(ResponseType::UnprocessableEntity),
114            0x9d => MessageClass::Response(ResponseType::TooManyRequests),
115
116            0xA0 => MessageClass::Response(ResponseType::InternalServerError),
117            0xA1 => MessageClass::Response(ResponseType::NotImplemented),
118            0xA2 => MessageClass::Response(ResponseType::BadGateway),
119            0xA3 => MessageClass::Response(ResponseType::ServiceUnavailable),
120            0xA4 => MessageClass::Response(ResponseType::GatewayTimeout),
121            0xA5 => MessageClass::Response(ResponseType::ProxyingNotSupported),
122            0xA8 => MessageClass::Response(ResponseType::HopLimitReached),
123
124            n => MessageClass::Reserved(n),
125        }
126    }
127}
128
129impl From<MessageClass> for u8 {
130    fn from(class: MessageClass) -> u8 {
131        match class {
132            MessageClass::Empty => 0x00,
133
134            MessageClass::Request(RequestType::Get) => 0x01,
135            MessageClass::Request(RequestType::Post) => 0x02,
136            MessageClass::Request(RequestType::Put) => 0x03,
137            MessageClass::Request(RequestType::Delete) => 0x04,
138            MessageClass::Request(RequestType::Fetch) => 0x05,
139            MessageClass::Request(RequestType::Patch) => 0x06,
140            MessageClass::Request(RequestType::IPatch) => 0x07,
141            MessageClass::Request(RequestType::UnKnown) => 0xFF,
142
143            MessageClass::Response(ResponseType::Created) => 0x41,
144            MessageClass::Response(ResponseType::Deleted) => 0x42,
145            MessageClass::Response(ResponseType::Valid) => 0x43,
146            MessageClass::Response(ResponseType::Changed) => 0x44,
147            MessageClass::Response(ResponseType::Content) => 0x45,
148            MessageClass::Response(ResponseType::Continue) => 0x5F,
149
150            MessageClass::Response(ResponseType::BadRequest) => 0x80,
151            MessageClass::Response(ResponseType::Unauthorized) => 0x81,
152            MessageClass::Response(ResponseType::BadOption) => 0x82,
153            MessageClass::Response(ResponseType::Forbidden) => 0x83,
154            MessageClass::Response(ResponseType::NotFound) => 0x84,
155            MessageClass::Response(ResponseType::MethodNotAllowed) => 0x85,
156            MessageClass::Response(ResponseType::NotAcceptable) => 0x86,
157            MessageClass::Response(ResponseType::Conflict) => 0x89,
158            MessageClass::Response(ResponseType::PreconditionFailed) => 0x8C,
159            MessageClass::Response(ResponseType::RequestEntityTooLarge) => {
160                0x8D
161            }
162            MessageClass::Response(ResponseType::UnsupportedContentFormat) => {
163                0x8F
164            }
165            MessageClass::Response(ResponseType::RequestEntityIncomplete) => {
166                0x88
167            }
168            MessageClass::Response(ResponseType::UnprocessableEntity) => 0x96,
169            MessageClass::Response(ResponseType::TooManyRequests) => 0x9d,
170
171            MessageClass::Response(ResponseType::InternalServerError) => 0xA0,
172            MessageClass::Response(ResponseType::NotImplemented) => 0xA1,
173            MessageClass::Response(ResponseType::BadGateway) => 0xA2,
174            MessageClass::Response(ResponseType::ServiceUnavailable) => 0xA3,
175            MessageClass::Response(ResponseType::GatewayTimeout) => 0xA4,
176            MessageClass::Response(ResponseType::ProxyingNotSupported) => 0xA5,
177            MessageClass::Response(ResponseType::HopLimitReached) => 0xA8,
178            MessageClass::Response(ResponseType::UnKnown) => 0xFF,
179
180            MessageClass::Reserved(c) => c,
181        }
182    }
183}
184
185impl fmt::Display for MessageClass {
186    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187        let code: u8 = (*self).into();
188        let class_code = (0xE0 & code) >> 5;
189        let detail_code = 0x1F & code;
190        write!(f, "{}.{:02}", class_code, detail_code)
191    }
192}
193
194/// The request codes.
195#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
196pub enum RequestType {
197    Get,
198    Post,
199    Put,
200    Delete,
201    Fetch,
202    Patch,
203    IPatch,
204    UnKnown,
205}
206
207/// The response codes.
208#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
209pub enum ResponseType {
210    // 200 Codes
211    Created,
212    Deleted,
213    Valid,
214    Changed,
215    Content,
216    Continue,
217
218    // 400 Codes
219    BadRequest,
220    Unauthorized,
221    BadOption,
222    Forbidden,
223    NotFound,
224    MethodNotAllowed,
225    NotAcceptable,
226    Conflict,
227    PreconditionFailed,
228    RequestEntityTooLarge,
229    UnsupportedContentFormat,
230    RequestEntityIncomplete,
231    UnprocessableEntity,
232    TooManyRequests,
233
234    // 500 Codes
235    InternalServerError,
236    NotImplemented,
237    BadGateway,
238    ServiceUnavailable,
239    GatewayTimeout,
240    ProxyingNotSupported,
241    HopLimitReached,
242
243    UnKnown,
244}
245
246impl ResponseType {
247    pub fn is_error(&self) -> bool {
248        MessageClass::Response(*self)
249            >= MessageClass::Response(ResponseType::BadRequest)
250    }
251}
252
253/// The message types.
254#[derive(Debug, Clone, Copy, PartialEq)]
255pub enum MessageType {
256    Confirmable,
257    NonConfirmable,
258    Acknowledgement,
259    Reset,
260}
261
262/// The message header.
263#[derive(Debug, Clone, PartialEq)]
264pub struct Header {
265    ver_type_tkl: u8,
266    pub code: MessageClass,
267    pub message_id: u16,
268}
269
270impl Default for Header {
271    fn default() -> Header {
272        Header::from_raw(&HeaderRaw::default())
273    }
274}
275
276impl Header {
277    /// Creates a new header.
278    pub fn new() -> Header {
279        Default::default()
280    }
281
282    /// Creates a new header from a raw header.
283    pub fn from_raw(raw: &HeaderRaw) -> Header {
284        Header {
285            ver_type_tkl: raw.ver_type_tkl,
286            code: raw.code.into(),
287            message_id: raw.message_id,
288        }
289    }
290
291    /// Returns the raw header.
292    pub fn to_raw(&self) -> HeaderRaw {
293        HeaderRaw {
294            ver_type_tkl: self.ver_type_tkl,
295            code: self.code.into(),
296            message_id: self.message_id,
297        }
298    }
299
300    /// Sets the version.
301    #[inline]
302    pub fn set_version(&mut self, v: u8) {
303        let type_tkl = 0x3F & self.ver_type_tkl;
304        self.ver_type_tkl = v << 6 | type_tkl;
305    }
306
307    /// Returns the version.
308    #[inline]
309    pub fn get_version(&self) -> u8 {
310        self.ver_type_tkl >> 6
311    }
312
313    /// Sets the message type.
314    #[inline]
315    pub fn set_type(&mut self, t: MessageType) {
316        let tn = match t {
317            MessageType::Confirmable => 0,
318            MessageType::NonConfirmable => 1,
319            MessageType::Acknowledgement => 2,
320            MessageType::Reset => 3,
321        };
322
323        let ver_tkl = 0xCF & self.ver_type_tkl;
324        self.ver_type_tkl = tn << 4 | ver_tkl;
325    }
326
327    /// Returns the message type.
328    #[inline]
329    pub fn get_type(&self) -> MessageType {
330        let tn = (0x30 & self.ver_type_tkl) >> 4;
331        match tn {
332            0 => MessageType::Confirmable,
333            1 => MessageType::NonConfirmable,
334            2 => MessageType::Acknowledgement,
335            3 => MessageType::Reset,
336            _ => unreachable!(),
337        }
338    }
339
340    /// Sets the token length.
341    #[inline]
342    pub fn set_token_length(&mut self, tkl: u8) {
343        assert_eq!(0xF0 & tkl, 0);
344
345        let ver_type = 0xF0 & self.ver_type_tkl;
346        self.ver_type_tkl = tkl | ver_type;
347    }
348
349    /// Returns the token length.
350    #[inline]
351    pub fn get_token_length(&self) -> u8 {
352        0x0F & self.ver_type_tkl
353    }
354
355    /// Sets the message code from a string.
356    pub fn set_code(&mut self, code: &str) {
357        let code_vec: Vec<&str> = code.split('.').collect();
358        assert_eq!(code_vec.len(), 2);
359
360        let class_code = code_vec[0].parse::<u8>().unwrap();
361        let detail_code = code_vec[1].parse::<u8>().unwrap();
362        assert_eq!(0xF8 & class_code, 0);
363        assert_eq!(0xE0 & detail_code, 0);
364
365        self.code = (class_code << 5 | detail_code).into();
366    }
367
368    /// Returns the message code as a string.
369    pub fn get_code(&self) -> String {
370        self.code.to_string()
371    }
372}
373
374#[cfg(test)]
375mod test {
376    use super::*;
377
378    #[test]
379    fn test_header_codes() {
380        for code in 0..255 {
381            let class: MessageClass = code.into();
382            let code_str = class.to_string();
383
384            let mut header = Header::new();
385            header.set_code(&code_str);
386
387            // Reserved class could technically be many codes, so only check
388            // valid items
389            if !matches!(class, MessageClass::Reserved(_)) {
390                assert_eq!(u8::from(class), code);
391                assert_eq!(class, header.code);
392                assert_eq!(code_str, header.get_code());
393            }
394        }
395    }
396
397    #[test]
398    fn serialize_raw_fail() {
399        let h = HeaderRaw::default();
400        let mut buf = Vec::with_capacity(3);
401        assert_eq!(
402            MessageError::InvalidPacketLength,
403            h.serialize_into(&mut buf).unwrap_err()
404        );
405    }
406
407    #[test]
408    fn from_bytes_fail() {
409        let b: &[u8] = &[1, 2, 3];
410        assert_eq!(
411            MessageError::InvalidPacketLength,
412            HeaderRaw::try_from(b).unwrap_err()
413        );
414    }
415
416    #[test]
417    fn types() {
418        let mut h = Header::new();
419        h.set_type(MessageType::Acknowledgement);
420        assert_eq!(MessageType::Acknowledgement, h.get_type());
421        h.set_type(MessageType::Confirmable);
422        assert_eq!(MessageType::Confirmable, h.get_type());
423        h.set_type(MessageType::NonConfirmable);
424        assert_eq!(MessageType::NonConfirmable, h.get_type());
425        h.set_type(MessageType::Reset);
426        assert_eq!(MessageType::Reset, h.get_type());
427    }
428
429    #[test]
430    fn is_error() {
431        assert!(!ResponseType::Created.is_error());
432        assert!(!ResponseType::Continue.is_error());
433        assert!(ResponseType::BadRequest.is_error());
434        assert!(ResponseType::TooManyRequests.is_error());
435        assert!(ResponseType::HopLimitReached.is_error());
436    }
437}