toad_msg/msg/
mod.rs

1use core::cmp::Ordering;
2use core::hash::Hash;
3use core::iter::FromIterator;
4use core::str::{from_utf8, Utf8Error};
5
6use toad_array::{AppendCopy, Array, Indexed};
7use toad_cursor::Cursor;
8use toad_len::Len;
9use toad_macros::rfc_7252_doc;
10
11#[allow(unused_imports)]
12use crate::TryIntoBytes;
13
14/// Message Code
15pub mod code;
16
17/// Message parsing errors
18pub mod parse_error;
19
20/// Message ID
21pub mod id;
22
23/// Message Options
24pub mod opt;
25
26/// Message Type
27pub mod ty;
28
29/// Message Token
30pub mod token;
31
32/// Message Version
33pub mod ver;
34
35pub use code::*;
36pub use id::*;
37pub use opt::*;
38pub use parse_error::*;
39pub use token::*;
40pub use ty::*;
41pub use ver::*;
42
43use crate::from_bytes::TryConsumeBytes;
44use crate::{CacheKey, DefaultCacheKey, TryFromBytes};
45
46#[doc = rfc_7252_doc!("5.5")]
47#[derive(Default, Clone, Debug)]
48pub struct Payload<C>(pub C);
49
50impl<C> PartialOrd for Payload<C> where C: Array<Item = u8>
51{
52  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
53    self.0.iter().partial_cmp(other.0.iter())
54  }
55}
56
57impl<C> PartialEq for Payload<C> where C: Array<Item = u8>
58{
59  fn eq(&self, other: &Self) -> bool {
60    self.0.iter().eq(other.0.iter())
61  }
62}
63
64impl<C> Ord for Payload<C> where C: Array<Item = u8>
65{
66  fn cmp(&self, other: &Self) -> Ordering {
67    self.0.iter().cmp(other.0.iter())
68  }
69}
70
71impl<C> Eq for Payload<C> where C: Array<Item = u8> {}
72
73impl<C> Hash for Payload<C> where C: Array<Item = u8>
74{
75  fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
76    state.write(&self.0)
77  }
78}
79
80impl<C> Payload<C> where C: Array<Item = u8>
81{
82  /// Convert a reference to a Payload to a byte slice
83  pub fn as_bytes(&self) -> &[u8] {
84    &self.0
85  }
86}
87
88/// Struct representing the first byte of a message.
89///
90/// ```text
91/// CoAP version
92/// |
93/// |  Message type (request, response, empty)
94/// |  |
95/// |  |  Length of token, in bytes. (4-bit integer)
96/// |  |  |
97/// vv vv vvvv
98/// 01 00 0000
99/// ```
100#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
101pub(crate) struct Byte1 {
102  pub(crate) ver: Version,
103  pub(crate) ty: Type,
104  pub(crate) tkl: u8,
105}
106
107impl TryFrom<u8> for Byte1 {
108  type Error = MessageParseError;
109
110  fn try_from(b: u8) -> Result<Self, Self::Error> {
111    let ver = b >> 6; // bits 0 & 1
112    let ty = b >> 4 & 0b11; // bits 2 & 3
113    let tkl = b & 0b1111u8; // last 4 bits
114
115    Ok(Byte1 { ver: Version(ver),
116               ty: Type::try_from(ty)?,
117               tkl })
118  }
119}
120
121impl<PayloadBytes: Array<Item = u8>, Options: OptionMap> Len for Message<PayloadBytes, Options> {
122  const CAPACITY: Option<usize> = None;
123
124  fn len(&self) -> usize {
125    let header_size = 4;
126    let payload_marker_size = 1;
127    let payload_size = self.payload.0.len();
128    let token_size = self.token.0.len();
129    let opts_size: usize = self.opts.opt_refs().map(|o| o.len()).sum();
130
131    header_size + payload_marker_size + payload_size + token_size + opts_size
132  }
133
134  fn is_full(&self) -> bool {
135    false
136  }
137}
138
139/// # CoAP Messages
140/// This struct provides a high-level API for manipulating requests & responses,
141/// while still being cheaply serializable to & from the byte layout of CoAP messages on the wire.
142///
143/// ## Options
144/// Options (the CoAP equivalent to HTTP headers) can be manipulated with methods
145/// provided in the [`MessageOptions`] trait. This includes getting & setting common
146/// options known to this library.
147///
148/// ## Constructing
149/// [`Message::new`] is the most straightforward way to initialize messages.
150///
151/// Being one of the few structs in the toad-lib libraries with public fields,
152/// you may also initialize it with a struct literal.
153///
154/// ```
155/// use toad_msg::alloc::Message;
156/// use toad_msg::{Code, Id, Payload, Token, Type, Version};
157///
158/// let a = Message { id: Id(1),
159///                   token: Token(Default::default()),
160///                   ver: Version::default(),
161///                   ty: Type::Con,
162///                   code: Code::GET,
163///                   payload: Payload(vec![]),
164///                   opts: Default::default() };
165///
166/// let b = Message::new(Type::Con, Code::GET, Id(1), Token(Default::default()));
167///
168/// assert_eq!(a, b);
169/// ```
170///
171/// ## Sending / Receiving
172/// This crate (`toad-msg`) explicitly does **not** know or care about how
173/// the messages are sent and received, and is **just** concerned with the data
174/// structures involved on the machines having a CoAP conversation.
175///
176/// For a runtime that uses this library, see [`toad`](https://www.docs.rs/toad/latest).
177///
178/// <details>
179/// <summary><b>Further Reading from RFC7252</b></summary>
180#[doc = concat!("\n\n#", rfc_7252_doc!("2.1"))]
181#[doc = concat!("\n\n#", rfc_7252_doc!("3"))]
182/// </details>
183#[derive(Clone, Debug)]
184pub struct Message<PayloadBytes, Options> {
185  /// see [`Id`] for details
186  pub id: Id,
187  /// see [`Type`] for details
188  pub ty: Type,
189  /// see [`Version`] for details
190  pub ver: Version,
191  /// see [`Token`] for details
192  pub token: Token,
193  /// see [`Code`] for details
194  pub code: Code,
195  /// see [`opt::Opt`] for details
196  pub opts: Options,
197  /// see [`Payload`]
198  pub payload: Payload<PayloadBytes>,
199}
200
201impl<C, O> PartialOrd for Message<C, O>
202  where O: OptionMap + PartialOrd,
203        C: Array<Item = u8>
204{
205  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
206    Some(self.cmp(other))
207  }
208}
209impl<C, O> PartialEq for Message<C, O>
210  where O: OptionMap + PartialEq,
211        C: Array<Item = u8>
212{
213  fn eq(&self, other: &Self) -> bool {
214    self.id == other.id
215    && self.ver == other.ver
216    && self.code == other.code
217    && self.token == other.token
218    && self.payload == other.payload
219    && self.opts == other.opts
220  }
221}
222impl<C, O> Ord for Message<C, O>
223  where O: OptionMap + PartialOrd,
224        C: Array<Item = u8>
225{
226  fn cmp(&self, other: &Self) -> Ordering {
227    self.id
228        .cmp(&other.id)
229        .then(self.ver.cmp(&other.ver))
230        .then(self.code.cmp(&other.code))
231        .then(self.token.cmp(&other.token))
232        .then(self.payload.cmp(&other.payload))
233        .then(self.opts
234                  .partial_cmp(&other.opts)
235                  .unwrap_or(Ordering::Equal))
236  }
237}
238impl<C, O> Eq for Message<C, O>
239  where O: OptionMap + PartialEq,
240        C: Array<Item = u8>
241{
242}
243
244impl<C, O> Hash for Message<C, O>
245  where O: OptionMap + PartialEq + Hash,
246        C: Array<Item = u8>
247{
248  fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
249    self.id.hash(state);
250    self.code.hash(state);
251    self.token.hash(state);
252    self.ver.hash(state);
253    self.ty.hash(state);
254    self.opts.hash(state);
255    self.payload.hash(state);
256  }
257}
258
259/// An error occurred during a call to [`Message::set`]
260#[allow(missing_docs)]
261#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
262pub enum SetOptionError<OV, OVs> {
263  RepeatedTooManyTimes(OV),
264  TooManyOptions(OptNumber, OVs),
265}
266
267impl<P, O> MessageOptions for Message<P, O>
268  where P: Array<Item = u8> + AppendCopy<u8>,
269        O: OptionMap
270{
271  type OptValues = O::OptValues;
272  type OptValueBytes = O::OptValue;
273  type SetError = SetOptionError<OptValue<Self::OptValueBytes>, Self::OptValues>;
274
275  fn add(&mut self, n: OptNumber, v: OptValue<Self::OptValueBytes>) -> Result<(), Self::SetError> {
276    self.add(n, v)
277  }
278
279  fn set(&mut self,
280         n: OptNumber,
281         v: OptValue<Self::OptValueBytes>)
282         -> Result<Option<Self::OptValues>, Self::SetError> {
283    self.set(n, v)
284  }
285
286  fn count(&self, n: OptNumber) -> usize {
287    self.count(n)
288  }
289
290  fn get(&self, n: OptNumber) -> Option<&Self::OptValues> {
291    self.get(n)
292  }
293
294  fn get_first(&self, n: OptNumber) -> Option<&OptValue<Self::OptValueBytes>> {
295    self.get_first(n)
296  }
297
298  fn get_str(&self, n: OptNumber) -> Result<Option<&str>, Utf8Error> {
299    self.get_str(n)
300  }
301
302  fn get_strs<'a, F>(&'a self, n: OptNumber) -> Result<F, Utf8Error>
303    where F: FromIterator<&'a str>
304  {
305    self.get_strs(n)
306  }
307
308  fn get_u8(&self, n: OptNumber) -> Option<u8> {
309    self.get_u8(n)
310  }
311
312  fn get_u16(&self, n: OptNumber) -> Option<u16> {
313    self.get_u16(n)
314  }
315
316  fn get_u32(&self, n: OptNumber) -> Option<u32> {
317    self.get_u32(n)
318  }
319
320  fn get_u64(&self, n: OptNumber) -> Option<u64> {
321    self.get_u64(n)
322  }
323
324  fn remove(&mut self, n: OptNumber) -> Option<Self::OptValues> {
325    self.remove(n)
326  }
327}
328
329/// Methods that allow accessing & setting options known to the toad library.
330pub trait MessageOptions {
331  /// [`OptionMap::OptValues`]
332  type OptValues: Array<Item = OptValue<Self::OptValueBytes>>;
333  /// [`OptionMap::OptValue`]
334  type OptValueBytes: Array<Item = u8> + AppendCopy<u8>;
335  /// [`SetOptionError`]
336  type SetError;
337
338  /// Insert a new value for a given option
339  ///
340  /// Errors when there cannot be any more options, or the option
341  /// cannot be repeated any more (only applies to non-std environments)
342  #[doc = rfc_7252_doc!("5.4.5")]
343  fn add(&mut self, n: OptNumber, v: OptValue<Self::OptValueBytes>) -> Result<(), Self::SetError>;
344
345  /// Replace any / all existing values with a new one,
346  /// yielding the previous value(s)
347  fn set(&mut self,
348         n: OptNumber,
349         v: OptValue<Self::OptValueBytes>)
350         -> Result<Option<Self::OptValues>, Self::SetError>;
351
352  /// Get the number of values for a given option
353  fn count(&self, n: OptNumber) -> usize;
354
355  /// Get the value(s) of an option by number
356  ///
357  /// This just invokes [`toad_common::Map::get`] on [`Message.opts`].
358  fn get(&self, n: OptNumber) -> Option<&Self::OptValues>;
359
360  /// Get the value of an option, taking the first if there are multiple.
361  fn get_first(&self, n: OptNumber) -> Option<&OptValue<Self::OptValueBytes>>;
362
363  /// Get the value of an option, and interpret it
364  /// as a UTF-8 string
365  fn get_str(&self, n: OptNumber) -> Result<Option<&str>, Utf8Error>;
366
367  /// Get all values for an option, and interpret them as UTF-8 strings
368  fn get_strs<'a, F>(&'a self, n: OptNumber) -> Result<F, Utf8Error>
369    where F: FromIterator<&'a str>;
370
371  /// Get the value of an option, and interpret it
372  /// as a u8
373  fn get_u8(&self, n: OptNumber) -> Option<u8>;
374
375  /// Get the value of an option, and interpret it
376  /// as a u16
377  fn get_u16(&self, n: OptNumber) -> Option<u16>;
378
379  /// Get the value of an option, and interpret it
380  /// as a u32
381  fn get_u32(&self, n: OptNumber) -> Option<u32>;
382
383  /// Get the value of an option, and interpret it
384  /// as a u64
385  fn get_u64(&self, n: OptNumber) -> Option<u64>;
386
387  /// Remove all values for the option from this message,
388  /// returning them if there were any.
389  fn remove(&mut self, n: OptNumber) -> Option<Self::OptValues>;
390
391  /// Update the value for the [Uri-Host](opt::known::no_repeat::HOST) option,
392  /// discarding any existing values.
393  ///
394  /// ```
395  /// use toad_msg::alloc::Message;
396  /// use toad_msg::{Code, Id, MessageOptions, Token, Type};
397  ///
398  /// let mut msg = Message::new(Type::Con, Code::GET, Id(1), Token(Default::default()));
399  ///
400  /// msg.set_host("cheese.com").unwrap();
401  /// assert_eq!(msg.host(), Ok(Some("cheese.com")));
402  /// ```
403  #[doc = rfc_7252_doc!("5.10.1")]
404  fn set_host<S>(&mut self, host: S) -> Result<(), Self::SetError>
405    where S: AsRef<str>
406  {
407    self.set(opt::known::no_repeat::HOST,
408             host.as_ref().as_bytes().iter().copied().collect())
409        .map(|_| ())
410  }
411
412  /// [`opt::known::no_repeat::BLOCK1`]
413  fn block1(&self) -> Option<block::Block> {
414    self.get_u32(opt::known::no_repeat::BLOCK1)
415        .map(block::Block::from)
416  }
417
418  /// [`opt::known::no_repeat::BLOCK1`]
419  fn set_block1(&mut self, size: u16, num: u32, more: bool) -> Result<(), Self::SetError> {
420    let block = block::Block::new(size, num, more);
421    self.set(opt::known::no_repeat::BLOCK1,
422             OptValue(u32::from(block).to_be_bytes().iter().copied().collect()))
423        .map(|_| ())
424  }
425
426  /// [`opt::known::no_repeat::BLOCK2`]
427  fn block2(&self) -> Option<block::Block> {
428    self.get_u32(opt::known::no_repeat::BLOCK2)
429        .map(block::Block::from)
430  }
431
432  /// [`opt::known::no_repeat::BLOCK2`]
433  fn set_block2(&mut self, size: u16, num: u32, more: bool) -> Result<(), Self::SetError> {
434    let block = block::Block::new(size, num, more);
435    self.set(opt::known::no_repeat::BLOCK2,
436             OptValue(u32::from(block).to_be_bytes().iter().copied().collect()))
437        .map(|_| ())
438  }
439
440  /// Get the value for the [Uri-Host](opt::known::no_repeat::HOST) option
441  fn host(&self) -> Result<Option<&str>, Utf8Error> {
442    self.get_str(opt::known::no_repeat::HOST)
443  }
444
445  /// Update the value for the [Uri-Port](opt::known::no_repeat::PORT) option,
446  /// discarding any existing values.
447  ///
448  /// ```
449  /// use toad_msg::alloc::Message;
450  /// use toad_msg::{Code, Id, MessageOptions, Token, Type};
451  ///
452  /// let mut msg = Message::new(Type::Con, Code::GET, Id(1), Token(Default::default()));
453  ///
454  /// msg.set_host("cheese.com").unwrap();
455  /// msg.set_port(1234).unwrap();
456  /// assert_eq!(msg.host(), Ok(Some("cheese.com")));
457  /// assert_eq!(msg.port(), Some(1234));
458  /// ```
459  fn set_port(&mut self, port: u16) -> Result<(), Self::SetError> {
460    self.set(opt::known::no_repeat::PORT,
461             port.to_be_bytes().into_iter().collect())
462        .map(|_| ())
463  }
464
465  /// Get the value for the [Uri-Port](opt::known::no_repeat::PORT) option
466  fn port(&self) -> Option<u16> {
467    self.get_u16(opt::known::no_repeat::PORT)
468  }
469
470  /// Update the value for the [Uri-Path](opt::known::no_repeat::PATH) option,
471  /// discarding any existing values.
472  ///
473  /// ```
474  /// use toad_msg::alloc::Message;
475  /// use toad_msg::{Code, Id, MessageOptions, Token, Type};
476  ///
477  /// let mut msg = Message::new(Type::Con, Code::GET, Id(1), Token(Default::default()));
478  ///
479  /// msg.set_host("cheese.com").unwrap();
480  /// msg.set_port(1234).unwrap();
481  /// msg.set_path("cheese/havarti/suggestions").unwrap();
482  /// assert_eq!(msg.host(), Ok(Some("cheese.com")));
483  /// assert_eq!(msg.port(), Some(1234));
484  /// assert_eq!(msg.path_string(),
485  ///            Ok("cheese/havarti/suggestions".to_string()));
486  /// ```
487  fn set_path<S>(&mut self, path: S) -> Result<(), Self::SetError>
488    where S: AsRef<str>
489  {
490    path.as_ref()
491        .split('/')
492        .try_for_each(|segment| {
493          self.add(opt::known::repeat::PATH,
494                   segment.as_bytes().iter().copied().collect())
495        })
496        .map(|_| ())
497  }
498
499  /// Get an iterator over the [Uri-Path](opt::known::repeat::PATH) segments
500  fn path<'a, F>(&'a self) -> Result<F, Utf8Error>
501    where F: FromIterator<&'a str>
502  {
503    self.get_strs(opt::known::repeat::PATH)
504  }
505
506  /// Get the fully built path, joining segments with '/'.
507  #[cfg(feature = "std")]
508  fn path_string<'a>(&'a self) -> Result<String, Utf8Error> {
509    self.get_strs::<Vec<_>>(opt::known::repeat::PATH)
510        .map(|segs| {
511          let mut s = segs.into_iter()
512                          .fold(String::new(), |s, seg| format!("{s}{seg}/"));
513          s.pop();
514          s
515        })
516  }
517
518  /// Insert a new value for the [Uri-Query](opt::known::repeat::QUERY) option,
519  /// alongside any existing values.
520  fn add_query<S>(&mut self, query: S) -> Result<(), Self::SetError>
521    where S: AsRef<str>
522  {
523    self.add(opt::known::repeat::QUERY,
524             query.as_ref().as_bytes().iter().copied().collect())
525  }
526
527  /// Get all query parameters for this request
528  ///
529  /// ```
530  /// use toad_msg::alloc::Message;
531  /// use toad_msg::{Code, Id, MessageOptions, Token, Type};
532  ///
533  /// let mut msg = Message::new(Type::Con, Code::GET, Id(1), Token(Default::default()));
534  ///
535  /// msg.add_query("id[eq]=123").unwrap();
536  /// msg.add_query("price[lt]=333").unwrap();
537  /// assert_eq!(msg.query::<Vec<_>>(),
538  ///            Ok(vec!["id[eq]=123", "price[lt]=333"]));
539  /// ```
540  fn query<'a, F>(&'a self) -> Result<F, Utf8Error>
541    where F: FromIterator<&'a str>
542  {
543    self.get_strs(opt::known::repeat::QUERY)
544  }
545
546  /// Update the value for the [Content-Format](opt::known::no_repeat::CONTENT_FORMAT) option,
547  /// discarding any existing values.
548  #[doc = rfc_7252_doc!("5.10.3")]
549  fn set_content_format(&mut self, format: ContentFormat) -> Result<(), Self::SetError> {
550    self.set(opt::known::no_repeat::CONTENT_FORMAT,
551             format.into_iter().collect())
552        .map(|_| ())
553  }
554
555  /// Get the value for the [Content-Format](opt::known::no_repeat::CONTENT_FORMAT) option
556  ///
557  /// ```
558  /// use toad_msg::alloc::Message;
559  /// use toad_msg::ContentFormat::Json;
560  /// use toad_msg::{Code, Id, MessageOptions, Token, Type};
561  ///
562  /// let mut msg = Message::new(Type::Con, Code::GET, Id(1), Token(Default::default()));
563  ///
564  /// msg.set_content_format(Json).unwrap();
565  /// assert_eq!(msg.content_format(), Some(Json));
566  /// ```
567  fn content_format(&self) -> Option<ContentFormat> {
568    self.get_u16(opt::known::no_repeat::CONTENT_FORMAT)
569        .map(ContentFormat::from)
570  }
571
572  /// Set the value for the [Observe](opt::known::no_repeat::OBSERVE) option,
573  /// discarding any existing values.
574  fn set_observe(&mut self, a: observe::Action) -> Result<(), Self::SetError> {
575    self.set(opt::known::no_repeat::OBSERVE,
576             core::iter::once(u8::from(a)).collect())
577        .map(|_| ())
578  }
579
580  /// Get the value for the [Observe](opt::known::no_repeat::OBSERVE) option
581  fn observe(&self) -> Option<observe::Action> {
582    self.get_u8(opt::known::no_repeat::OBSERVE)
583        .and_then(observe::Action::from_byte)
584  }
585
586  /// Update the value for the [Accept](opt::known::no_repeat::ACCEPT) option,
587  /// discarding any existing values.
588  #[doc = rfc_7252_doc!("5.10.4")]
589  fn set_accept(&mut self, format: ContentFormat) -> Result<(), Self::SetError> {
590    self.set(opt::known::no_repeat::ACCEPT, format.into_iter().collect())
591        .map(|_| ())
592  }
593
594  /// Get the value for the [Accept](opt::known::no_repeat::ACCEPT) option
595  fn accept(&self) -> Option<ContentFormat> {
596    self.get_u16(opt::known::no_repeat::ACCEPT)
597        .map(ContentFormat::from)
598  }
599
600  /// Update the value for the [Size1](opt::known::no_repeat::SIZE1) option,
601  /// discarding any existing values.
602  #[doc = rfc_7252_doc!("5.10.9")]
603  fn set_size1(&mut self, size_bytes: u64) -> Result<(), Self::SetError> {
604    self.set(opt::known::no_repeat::SIZE1,
605             size_bytes.to_be_bytes().into_iter().collect())
606        .map(|_| ())
607  }
608
609  /// Get the value for the [Size1](opt::known::no_repeat::SIZE1) option
610  fn size1(&self) -> Option<u64> {
611    self.get_u64(opt::known::no_repeat::SIZE1)
612  }
613
614  /// Update the value for the [Size2](opt::known::no_repeat::SIZE2) option,
615  /// discarding any existing values.
616  fn set_size2(&mut self, size_bytes: u64) -> Result<(), Self::SetError> {
617    self.set(opt::known::no_repeat::SIZE2,
618             size_bytes.to_be_bytes().into_iter().collect())
619        .map(|_| ())
620  }
621
622  /// Get the value for the [Size2](opt::known::no_repeat::SIZE2) option
623  fn size2(&self) -> Option<u64> {
624    self.get_u64(opt::known::no_repeat::SIZE2)
625  }
626
627  /// Discard all values for [If-Match](opt::known::repeat::IF_MATCH), and replace them with
628  /// an empty value.
629  ///
630  /// This signals that our request should only be processed if we're trying to update
631  /// a resource that exists (e.g. this ensures PUT only updates and will never insert)
632  #[doc = rfc_7252_doc!("5.10.8.1")]
633  fn set_if_exists(&mut self) -> Result<(), Self::SetError> {
634    self.set(opt::known::repeat::IF_MATCH, Default::default())
635        .map(|_| ())
636  }
637
638  /// Get whether or not [`Message::set_if_exists`] applies
639  fn if_exists_flag_enabled(&self) -> bool {
640    self.get(opt::known::repeat::IF_MATCH)
641        .map(|vs| vs.iter().any(|v| v.0.len() == 0))
642        .unwrap_or(false)
643  }
644
645  /// Enable the [If-None-Match](opt::known::no_repeat::IF_NONE_MATCH) flag
646  ///
647  /// This signals that our request should only be processed if we're trying to insert
648  /// a resource that does not exist (e.g. this ensures PUT only inserts and will never update)
649  #[doc = rfc_7252_doc!("5.10.8.2")]
650  fn set_if_not_exists(&mut self) -> Result<(), Self::SetError> {
651    self.set(opt::known::no_repeat::IF_NONE_MATCH, Default::default())
652        .map(|_| ())
653  }
654
655  /// Get whether or not [`Message::set_if_not_exists`] applies
656  fn if_not_exists_flag_enabled(&self) -> bool {
657    self.get_first(opt::known::no_repeat::IF_NONE_MATCH)
658        .map(|_| true)
659        .unwrap_or(false)
660  }
661
662  /// Update the value for the [Max-Age](opt::known::no_repeat::MAX_AGE) option,
663  /// discarding any existing values.
664  #[doc = rfc_7252_doc!("5.10.5")]
665  fn set_max_age(&mut self, max_age_seconds: u32) -> Result<(), Self::SetError> {
666    self.set(opt::known::no_repeat::MAX_AGE,
667             max_age_seconds.to_be_bytes().into_iter().collect())
668        .map(|_| ())
669  }
670
671  /// Get the value for the [Max-Age](opt::known::no_repeat::MAX_AGE) option, in seconds
672  fn max_age_seconds(&self) -> Option<u32> {
673    self.get_u32(opt::known::no_repeat::MAX_AGE)
674  }
675
676  /// Update the value for the [Proxy-Uri](opt::known::no_repeat::PROXY_URI) option,
677  /// discarding any existing values.
678  #[doc = rfc_7252_doc!("5.10.2")]
679  fn set_proxy_uri<S>(&mut self, uri: S) -> Result<(), Self::SetError>
680    where S: AsRef<str>
681  {
682    self.set(opt::known::no_repeat::PROXY_URI,
683             uri.as_ref().as_bytes().iter().copied().collect())
684        .map(|_| ())
685  }
686
687  /// Get the value for the [Proxy-Uri](opt::known::no_repeat::PROXY_URI) option
688  fn proxy_uri(&self) -> Result<Option<&str>, Utf8Error> {
689    self.get_str(opt::known::no_repeat::PROXY_URI)
690  }
691
692  /// Update the value for the [Proxy-Scheme](opt::known::no_repeat::PROXY_SCHEME) option,
693  /// discarding any existing values.
694  fn set_proxy_scheme<S>(&mut self, scheme: S) -> Result<(), Self::SetError>
695    where S: AsRef<str>
696  {
697    self.set(opt::known::no_repeat::PROXY_SCHEME,
698             scheme.as_ref().as_bytes().iter().copied().collect())
699        .map(|_| ())
700  }
701
702  /// Get the value for the [Proxy-Scheme](opt::known::no_repeat::PROXY_SCHEME) option
703  fn proxy_scheme(&self) -> Result<Option<&str>, Utf8Error> {
704    self.get_str(opt::known::no_repeat::PROXY_SCHEME)
705  }
706
707  /// Insert a new value for the [If-Match](opt::known::repeat::IF_MATCH) option,
708  /// alongside any existing values.
709  #[doc = rfc_7252_doc!("5.10.8.1")]
710  fn add_if_match<B>(&mut self, tag: B) -> Result<(), Self::SetError>
711    where B: AsRef<[u8]>
712  {
713    if let Some(others) = self.remove(opt::known::repeat::IF_MATCH) {
714      others.into_iter()
715            .filter(|v| v.0.len() > 0)
716            .map(|v| self.add(opt::known::repeat::IF_MATCH, v))
717            .collect::<Result<(), _>>()?;
718    }
719
720    self.add(opt::known::repeat::IF_MATCH,
721             tag.as_ref().iter().copied().collect())
722  }
723
724  /// Get all values for the [If-Match](opt::known::repeat::IF_MATCH) option
725  fn if_match(&self) -> Option<&Self::OptValues> {
726    self.get(opt::known::repeat::IF_MATCH)
727  }
728
729  /// Insert a new value for the [Location-Path](opt::known::repeat::LOCATION_PATH) option,
730  /// alongside any existing values.
731  #[doc = rfc_7252_doc!("5.10.7")]
732  fn add_location_path<S>(&mut self, path: S) -> Result<(), Self::SetError>
733    where S: AsRef<str>
734  {
735    self.add(opt::known::repeat::LOCATION_PATH,
736             path.as_ref().as_bytes().iter().copied().collect())
737  }
738
739  /// Get all values for the [Location-Path](opt::known::repeat::LOCATION_PATH) option
740  fn location_path<'a, F>(&'a self) -> Result<F, Utf8Error>
741    where F: FromIterator<&'a str>
742  {
743    self.get_strs(opt::known::repeat::LOCATION_PATH)
744  }
745
746  /// Insert a new value for the [Location-Query](opt::known::repeat::LOCATION_QUERY) option,
747  /// alongside any existing values.
748  #[doc = rfc_7252_doc!("5.10.7")]
749  fn add_location_query<S>(&mut self, query: S) -> Result<(), Self::SetError>
750    where S: AsRef<str>
751  {
752    self.add(opt::known::repeat::LOCATION_QUERY,
753             query.as_ref().as_bytes().iter().copied().collect())
754  }
755
756  /// Get all values for the [Location-Query](opt::known::repeat::LOCATION_QUERY) option
757  fn location_query<'a, F>(&'a self) -> Result<F, Utf8Error>
758    where F: FromIterator<&'a str>
759  {
760    self.get_strs(opt::known::repeat::LOCATION_QUERY)
761  }
762
763  /// Insert a new value for the [ETag](opt::known::repeat::ETAG) option,
764  /// alongside any existing values.
765  #[doc = rfc_7252_doc!("5.10.7")]
766  fn add_etag<B>(&mut self, tag: B) -> Result<(), Self::SetError>
767    where B: AsRef<[u8]>
768  {
769    self.add(opt::known::repeat::ETAG,
770             tag.as_ref().iter().copied().collect())
771  }
772
773  /// Get all values for the [ETag](opt::known::repeat::ETAG) option
774  fn etags(&self) -> Option<&Self::OptValues> {
775    self.get(opt::known::repeat::ETAG)
776  }
777}
778
779impl<PayloadBytes: Array<Item = u8> + AppendCopy<u8>, Options: OptionMap>
780  Message<PayloadBytes, Options>
781{
782  /// Create a new message
783  pub fn new(ty: Type, code: Code, id: Id, token: Token) -> Self {
784    Self { id,
785           token,
786           ty,
787           code,
788           ver: Version::default(),
789           payload: Payload(PayloadBytes::default()),
790           opts: Options::default() }
791  }
792
793  /// Using [`DefaultCacheKey`], get the cache key for
794  /// this request.
795  ///
796  /// The cache key can be used to compare messages for representing
797  /// the same action against the same resource; requests with different
798  /// IDs but the same method and cache-key affecting options
799  /// (ex. path, query parameters) will yield the same cache-key.
800  pub fn cache_key(&self) -> u64 {
801    DefaultCacheKey::default().cache_key(self)
802  }
803
804  /// Get the payload
805  pub fn payload(&self) -> &Payload<PayloadBytes> {
806    &self.payload
807  }
808
809  /// Set the payload, returning the old payload if there was one
810  pub fn set_payload(&mut self, p: Payload<PayloadBytes>) -> Option<Payload<PayloadBytes>> {
811    let mut old: Payload<_> = p;
812    core::mem::swap(&mut old, &mut self.payload);
813    Some(old).filter(|old| old.0.len() > 0)
814  }
815
816  /// Create a new message that ACKs this one.
817  ///
818  /// This needs an [`Id`] to assign to the newly created message.
819  ///
820  /// ```
821  /// // we are a server
822  ///
823  /// use std::net::SocketAddr;
824  ///
825  /// use toad_msg::alloc::Message;
826  /// use toad_msg::Id;
827  ///
828  /// fn server_get_request() -> Option<(SocketAddr, Message)> {
829  ///   // Servery sockety things...
830  ///   # use std::net::{Ipv4Addr, ToSocketAddrs};
831  ///   # use toad_msg::{Type, Code, Token, Version, Payload};
832  ///   # let addr = (Ipv4Addr::new(0, 0, 0, 0), 1234);
833  ///   # let addr = addr.to_socket_addrs().unwrap().next().unwrap();
834  ///   # let msg = Message { code: Code::new(0, 0),
835  ///   #                     id: Id(1),
836  ///   #                     ty: Type::Con,
837  ///   #                     ver: Version(1),
838  ///   #                     token: Token(tinyvec::array_vec!([u8; 8] => 254)),
839  ///   #                     opts: Default::default(),
840  ///   #                     payload: Payload(vec![]) };
841  ///   # Some((addr, msg))
842  /// }
843  ///
844  /// fn server_send_msg(addr: SocketAddr, msg: Message) -> Result<(), ()> {
845  ///   // Message sendy bits...
846  ///   # Ok(())
847  /// }
848  ///
849  /// let (addr, req) = server_get_request().unwrap();
850  /// let ack_id = Id(req.id.0 + 1);
851  /// let ack = req.ack(ack_id);
852  ///
853  /// server_send_msg(addr, ack).unwrap();
854  /// ```
855  pub fn ack(&self, id: Id) -> Self {
856    Self { id,
857           token: self.token,
858           ver: Default::default(),
859           ty: Type::Ack,
860           code: Code::new(0, 0),
861           payload: Payload(Default::default()),
862           opts: Default::default() }
863  }
864
865  fn add(&mut self,
866         n: OptNumber,
867         v: OptValue<Options::OptValue>)
868         -> Result<(), SetOptionError<OptValue<Options::OptValue>, Options::OptValues>> {
869    match (self.remove(n).unwrap_or_default(), &mut self.opts) {
870      | (vals, _) if vals.is_full() => Err(SetOptionError::RepeatedTooManyTimes(v)),
871      | (vals, opts) if opts.is_full() => Err(SetOptionError::TooManyOptions(n, vals)),
872      | (mut vals, opts) => {
873        vals.append(v);
874        opts.insert(n, vals).ok();
875        Ok(())
876      },
877    }
878  }
879
880  fn set(
881    &mut self,
882    n: OptNumber,
883    v: OptValue<Options::OptValue>)
884    -> Result<Option<Options::OptValues>,
885              SetOptionError<OptValue<Options::OptValue>, Options::OptValues>> {
886    Ok(self.remove(n)).and_then(|old| self.add(n, v).map(|_| old))
887  }
888
889  fn count(&self, n: OptNumber) -> usize {
890    self.get(n).map(|a| a.len()).unwrap_or(0)
891  }
892
893  fn get(&self, n: OptNumber) -> Option<&Options::OptValues> {
894    self.opts.get(&n)
895  }
896
897  fn get_first(&self, n: OptNumber) -> Option<&OptValue<Options::OptValue>> {
898    self.get(n).and_then(|vs| vs.get(0))
899  }
900
901  fn get_str(&self, n: OptNumber) -> Result<Option<&str>, Utf8Error> {
902    match self.get_first(n) {
903      | Some(v) => from_utf8(&v.0).map(Some),
904      | _ => Ok(None),
905    }
906  }
907
908  fn get_strs<'a, F>(&'a self, n: OptNumber) -> Result<F, Utf8Error>
909    where F: FromIterator<&'a str>
910  {
911    match self.get(n) {
912      | Some(vs) if vs.len() >= 1 => vs.iter().map(|s| from_utf8(&s.0)).collect(),
913      | _ => Ok(core::iter::empty().collect()),
914    }
915  }
916
917  fn get_u8(&self, n: OptNumber) -> Option<u8> {
918    self.get_first(n)
919        .filter(|bytes| bytes.0.len() == 1)
920        .map(|bytes| bytes.0[0])
921  }
922
923  fn get_u16(&self, n: OptNumber) -> Option<u16> {
924    self.get_first(n)
925        .filter(|bytes| bytes.0.len() == 2)
926        .map(|bytes| u16::from_be_bytes([bytes.0[0], bytes.0[1]]))
927  }
928
929  fn get_u32(&self, n: OptNumber) -> Option<u32> {
930    self.get_first(n)
931        .filter(|bytes| bytes.0.len() == 4)
932        .map(|bytes| u32::from_be_bytes([bytes.0[0], bytes.0[1], bytes.0[2], bytes.0[3]]))
933  }
934
935  fn get_u64(&self, n: OptNumber) -> Option<u64> {
936    self.get_first(n)
937        .filter(|bytes| bytes.0.len() == 8)
938        .map(|bytes| {
939          u64::from_be_bytes([bytes.0[0], bytes.0[1], bytes.0[2], bytes.0[3], bytes.0[4],
940                              bytes.0[5], bytes.0[6], bytes.0[7]])
941        })
942  }
943
944  fn remove(&mut self, n: OptNumber) -> Option<Options::OptValues> {
945    self.opts.remove(&n)
946  }
947}
948
949impl<Bytes: AsRef<[u8]>, PayloadBytes: Array<Item = u8> + AppendCopy<u8>, Options: OptionMap>
950  TryFromBytes<Bytes> for Message<PayloadBytes, Options>
951{
952  type Error = MessageParseError;
953
954  fn try_from_bytes(bytes: Bytes) -> Result<Self, Self::Error> {
955    let mut bytes = Cursor::new(bytes);
956
957    let Byte1 { tkl, ty, ver } = bytes.next()
958                                      .ok_or_else(MessageParseError::eof)?
959                                      .try_into()?;
960
961    if tkl > 8 {
962      return Err(Self::Error::InvalidTokenLength(tkl));
963    }
964
965    let code: Code = bytes.next().ok_or_else(MessageParseError::eof)?.into();
966    let id: Id = Id::try_consume_bytes(&mut bytes)?;
967
968    let token = bytes.take_exact(tkl as usize)
969                     .ok_or_else(MessageParseError::eof)?;
970    let token = tinyvec::ArrayVec::<[u8; 8]>::try_from(token).expect("tkl was checked to be <= 8");
971    let token = Token(token);
972
973    let opts = Options::try_consume_bytes(&mut bytes).map_err(Self::Error::OptParseError)?;
974
975    let mut payload = PayloadBytes::reserve(bytes.remaining());
976    payload.append_copy(bytes.take_until_end());
977    let payload = Payload(payload);
978
979    Ok(Message { id,
980                 ty,
981                 ver,
982                 code,
983                 token,
984                 opts,
985                 payload })
986  }
987}
988
989#[cfg(test)]
990mod tests {
991  use super::*;
992  use crate::alloc;
993
994  #[test]
995  fn parse_msg() {
996    let (expect, msg) = crate::test_msg();
997    assert_eq!(alloc::Message::try_from_bytes(&msg).unwrap(), expect)
998  }
999
1000  #[test]
1001  fn parse_byte1() {
1002    let byte = 0b_01_10_0011u8;
1003    let byte = Byte1::try_from(byte).unwrap();
1004    assert_eq!(byte,
1005               Byte1 { ver: Version(1),
1006                       ty: Type::Ack,
1007                       tkl: 3 })
1008  }
1009
1010  #[test]
1011  fn parse_id() {
1012    let mut id_bytes = Cursor::new(34u16.to_be_bytes());
1013    let id = Id::try_consume_bytes(&mut id_bytes).unwrap();
1014    assert_eq!(id, Id(34));
1015  }
1016}