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
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/// An expansion of a bitmask contained in `CompatibilityTable`.

#[derive(Clone, Copy)]
pub struct CompatibilityEntry {
  /// Whether we support this option from us -> them.

  pub local: bool,
  /// Whether we support this option from them -> us.

  pub remote: bool,
  /// Whether this option is locally enabled.

  pub local_state: bool,
  /// Whether this option is remotely enabled.

  pub remote_state: bool,
}

impl CompatibilityEntry {
  pub fn new(local: bool, remote: bool, local_state: bool, remote_state: bool) -> Self {
    Self {
      local,
      remote,
      local_state,
      remote_state,
    }
  }
  /// Creates a u8 bitmask from this entry.

  pub fn into_u8(self) -> u8 {
    let mut res: u8 = 0;
    if self.local {
      res |= CompatibilityTable::ENABLED_LOCAL;
    }
    if self.remote {
      res |= CompatibilityTable::ENABLED_REMOTE;
    }
    if self.local_state {
      res |= CompatibilityTable::LOCAL_STATE;
    }
    if self.remote_state {
      res |= CompatibilityTable::REMOTE_STATE;
    }
    res
  }
  /// Expands a u8 bitmask into a CompatibilityEntry.

  pub fn from(value: u8) -> Self {
    Self {
      local: value & CompatibilityTable::ENABLED_LOCAL == CompatibilityTable::ENABLED_LOCAL,
      remote: value & CompatibilityTable::ENABLED_REMOTE == CompatibilityTable::ENABLED_REMOTE,
      local_state: value & CompatibilityTable::LOCAL_STATE == CompatibilityTable::LOCAL_STATE,
      remote_state: value & CompatibilityTable::REMOTE_STATE == CompatibilityTable::REMOTE_STATE,
    }
  }
}

/// A table of options that are supported locally or remotely, and their current state.

#[derive(Clone)]
pub struct CompatibilityTable {
  options: [u8; 256],
}

impl Default for CompatibilityTable {
  fn default() -> Self {
    Self { options: [0; 256] }
  }
}

impl CompatibilityTable {
  /// Option is locally supported.

  pub const ENABLED_LOCAL: u8 = 1;
  /// Option is remotely supported.

  pub const ENABLED_REMOTE: u8 = 1 << 1;
  /// Option is currently enabled locally.

  pub const LOCAL_STATE: u8 = 1 << 2;
  /// Option is currently enabled remotely.

  pub const REMOTE_STATE: u8 = 1 << 3;
  pub fn new() -> Self {
    Self::default()
  }
  /// Create a table with some option values set.

  ///

  /// # Arguments

  ///

  /// `values` - A slice of `(u8, u8)` tuples. The first value is the option code, and the second is the bitmask value for that option.

  ///

  /// # Notes

  ///

  /// An option bitmask can be generated using the `CompatibilityEntry` struct, using `entry.into_u8()`.

  pub fn from_options(values: &[(u8, u8)]) -> Self {
    let mut options: [u8; 256] = [0; 256];
    for (opt, val) in values {
      options[*opt as usize] = *val;
    }
    Self { options }
  }
  /// Enable local support for an option.

  pub fn support_local(&mut self, option: u8) {
    let mut opt = CompatibilityEntry::from(self.options[option as usize]);
    opt.local = true;
    self.set_option(option, opt);
  }
  /// Enable remote support for an option.

  pub fn support_remote(&mut self, option: u8) {
    let mut opt = CompatibilityEntry::from(self.options[option as usize]);
    opt.remote = true;
    self.set_option(option, opt);
  }
  /// Enable both remote and local support for an option.

  pub fn support(&mut self, option: u8) {
    let mut opt = CompatibilityEntry::from(self.options[option as usize]);
    opt.local = true;
    opt.remote = true;
    self.set_option(option, opt);
  }
  /// Retrieve a `CompatbilityEntry` generated from the current state of the option value.

  pub fn get_option(&self, option: u8) -> CompatibilityEntry {
    CompatibilityEntry::from(self.options[option as usize])
  }
  /// Set an option value by getting the bitmask from a `CompatibilityEntry`.

  pub fn set_option(&mut self, option: u8, entry: CompatibilityEntry) {
    self.options[option as usize] = entry.clone().into_u8();
  }

  /// Reset all negotiated states

  pub fn reset_states(&mut self) {
    for opt in self.options.iter_mut() {
      let mut entry = CompatibilityEntry::from(*opt);
      entry.local_state = false;
      entry.remote_state = false;
      *opt = entry.into_u8();
    }
  }
}

#[cfg(test)]
mod test_compat {
  use super::*;

  #[test]
  fn test_reset() {
    let mut table = CompatibilityTable::default();
    let entry = CompatibilityEntry::new(true, true, true, true);
    assert_eq!(entry.remote, true);
    assert_eq!(entry.local, true);
    assert_eq!(entry.remote_state, true);
    assert_eq!(entry.local_state, true);
    table.set_option(201, entry);
    table.reset_states();
    let entry = table.get_option(201);
    assert_eq!(entry.remote, true);
    assert_eq!(entry.local, true);
    assert_eq!(entry.remote_state, false);
    assert_eq!(entry.local_state, false);
  }
}