| 1 | //! pkt-line encoding as defined by Git protocol. |
| 2 | //! Format: 4-hex-digit length prefix (includes the 4 bytes) + content. |
| 3 | //! Flush packet: "0000" |
| 4 | |
| 5 | /// Encode a single pkt-line. |
| 6 | pub fn encode(data: &[u8]) -> Vec<u8> { |
| 7 | let len = data.len() + 4; |
| 8 | let mut buf = format!("{len:04x}").into_bytes(); |
| 9 | buf.extend_from_slice(data); |
| 10 | buf |
| 11 | } |
| 12 | |
| 13 | /// Encode a flush packet. |
| 14 | pub fn flush() -> &'static [u8] { |
| 15 | b"0000" |
| 16 | } |
| 17 | |
| 18 | /// Encode a comment line (e.g. "# service=git-upload-pack\n"). |
| 19 | pub fn encode_comment(comment: &str) -> Vec<u8> { |
| 20 | encode(format!("# {comment}\n").as_bytes()) |
| 21 | } |
| 22 | |
| 23 | #[cfg(test)] |
| 24 | mod tests { |
| 25 | use super::*; |
| 26 | |
| 27 | #[test] |
| 28 | fn encode_simple_line() { |
| 29 | let encoded = encode(b"hello\n"); |
| 30 | assert_eq!(&encoded, b"000ahello\n"); |
| 31 | } |
| 32 | |
| 33 | #[test] |
| 34 | fn encode_empty_content() { |
| 35 | let encoded = encode(b""); |
| 36 | assert_eq!(&encoded, b"0004"); |
| 37 | } |
| 38 | |
| 39 | #[test] |
| 40 | fn encode_comment_line() { |
| 41 | let encoded = encode_comment("service=git-upload-pack"); |
| 42 | assert_eq!(&encoded, b"001e# service=git-upload-pack\n"); |
| 43 | } |
| 44 | |
| 45 | #[test] |
| 46 | fn flush_packet() { |
| 47 | assert_eq!(flush(), b"0000"); |
| 48 | } |
| 49 | |
| 50 | #[test] |
| 51 | fn encode_ref_line() { |
| 52 | let hash = "0000000000000000000000000000000000000000"; |
| 53 | let line = format!("{hash} refs/heads/main\n"); |
| 54 | let encoded = encode(line.as_bytes()); |
| 55 | // 4 (prefix) + 40 (hash) + 1 (space) + 15 (refs/heads/main) + 1 (\n) = 61 = 0x3d |
| 56 | assert_eq!(&encoded[..4], b"003d"); |
| 57 | } |
| 58 | } |