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
#[derive(Clone, Copy)]
pub struct CompatibilityEntry {
pub local: bool,
pub remote: bool,
pub local_state: bool,
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,
}
}
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
}
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,
}
}
}
#[derive(Clone)]
pub struct CompatibilityTable {
options: [u8; 256],
}
impl Default for CompatibilityTable {
fn default() -> Self {
Self { options: [0; 256] }
}
}
impl CompatibilityTable {
pub const ENABLED_LOCAL: u8 = 1;
pub const ENABLED_REMOTE: u8 = 1 << 1;
pub const LOCAL_STATE: u8 = 1 << 2;
pub const REMOTE_STATE: u8 = 1 << 3;
pub fn new() -> Self {
Self::default()
}
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 }
}
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);
}
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);
}
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);
}
pub fn get_option(&self, option: u8) -> CompatibilityEntry {
CompatibilityEntry::from(self.options[option as usize])
}
pub fn set_option(&mut self, option: u8, entry: CompatibilityEntry) {
self.options[option as usize] = entry.clone().into_u8();
}
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);
}
}