1use crate::Error;
7
8pub const MAX_MESSAGE_SIZE: usize = 64 * 1024 * 1024;
10
11pub const LENGTH_PREFIX_SIZE: usize = 4;
13
14pub fn encode_frame(payload: &[u8]) -> Result<Vec<u8>, Error> {
18 if payload.len() > MAX_MESSAGE_SIZE {
19 return Err(Error::InvalidMessage(format!(
20 "payload size {} exceeds maximum {}",
21 payload.len(),
22 MAX_MESSAGE_SIZE
23 )));
24 }
25
26 let len = payload.len() as u32;
27 let mut frame = Vec::with_capacity(LENGTH_PREFIX_SIZE + payload.len());
28 frame.extend_from_slice(&len.to_be_bytes());
29 frame.extend_from_slice(payload);
30 Ok(frame)
31}
32
33pub fn decode_frame_length(header: &[u8; LENGTH_PREFIX_SIZE]) -> Result<usize, Error> {
37 let len = u32::from_be_bytes(*header) as usize;
38 if len > MAX_MESSAGE_SIZE {
39 return Err(Error::InvalidMessage(format!(
40 "frame length {} exceeds maximum {}",
41 len, MAX_MESSAGE_SIZE
42 )));
43 }
44 Ok(len)
45}
46
47pub fn read_length_prefix(data: &[u8]) -> Result<(usize, &[u8]), Error> {
51 if data.len() < LENGTH_PREFIX_SIZE {
52 return Err(Error::InvalidMessage(format!(
53 "buffer too short for length prefix: {} < {}",
54 data.len(),
55 LENGTH_PREFIX_SIZE
56 )));
57 }
58
59 let mut header = [0u8; LENGTH_PREFIX_SIZE];
60 header.copy_from_slice(&data[..LENGTH_PREFIX_SIZE]);
61 let len = decode_frame_length(&header)?;
62
63 Ok((len, &data[LENGTH_PREFIX_SIZE..]))
64}
65
66pub fn frame_complete(data: &[u8]) -> Option<usize> {
70 if data.len() < LENGTH_PREFIX_SIZE {
71 return None;
72 }
73
74 let mut header = [0u8; LENGTH_PREFIX_SIZE];
75 header.copy_from_slice(&data[..LENGTH_PREFIX_SIZE]);
76 let len = u32::from_be_bytes(header) as usize;
77
78 let total = LENGTH_PREFIX_SIZE + len;
79 if data.len() >= total {
80 Some(total)
81 } else {
82 None
83 }
84}
85
86pub fn extract_payload(frame: &[u8]) -> Result<&[u8], Error> {
90 if frame.len() < LENGTH_PREFIX_SIZE {
91 return Err(Error::InvalidMessage("frame too short".to_string()));
92 }
93
94 let mut header = [0u8; LENGTH_PREFIX_SIZE];
95 header.copy_from_slice(&frame[..LENGTH_PREFIX_SIZE]);
96 let len = decode_frame_length(&header)?;
97
98 if frame.len() < LENGTH_PREFIX_SIZE + len {
99 return Err(Error::InvalidMessage(format!(
100 "frame incomplete: have {}, need {}",
101 frame.len(),
102 LENGTH_PREFIX_SIZE + len
103 )));
104 }
105
106 Ok(&frame[LENGTH_PREFIX_SIZE..LENGTH_PREFIX_SIZE + len])
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_encode_frame_empty() {
115 let frame = encode_frame(&[]).unwrap();
116 assert_eq!(frame.len(), LENGTH_PREFIX_SIZE);
117 assert_eq!(&frame[..4], &[0, 0, 0, 0]);
118 }
119
120 #[test]
121 fn test_encode_frame_small() {
122 let payload = b"hello";
123 let frame = encode_frame(payload).unwrap();
124
125 assert_eq!(frame.len(), LENGTH_PREFIX_SIZE + payload.len());
126 assert_eq!(&frame[..4], &[0, 0, 0, 5]);
128 assert_eq!(&frame[4..], payload);
129 }
130
131 #[test]
132 fn test_encode_frame_large() {
133 let payload = vec![0u8; 1000];
134 let frame = encode_frame(&payload).unwrap();
135
136 assert_eq!(frame.len(), LENGTH_PREFIX_SIZE + 1000);
137 assert_eq!(&frame[..4], &[0, 0, 0x03, 0xE8]);
139 }
140
141 #[test]
142 fn test_encode_frame_too_large() {
143 let payload = vec![0u8; MAX_MESSAGE_SIZE + 1];
144 let result = encode_frame(&payload);
145 assert!(result.is_err());
146 }
147
148 #[test]
149 fn test_decode_frame_length() {
150 let header = [0, 0, 0, 0];
152 assert_eq!(decode_frame_length(&header).unwrap(), 0);
153
154 let header = [0, 0, 0, 5];
156 assert_eq!(decode_frame_length(&header).unwrap(), 5);
157
158 let header = [0, 0, 0x03, 0xE8];
160 assert_eq!(decode_frame_length(&header).unwrap(), 1000);
161
162 let max_len = MAX_MESSAGE_SIZE as u32;
164 let header = max_len.to_be_bytes();
165 assert_eq!(decode_frame_length(&header).unwrap(), MAX_MESSAGE_SIZE);
166 }
167
168 #[test]
169 fn test_decode_frame_length_too_large() {
170 let too_large = (MAX_MESSAGE_SIZE as u32) + 1;
171 let header = too_large.to_be_bytes();
172 let result = decode_frame_length(&header);
173 assert!(result.is_err());
174 }
175
176 #[test]
177 fn test_read_length_prefix() {
178 let data = [0, 0, 0, 5, 1, 2, 3, 4, 5, 6, 7];
179 let (len, rest) = read_length_prefix(&data).unwrap();
180
181 assert_eq!(len, 5);
182 assert_eq!(rest, &[1, 2, 3, 4, 5, 6, 7]);
183 }
184
185 #[test]
186 fn test_read_length_prefix_too_short() {
187 let data = [0, 0, 0];
188 let result = read_length_prefix(&data);
189 assert!(result.is_err());
190 }
191
192 #[test]
193 fn test_frame_complete() {
194 assert_eq!(frame_complete(&[0, 0, 0]), None);
196
197 assert_eq!(frame_complete(&[0, 0, 0, 5]), None);
199
200 assert_eq!(frame_complete(&[0, 0, 0, 5, 1, 2, 3]), None);
202
203 assert_eq!(frame_complete(&[0, 0, 0, 0]), Some(4));
205
206 assert_eq!(frame_complete(&[0, 0, 0, 3, 1, 2, 3]), Some(7));
208
209 assert_eq!(frame_complete(&[0, 0, 0, 2, 1, 2, 3, 4, 5]), Some(6));
211 }
212
213 #[test]
214 fn test_extract_payload() {
215 let frame = [0, 0, 0, 0];
217 let payload = extract_payload(&frame).unwrap();
218 assert!(payload.is_empty());
219
220 let frame = [0, 0, 0, 3, 1, 2, 3];
222 let payload = extract_payload(&frame).unwrap();
223 assert_eq!(payload, &[1, 2, 3]);
224
225 let frame = [0, 0, 0, 2, 1, 2, 3, 4, 5];
227 let payload = extract_payload(&frame).unwrap();
228 assert_eq!(payload, &[1, 2]);
229 }
230
231 #[test]
232 fn test_roundtrip() {
233 let original = b"The quick brown fox jumps over the lazy dog";
234 let frame = encode_frame(original).unwrap();
235 let payload = extract_payload(&frame).unwrap();
236 assert_eq!(payload, original);
237 }
238
239 #[test]
240 fn test_roundtrip_binary() {
241 let original: Vec<u8> = (0..=255).collect();
242 let frame = encode_frame(&original).unwrap();
243 let payload = extract_payload(&frame).unwrap();
244 assert_eq!(payload, original.as_slice());
245 }
246}