1use crate::{GitError, Result};
7use std::io::{Read, Write};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum PktLine {
12 Data(Vec<u8>),
14 Flush,
16 Delimiter,
18 ResponseEnd,
20}
21
22impl PktLine {
23 pub fn from_string(s: &str) -> Self {
25 Self::Data(s.as_bytes().to_vec())
26 }
27
28 pub fn from_bytes(b: impl Into<Vec<u8>>) -> Self {
30 Self::Data(b.into())
31 }
32
33 pub fn encode(&self) -> Vec<u8> {
35 match self {
36 Self::Data(data) => {
37 let len = data.len() + 4; let mut result = format!("{:04x}", len).into_bytes();
39 result.extend_from_slice(data);
40 result
41 }
42 Self::Flush => b"0000".to_vec(),
43 Self::Delimiter => b"0001".to_vec(),
44 Self::ResponseEnd => b"0002".to_vec(),
45 }
46 }
47
48 pub fn is_flush(&self) -> bool {
50 matches!(self, Self::Flush)
51 }
52
53 pub fn data(&self) -> Option<&[u8]> {
55 match self {
56 Self::Data(data) => Some(data),
57 _ => None,
58 }
59 }
60
61 pub fn as_str(&self) -> Option<&str> {
63 self.data()
64 .and_then(|d| std::str::from_utf8(d).ok())
65 .map(|s| s.trim_end_matches('\n'))
66 }
67}
68
69pub struct PktLineReader<R> {
71 reader: R,
72}
73
74impl<R: Read> PktLineReader<R> {
75 pub fn new(reader: R) -> Self {
77 Self { reader }
78 }
79
80 pub fn read(&mut self) -> Result<Option<PktLine>> {
82 let mut len_buf = [0u8; 4];
83 match self.reader.read_exact(&mut len_buf) {
84 Ok(()) => {}
85 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Ok(None),
86 Err(e) => return Err(e.into()),
87 }
88
89 let len_str = std::str::from_utf8(&len_buf)
90 .map_err(|_| GitError::InvalidPktLine("invalid length prefix".to_string()))?;
91
92 match len_str {
93 "0000" => Ok(Some(PktLine::Flush)),
94 "0001" => Ok(Some(PktLine::Delimiter)),
95 "0002" => Ok(Some(PktLine::ResponseEnd)),
96 _ => {
97 let len = u16::from_str_radix(len_str, 16)
98 .map_err(|_| GitError::InvalidPktLine("invalid length".to_string()))?
99 as usize;
100
101 if len < 4 {
102 return Err(GitError::InvalidPktLine("length too small".to_string()));
103 }
104
105 let data_len = len - 4;
106 let mut data = vec![0u8; data_len];
107 self.reader.read_exact(&mut data)?;
108
109 Ok(Some(PktLine::Data(data)))
110 }
111 }
112 }
113
114 pub fn read_until_flush(&mut self) -> Result<Vec<PktLine>> {
116 let mut packets = Vec::new();
117 loop {
118 match self.read()? {
119 Some(PktLine::Flush) | None => break,
120 Some(pkt) => packets.push(pkt),
121 }
122 }
123 Ok(packets)
124 }
125
126 pub fn inner_mut(&mut self) -> &mut R {
128 &mut self.reader
129 }
130
131 pub fn into_inner(self) -> R {
133 self.reader
134 }
135}
136
137pub struct PktLineWriter<W> {
139 writer: W,
140}
141
142impl<W: Write> PktLineWriter<W> {
143 pub fn new(writer: W) -> Self {
145 Self { writer }
146 }
147
148 pub fn write(&mut self, pkt: &PktLine) -> Result<()> {
150 self.writer.write_all(&pkt.encode())?;
151 Ok(())
152 }
153
154 pub fn write_data(&mut self, data: &[u8]) -> Result<()> {
156 self.write(&PktLine::Data(data.to_vec()))
157 }
158
159 pub fn write_line(&mut self, s: &str) -> Result<()> {
161 let mut data = s.as_bytes().to_vec();
162 if !s.ends_with('\n') {
163 data.push(b'\n');
164 }
165 self.write(&PktLine::Data(data))
166 }
167
168 pub fn flush_pkt(&mut self) -> Result<()> {
170 self.write(&PktLine::Flush)
171 }
172
173 pub fn flush(&mut self) -> Result<()> {
175 self.writer.flush()?;
176 Ok(())
177 }
178
179 pub fn into_inner(self) -> W {
181 self.writer
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use std::io::Cursor;
189
190 #[test]
191 fn test_pktline_encode() {
192 assert_eq!(PktLine::from_string("hello\n").encode(), b"000ahello\n");
193 assert_eq!(PktLine::Flush.encode(), b"0000");
194 assert_eq!(PktLine::Delimiter.encode(), b"0001");
195 }
196
197 #[test]
198 fn test_pktline_roundtrip() {
199 let packets = vec![
200 PktLine::from_string("hello\n"),
201 PktLine::from_string("world\n"),
202 PktLine::Flush,
203 ];
204
205 let mut buf = Vec::new();
206 {
207 let mut writer = PktLineWriter::new(&mut buf);
208 for pkt in &packets {
209 writer.write(pkt).unwrap();
210 }
211 }
212
213 let mut reader = PktLineReader::new(Cursor::new(buf));
214 assert_eq!(reader.read().unwrap(), Some(packets[0].clone()));
215 assert_eq!(reader.read().unwrap(), Some(packets[1].clone()));
216 assert_eq!(reader.read().unwrap(), Some(PktLine::Flush));
217 }
218
219 #[test]
220 fn test_pktline_response_end() {
221 assert_eq!(PktLine::ResponseEnd.encode(), b"0002");
222 }
223
224 #[test]
225 fn test_pktline_from_bytes() {
226 let pkt = PktLine::from_bytes(b"test data".to_vec());
227 assert_eq!(pkt.data(), Some(b"test data".as_slice()));
228 }
229
230 #[test]
231 fn test_pktline_is_flush() {
232 assert!(PktLine::Flush.is_flush());
233 assert!(!PktLine::from_string("test").is_flush());
234 assert!(!PktLine::Delimiter.is_flush());
235 assert!(!PktLine::ResponseEnd.is_flush());
236 }
237
238 #[test]
239 fn test_pktline_data() {
240 let pkt = PktLine::from_string("hello");
241 assert_eq!(pkt.data(), Some(b"hello".as_slice()));
242
243 assert!(PktLine::Flush.data().is_none());
244 assert!(PktLine::Delimiter.data().is_none());
245 assert!(PktLine::ResponseEnd.data().is_none());
246 }
247
248 #[test]
249 fn test_pktline_as_str() {
250 let pkt = PktLine::from_string("hello\n");
251 assert_eq!(pkt.as_str(), Some("hello"));
252
253 let pkt2 = PktLine::from_string("no newline");
254 assert_eq!(pkt2.as_str(), Some("no newline"));
255 }
256
257 #[test]
258 fn test_pktline_as_str_invalid_utf8() {
259 let pkt = PktLine::from_bytes(vec![0xff, 0xfe]);
260 assert!(pkt.as_str().is_none());
261 }
262
263 #[test]
264 fn test_pktline_reader_eof() {
265 let reader = PktLineReader::new(Cursor::new(Vec::<u8>::new()));
266 let result = reader.into_inner();
267 assert_eq!(result.position(), 0);
268 }
269
270 #[test]
271 fn test_pktline_read_until_flush() {
272 let mut buf = Vec::new();
273 {
274 let mut writer = PktLineWriter::new(&mut buf);
275 writer.write_line("line1").unwrap();
276 writer.write_line("line2").unwrap();
277 writer.flush_pkt().unwrap();
278 writer.write_line("line3").unwrap();
279 }
280
281 let mut reader = PktLineReader::new(Cursor::new(buf));
282 let packets = reader.read_until_flush().unwrap();
283 assert_eq!(packets.len(), 2);
284 }
285
286 #[test]
287 fn test_pktline_writer_write_line() {
288 let mut buf = Vec::new();
289 {
290 let mut writer = PktLineWriter::new(&mut buf);
291 writer.write_line("test").unwrap();
292 }
293 assert!(buf.starts_with(b"0009"));
295 assert!(buf.ends_with(b"test\n"));
296 }
297
298 #[test]
299 fn test_pktline_writer_write_line_with_newline() {
300 let mut buf = Vec::new();
301 {
302 let mut writer = PktLineWriter::new(&mut buf);
303 writer.write_line("test\n").unwrap();
304 }
305 assert!(buf.ends_with(b"test\n"));
307 assert!(!buf.ends_with(b"test\n\n"));
308 }
309
310 #[test]
311 fn test_pktline_writer_write_data() {
312 let mut buf = Vec::new();
313 {
314 let mut writer = PktLineWriter::new(&mut buf);
315 writer.write_data(b"binary\x00data").unwrap();
316 }
317 assert!(buf.len() > 4); }
319
320 #[test]
321 fn test_pktline_writer_flush() {
322 let mut buf = Vec::new();
323 {
324 let mut writer = PktLineWriter::new(&mut buf);
325 writer.write_line("test").unwrap();
326 writer.flush().unwrap();
327 }
328 assert!(!buf.is_empty());
330 }
331
332 #[test]
333 fn test_pktline_writer_into_inner() {
334 let buf = Vec::new();
335 let writer = PktLineWriter::new(buf);
336 let inner = writer.into_inner();
337 assert!(inner.is_empty());
338 }
339
340 #[test]
341 fn test_pktline_reader_inner_mut() {
342 let cursor = Cursor::new(Vec::<u8>::new());
343 let mut reader = PktLineReader::new(cursor);
344 let inner = reader.inner_mut();
345 assert_eq!(inner.position(), 0);
346 }
347
348 #[test]
349 fn test_pktline_read_delimiter() {
350 let mut buf = Vec::new();
351 buf.extend_from_slice(b"0001");
352
353 let mut reader = PktLineReader::new(Cursor::new(buf));
354 assert_eq!(reader.read().unwrap(), Some(PktLine::Delimiter));
355 }
356
357 #[test]
358 fn test_pktline_read_response_end() {
359 let mut buf = Vec::new();
360 buf.extend_from_slice(b"0002");
361
362 let mut reader = PktLineReader::new(Cursor::new(buf));
363 assert_eq!(reader.read().unwrap(), Some(PktLine::ResponseEnd));
364 }
365
366 #[test]
367 fn test_pktline_equality() {
368 assert_eq!(PktLine::Flush, PktLine::Flush);
369 assert_eq!(PktLine::Delimiter, PktLine::Delimiter);
370 assert_eq!(PktLine::ResponseEnd, PktLine::ResponseEnd);
371 assert_eq!(PktLine::from_string("test"), PktLine::from_string("test"));
372 assert_ne!(PktLine::Flush, PktLine::Delimiter);
373 }
374
375 #[test]
376 fn test_pktline_clone() {
377 let pkt = PktLine::from_string("test");
378 let cloned = pkt.clone();
379 assert_eq!(pkt, cloned);
380 }
381
382 #[test]
383 fn test_pktline_debug() {
384 let pkt = PktLine::Flush;
385 let debug = format!("{:?}", pkt);
386 assert!(debug.contains("Flush"));
387 }
388
389 #[test]
390 fn test_pktline_read_invalid_length() {
391 let mut buf = Vec::new();
392 buf.extend_from_slice(b"0003"); let mut reader = PktLineReader::new(Cursor::new(buf));
395 let result = reader.read();
396 assert!(result.is_err());
397 }
398
399 #[test]
400 fn test_pktline_large_packet() {
401 let data = "x".repeat(1000);
402 let pkt = PktLine::from_string(&data);
403 let encoded = pkt.encode();
404
405 let mut reader = PktLineReader::new(Cursor::new(encoded));
407 let read_pkt = reader.read().unwrap().unwrap();
408 assert_eq!(read_pkt.data().unwrap().len(), 1000);
409 }
410
411 #[test]
412 fn test_pktline_empty_data() {
413 let pkt = PktLine::from_bytes(Vec::new());
414 let encoded = pkt.encode();
415 assert_eq!(&encoded[..4], b"0004"); }
417
418 #[test]
419 fn test_pktline_read_eof_on_empty() {
420 let mut reader = PktLineReader::new(Cursor::new(Vec::<u8>::new()));
421 let result = reader.read().unwrap();
422 assert!(result.is_none());
423 }
424}