1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use speedy::{Context, Readable, Writable, Writer};

use crate::{
  messages::submessages::submessage_elements::parameter::Parameter,
  structure::parameter_id::ParameterId,
};

/// ParameterList is used as part of several messages to encapsulate
/// QoS parameters that may affect the interpretation of the message.
/// The encapsulation of the parameters follows a mechanism that allows
/// extensions to the QoS without breaking backwards compatibility.
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct ParameterList {
  pub parameters: Vec<Parameter>,
}

impl ParameterList {
  pub fn new() -> Self {
    Self::default()
  }

  pub fn is_empty(&self) -> bool {
    self.parameters.is_empty()
  }

  pub fn len_serialized(&self) -> usize {
    self.parameters.iter().map(|p| p.len_serialized()).sum()
  }
}

const SENTINEL: u32 = 0x00000001;

impl<C: Context> Writable<C> for ParameterList {
  #[inline]
  fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
    for param in &self.parameters {
      writer.write_value(param)?;
    }

    writer.write_u32(SENTINEL)?;

    Ok(())
  }
}

impl<'a, C: Context> Readable<'a, C> for ParameterList {
  #[inline]
  fn read_from<R: speedy::Reader<'a, C>>(reader: &mut R) -> Result<Self, C::Error> {
    let mut parameters = Self::default();

    // loop ends in failure to read something or catching sentinel
    loop {
      let parameter_id = ParameterId::read_from(reader)?;
      let length = u16::read_from(reader)?;

      if parameter_id == ParameterId::PID_SENTINEL {
        // This is paramter list end marker.
        return Ok(parameters);
      }

      parameters.parameters.push(Parameter {
        parameter_id,
        value: reader.read_vec(length as usize)?,
      });
    }
  }
}