1use std::io::{self, BufRead, BufReader, Read, Write};
3
4use crate::{
5 error::ReadError,
6 protocol::{Message, Version, XvcInfo},
7};
8
9const XVC_INFO_PREFIX: &[u8] = b"xvcServer";
10
11impl XvcInfo {
12 pub fn write_to(&self, writer: &mut impl Write) -> io::Result<()> {
13 writeln!(
14 writer,
15 "xvcServer_v{}:{}",
16 self.version(),
17 self.max_vector_len()
18 )
19 }
20
21 pub fn from_reader(reader: &mut impl Read) -> Result<XvcInfo, ReadError> {
22 let mut buf_reader = BufReader::with_capacity(32, reader);
23 let mut line = Vec::with_capacity(32);
24 let _ = buf_reader.read_until(b'\n', &mut line)?;
25
26 let mut line = line.trim_ascii_end();
28
29 if !line.starts_with(XVC_INFO_PREFIX) {
31 return Err(ReadError::InvalidFormat(
32 "Invalid prefix in info message".to_string(),
33 ));
34 }
35
36 line = &line[XVC_INFO_PREFIX.len()..];
37 if line[0] != b'_' {
38 return Err(ReadError::InvalidFormat(
39 "Missing '_' separator".to_string(),
40 ));
41 }
42
43 line = &line[1..];
44 if line[0] != b'v' {
45 return Err(ReadError::InvalidFormat(
46 "Version must start with 'v".to_string(),
47 ));
48 }
49
50 line = &line[1..];
51 let colon_index = line.iter().position(|l| *l == b':').ok_or_else(|| {
52 ReadError::InvalidFormat("Missing ':' separator in info message".to_string())
53 })?;
54
55 let (version_part, rest) = line.split_at(colon_index);
56
57 let version = match version_part {
58 b"1.0" => Version::V1_0,
59 _ => {
60 return Err(ReadError::UnsupportedVersion(
61 String::from_utf8_lossy(version_part).to_string(),
62 ));
63 }
64 };
65
66 let max_vector_len = str::from_utf8(&rest[1..])?.parse::<u32>()?;
67
68 Ok(XvcInfo::new(version, max_vector_len))
69 }
70}
71
72#[test]
73fn write_server_info() {
74 let mut out = Vec::new();
75 XvcInfo::default().write_to(&mut out).unwrap();
76 assert_eq!(out, b"xvcServer_v1.0:10485760\n".to_vec());
77}
78
79#[test]
80fn read_server_info() {
81 let data = b"xvcServer_v1.0:32\n";
82 let mut cursor = std::io::Cursor::new(data);
83 let info = XvcInfo::from_reader(&mut cursor).unwrap();
84 assert_eq!(info.version(), Version::V1_0);
85 assert_eq!(info.max_vector_len(), 32)
86}
87
88impl Message {
89 const CMD_NAME_GET_INFO: &[u8; 7] = b"getinfo";
90 const CMD_NAME_SET_TCK: &[u8; 6] = b"settck";
91 const CMD_NAME_SHIFT: &[u8; 5] = b"shift";
92 const CMD_DELIMITER: u8 = b':';
93
94 pub fn from_reader(
95 reader: &mut impl Read,
96 max_shift_bytes: usize,
97 ) -> Result<Message, ReadError> {
98 let mut buf = [0u8; 16];
100 reader.read_exact(&mut buf[..2])?;
102 match &buf[..2] {
103 b"ge" => {
104 reader.read_exact(&mut buf[2..Self::CMD_NAME_GET_INFO.len() + 1])?;
105 if &buf[..Self::CMD_NAME_GET_INFO.len()] != Self::CMD_NAME_GET_INFO
106 || buf[Self::CMD_NAME_GET_INFO.len()] != Self::CMD_DELIMITER
107 {
108 return Err(ReadError::InvalidCommand(
109 String::from_utf8_lossy(&buf).to_string(),
110 ));
111 }
112 Ok(Message::GetInfo)
113 }
114 b"se" => {
115 reader.read_exact(&mut buf[2..Self::CMD_NAME_SET_TCK.len() + 1 + 4])?;
116 if &buf[..Self::CMD_NAME_SET_TCK.len()] != Self::CMD_NAME_SET_TCK
117 || buf[Self::CMD_NAME_SET_TCK.len()] != Self::CMD_DELIMITER
118 {
119 return Err(ReadError::InvalidCommand(
120 String::from_utf8_lossy(&buf).to_string(),
121 ));
122 }
123 let period = u32::from_le_bytes(
124 buf[Self::CMD_NAME_SET_TCK.len() + 1..Self::CMD_NAME_SET_TCK.len() + 5]
125 .try_into()
126 .unwrap(),
127 );
128 Ok(Message::SetTck { period_ns: period })
129 }
130 b"sh" => {
131 reader.read_exact(&mut buf[2..Self::CMD_NAME_SHIFT.len() + 1 + 4])?;
132 if &buf[..Self::CMD_NAME_SHIFT.len()] != Self::CMD_NAME_SHIFT
133 || buf[Self::CMD_NAME_SHIFT.len()] != Self::CMD_DELIMITER
134 {
135 return Err(ReadError::InvalidCommand(
136 String::from_utf8_lossy(&buf).to_string(),
137 ));
138 }
139 let num_bits = u32::from_le_bytes(
140 buf[Self::CMD_NAME_SHIFT.len() + 1..Self::CMD_NAME_SHIFT.len() + 5]
141 .try_into()
142 .unwrap(),
143 );
144 let num_bytes = num_bits.div_ceil(8_u32) as usize;
145 if num_bytes > max_shift_bytes {
146 return Err(ReadError::TooManyBytes {
147 max: max_shift_bytes,
148 got: num_bytes,
149 });
150 }
151 let mut tms_vector = vec![0_u8; num_bytes].into_boxed_slice();
152 reader.read_exact(&mut tms_vector[..])?;
153 let mut tdi_vector = vec![0_u8; num_bytes].into_boxed_slice();
154 reader.read_exact(&mut tdi_vector[..])?;
155 Ok(Message::Shift {
156 num_bits,
157 tms: tms_vector,
158 tdi: tdi_vector,
159 })
160 }
161 _ => Err(ReadError::InvalidCommandPrefix(
162 String::from_utf8_lossy(&buf[..2]).to_string(),
163 )),
164 }
165 }
166
167 pub fn write_to(&self, writer: &mut impl Write) -> io::Result<()> {
168 match self {
169 Message::GetInfo => {
170 writer.write_all(Self::CMD_NAME_GET_INFO)?;
171 writer.write_all(&[Self::CMD_DELIMITER])
172 }
173 Message::SetTck {
174 period_ns: period_in_ns,
175 } => {
176 writer.write_all(Self::CMD_NAME_SET_TCK)?;
177 writer.write_all(&[Self::CMD_DELIMITER])?;
178 writer.write_all(&period_in_ns.to_le_bytes())
179 }
180 Message::Shift {
181 num_bits,
182 tms: tms_vector,
183 tdi: tdi_vector,
184 } => {
185 writer.write_all(Self::CMD_NAME_SHIFT)?;
186 writer.write_all(&[Self::CMD_DELIMITER])?;
187 writer.write_all(&num_bits.to_le_bytes())?;
188 writer.write_all(tms_vector)?;
189 writer.write_all(tdi_vector)
190 }
191 }
192 }
193}
194
195#[cfg(test)]
196mod test {
197 use crate::error::ReadError;
198 use crate::protocol::Message;
199 use std::io::Cursor;
200
201 const DEFAULT_MAX_SHIFT_BYTES: usize = 1024;
202
203 #[test]
204 fn read_getinfo() {
205 let data = b"getinfo:".to_vec();
206 let mut cursor = Cursor::new(data);
207 match Message::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
208 Message::GetInfo => {}
209 _ => panic!("expected GetInfo"),
210 }
211 }
212
213 #[test]
214 fn write_getinfo() {
215 let mut out = Vec::new();
216 Message::GetInfo.write_to(&mut out).unwrap();
217 assert_eq!(out, b"getinfo:".to_vec());
218 }
219
220 #[test]
221 fn read_settck() {
222 let period: u32 = 0x1234_5678;
223 let mut data = b"settck:".to_vec();
224 data.extend_from_slice(&period.to_le_bytes());
225 let mut cursor = Cursor::new(data);
226 match Message::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
227 Message::SetTck {
228 period_ns: period_in_ns,
229 } => assert_eq!(period_in_ns, period),
230 _ => panic!("expected SetTck"),
231 }
232 }
233
234 #[test]
235 fn write_settck() {
236 let period: u32 = 0x1234_5678;
237 let mut out = Vec::new();
238 Message::SetTck { period_ns: period }
239 .write_to(&mut out)
240 .unwrap();
241 let mut expected = b"settck:".to_vec();
242 expected.extend_from_slice(&period.to_le_bytes());
243 assert_eq!(out, expected);
244 }
245
246 #[test]
247 fn read_shift() {
248 let num_bits: u32 = 13; let num_bytes = ((num_bits + 7) / 8) as usize;
250 let tms = vec![0xAAu8; num_bytes];
251 let tdi = vec![0x55u8; num_bytes];
252
253 let mut data = b"shift:".to_vec();
254 data.extend_from_slice(&num_bits.to_le_bytes());
255 data.extend_from_slice(&tms);
256 data.extend_from_slice(&tdi);
257
258 let mut cursor = Cursor::new(data);
259 match Message::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
260 Message::Shift {
261 num_bits: nb,
262 tms: tms_vector,
263 tdi: tdi_vector,
264 } => {
265 assert_eq!(nb, num_bits);
266 assert_eq!(&*tms_vector, &tms[..]);
267 assert_eq!(&*tdi_vector, &tdi[..]);
268 }
269 _ => panic!("expected Shift"),
270 }
271 }
272
273 #[test]
274 fn write_shift() {
275 let num_bits: u32 = 13; let num_bytes = ((num_bits + 7) / 8) as usize;
277 let tms = vec![0xAAu8; num_bytes].into_boxed_slice();
278 let tdi = vec![0x55u8; num_bytes].into_boxed_slice();
279
280 let cmd = Message::Shift {
281 num_bits,
282 tms: tms.clone(),
283 tdi: tdi.clone(),
284 };
285 let mut out = Vec::new();
286 cmd.write_to(&mut out).unwrap();
287
288 let mut expected = b"shift:".to_vec();
289 expected.extend_from_slice(&num_bits.to_le_bytes());
290 expected.extend_from_slice(&*tms);
291 expected.extend_from_slice(&*tdi);
292
293 assert_eq!(out, expected);
294 }
295
296 #[test]
297 fn invalid_prefix() {
298 let data = b"xx".to_vec();
299 let mut cursor = Cursor::new(data);
300 match Message::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
301 Err(ReadError::InvalidCommandPrefix(p)) => assert_eq!(p, "xx"),
302 other => panic!("expected InvalidCommandPrefix, got {:?}", other),
303 }
304 }
305
306 #[test]
307 fn too_many_bytes_shift() {
308 let num_bytes_exceed = 1024 + 1;
310 let num_bits = (num_bytes_exceed * 8) as u32;
311 let mut data = b"shift:".to_vec();
312 data.extend_from_slice(&num_bits.to_le_bytes());
313 let mut cursor = Cursor::new(data);
314 match Message::from_reader(&mut cursor, 1024) {
315 Err(ReadError::TooManyBytes { max, got }) => {
316 assert_eq!(max, 1024);
317 assert_eq!(got, num_bytes_exceed);
318 }
319 other => panic!("expected TooManyBytes, got {:?}", other),
320 }
321 }
322}