libmudtelnet_rs/
compatibility.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub struct CompatibilityEntry {
30 pub local: bool,
32 pub remote: bool,
34 pub local_state: bool,
36 pub remote_state: bool,
38}
39
40impl CompatibilityEntry {
41 #[must_use]
42 pub fn new(local: bool, remote: bool, local_state: bool, remote_state: bool) -> Self {
43 Self {
44 local,
45 remote,
46 local_state,
47 remote_state,
48 }
49 }
50
51 #[must_use]
53 pub fn into_u8(self) -> u8 {
54 let mut res = 0;
55 if self.local {
56 res |= CompatibilityTable::ENABLED_LOCAL;
57 }
58 if self.remote {
59 res |= CompatibilityTable::ENABLED_REMOTE;
60 }
61 if self.local_state {
62 res |= CompatibilityTable::LOCAL_STATE;
63 }
64 if self.remote_state {
65 res |= CompatibilityTable::REMOTE_STATE;
66 }
67 res
68 }
69
70 #[must_use]
72 pub fn from(value: u8) -> Self {
73 Self {
74 local: value & CompatibilityTable::ENABLED_LOCAL == CompatibilityTable::ENABLED_LOCAL,
75 remote: value & CompatibilityTable::ENABLED_REMOTE == CompatibilityTable::ENABLED_REMOTE,
76 local_state: value & CompatibilityTable::LOCAL_STATE == CompatibilityTable::LOCAL_STATE,
77 remote_state: value & CompatibilityTable::REMOTE_STATE == CompatibilityTable::REMOTE_STATE,
78 }
79 }
80}
81
82#[derive(Clone, Debug, Eq, PartialEq)]
84pub struct CompatibilityTable {
85 options: [u8; 256],
86}
87
88impl Default for CompatibilityTable {
89 fn default() -> Self {
90 Self { options: [0; 256] }
91 }
92}
93
94impl CompatibilityTable {
95 pub const ENABLED_LOCAL: u8 = 1;
97 pub const ENABLED_REMOTE: u8 = 1 << 1;
99 pub const LOCAL_STATE: u8 = 1 << 2;
101 pub const REMOTE_STATE: u8 = 1 << 3;
103
104 #[must_use]
105 pub fn new() -> Self {
106 Self::default()
107 }
108
109 #[must_use]
119 pub fn from_options(values: &[(u8, u8)]) -> Self {
120 let mut options = [0; 256];
121 for (opt, val) in values {
122 options[*opt as usize] = *val;
123 }
124 Self { options }
125 }
126
127 pub fn support_local(&mut self, option: u8) {
129 let mut opt = CompatibilityEntry::from(self.options[option as usize]);
130 opt.local = true;
131 self.set_option(option, opt);
132 }
133
134 pub fn support_remote(&mut self, option: u8) {
136 let mut opt = CompatibilityEntry::from(self.options[option as usize]);
137 opt.remote = true;
138 self.set_option(option, opt);
139 }
140
141 pub fn support(&mut self, option: u8) {
143 let mut opt = CompatibilityEntry::from(self.options[option as usize]);
144 opt.local = true;
145 opt.remote = true;
146 self.set_option(option, opt);
147 }
148
149 #[must_use]
151 pub fn get_option(&self, option: u8) -> CompatibilityEntry {
152 CompatibilityEntry::from(self.options[option as usize])
153 }
154
155 pub fn set_option(&mut self, option: u8, entry: CompatibilityEntry) {
157 self.options[option as usize] = entry.into_u8();
158 }
159
160 pub fn reset_states(&mut self) {
162 for opt in &mut self.options {
163 let mut entry = CompatibilityEntry::from(*opt);
164 entry.local_state = false;
165 entry.remote_state = false;
166 *opt = entry.into_u8();
167 }
168 }
169}
170
171#[cfg(test)]
172mod test_compat {
173 use super::*;
174 use crate::telnet::op_option::GMCP;
175
176 #[test]
177 fn test_reset() {
178 let mut table = CompatibilityTable::default();
179 let entry = CompatibilityEntry::new(true, true, true, true);
180 assert!(entry.remote);
181 assert!(entry.local);
182 assert!(entry.remote_state);
183 assert!(entry.local_state);
184 table.set_option(GMCP, entry);
185 table.reset_states();
186 let entry = table.get_option(GMCP);
187 assert!(entry.remote);
188 assert!(entry.local);
189 assert!(!entry.remote_state);
190 assert!(!entry.local_state);
191 }
192}