ruvector_temporal_tensor/
segment.rs1use crate::quantizer;
13
14pub const MAGIC: u32 = 0x4354_5154;
16pub const VERSION: u8 = 1;
18pub const HEADER_SIZE: usize = 26;
20
21pub fn encode(
23 bits: u8,
24 group_len: u32,
25 tensor_len: u32,
26 frame_count: u32,
27 scales: &[u16],
28 data: &[u8],
29 out: &mut Vec<u8>,
30) {
31 out.clear();
32 let estimated = HEADER_SIZE + scales.len() * 2 + data.len();
33 out.reserve(estimated);
34
35 out.extend_from_slice(&MAGIC.to_le_bytes());
37 out.push(VERSION);
38 out.push(bits);
39 out.extend_from_slice(&group_len.to_le_bytes());
40 out.extend_from_slice(&tensor_len.to_le_bytes());
41 out.extend_from_slice(&frame_count.to_le_bytes());
42
43 let scale_count = scales.len() as u32;
45 out.extend_from_slice(&scale_count.to_le_bytes());
46 for &s in scales {
47 out.extend_from_slice(&s.to_le_bytes());
48 }
49
50 let data_len = data.len() as u32;
52 out.extend_from_slice(&data_len.to_le_bytes());
53 out.extend_from_slice(data);
54}
55
56#[derive(Debug, Clone)]
58pub struct SegmentHeader {
59 pub bits: u8,
60 pub group_len: u32,
61 pub tensor_len: u32,
62 pub frame_count: u32,
63 pub scale_count: u32,
64}
65
66pub fn decode(segment: &[u8], out: &mut Vec<f32>) {
68 out.clear();
69 if segment.len() < HEADER_SIZE {
70 return;
71 }
72
73 let mut off = 0;
74
75 let magic = read_u32_le(segment, &mut off);
76 if magic != MAGIC {
77 return;
78 }
79
80 let version = segment[off];
81 off += 1;
82 if version != VERSION {
83 return;
84 }
85
86 let bits = segment[off];
87 off += 1;
88
89 let group_len = read_u32_le(segment, &mut off);
90 let tensor_len = read_u32_le(segment, &mut off);
91 let frame_count = read_u32_le(segment, &mut off);
92 let scale_count = read_u32_le(segment, &mut off);
93
94 let scales_end = off + (scale_count as usize) * 2;
96 if scales_end > segment.len() {
97 return;
98 }
99 let mut scales = Vec::with_capacity(scale_count as usize);
100 for _ in 0..scale_count {
101 scales.push(read_u16_le(segment, &mut off));
102 }
103
104 if off + 4 > segment.len() {
106 return;
107 }
108 let data_len = read_u32_le(segment, &mut off) as usize;
109 if off + data_len > segment.len() {
110 return;
111 }
112 let data = &segment[off..off + data_len];
113
114 let scales_f32 = quantizer::scales_to_f32(&scales);
116 quantizer::dequantize_f32(
117 data,
118 &scales_f32,
119 group_len as usize,
120 bits,
121 tensor_len as usize,
122 frame_count as usize,
123 out,
124 );
125}
126
127pub fn parse_header(segment: &[u8]) -> Option<SegmentHeader> {
129 if segment.len() < HEADER_SIZE {
130 return None;
131 }
132 let mut off = 0;
133 let magic = read_u32_le(segment, &mut off);
134 if magic != MAGIC {
135 return None;
136 }
137 let version = segment[off];
138 off += 1;
139 if version != VERSION {
140 return None;
141 }
142 let bits = segment[off];
143 off += 1;
144 let group_len = read_u32_le(segment, &mut off);
145 let tensor_len = read_u32_le(segment, &mut off);
146 let frame_count = read_u32_le(segment, &mut off);
147 let scale_count = read_u32_le(segment, &mut off);
148
149 Some(SegmentHeader {
150 bits,
151 group_len,
152 tensor_len,
153 frame_count,
154 scale_count,
155 })
156}
157
158pub fn compression_ratio(segment: &[u8]) -> f32 {
162 match parse_header(segment) {
163 Some(h) if h.frame_count > 0 => {
164 let raw = h.tensor_len as usize * h.frame_count as usize * 4;
165 raw as f32 / segment.len() as f32
166 }
167 _ => 0.0,
168 }
169}
170
171pub fn decode_single_frame(segment: &[u8], frame_idx: usize) -> Option<Vec<f32>> {
175 let header = parse_header(segment)?;
176 if frame_idx >= header.frame_count as usize {
177 return None;
178 }
179
180 let mut off = 22usize;
183 let scale_count = header.scale_count as usize;
184
185 let scales_end = off + scale_count * 2;
187 if scales_end > segment.len() {
188 return None;
189 }
190 let mut scales_f16 = Vec::with_capacity(scale_count);
191 for _ in 0..scale_count {
192 scales_f16.push(read_u16_le(segment, &mut off));
193 }
194 let scales_f32 = quantizer::scales_to_f32(&scales_f16);
195
196 if off + 4 > segment.len() {
198 return None;
199 }
200 let data_len = read_u32_le(segment, &mut off) as usize;
201 if off + data_len > segment.len() {
202 return None;
203 }
204 let data = &segment[off..off + data_len];
205
206 let tensor_len = header.tensor_len as usize;
208 let bits = header.bits;
209 let bits_per_frame = tensor_len * bits as usize;
210 let bytes_per_frame = bits_per_frame.div_ceil(8);
211
212 let frame_start = frame_idx * bytes_per_frame;
213 if frame_start + bytes_per_frame > data.len() {
214 return None;
215 }
216 let frame_data = &data[frame_start..frame_start + bytes_per_frame];
217
218 let mut out = Vec::new();
219 quantizer::dequantize_f32(
220 frame_data,
221 &scales_f32,
222 header.group_len as usize,
223 bits,
224 tensor_len,
225 1,
226 &mut out,
227 );
228 Some(out)
229}
230
231#[inline]
232fn read_u32_le(bytes: &[u8], offset: &mut usize) -> u32 {
233 let o = *offset;
234 let arr = [bytes[o], bytes[o + 1], bytes[o + 2], bytes[o + 3]];
235 *offset = o + 4;
236 u32::from_le_bytes(arr)
237}
238
239fn read_u16_le(bytes: &[u8], offset: &mut usize) -> u16 {
240 let o = *offset;
241 let arr = [bytes[o], bytes[o + 1]];
242 *offset = o + 2;
243 u16::from_le_bytes(arr)
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249 use crate::quantizer;
250
251 #[test]
252 fn test_encode_decode_roundtrip() {
253 let frame: Vec<f32> = (0..128).map(|i| (i as f32 - 64.0) * 0.1).collect();
254 let group_len = 64usize;
255 let bits = 8u8;
256
257 let scales = quantizer::compute_scales(&frame, group_len, bits);
258 let mut packed = Vec::new();
259 quantizer::quantize_and_pack(&frame, &scales, group_len, bits, &mut packed);
260
261 let mut seg = Vec::new();
262 encode(
263 bits,
264 group_len as u32,
265 frame.len() as u32,
266 1,
267 &scales,
268 &packed,
269 &mut seg,
270 );
271
272 let mut decoded = Vec::new();
273 decode(&seg, &mut decoded);
274
275 assert_eq!(decoded.len(), frame.len());
276 for (i, (&orig, &dec)) in frame.iter().zip(decoded.iter()).enumerate() {
277 let err = (orig - dec).abs();
278 assert!(err < 0.1, "i={i} orig={orig} dec={dec} err={err}");
279 }
280 }
281
282 #[test]
283 fn test_magic_validation() {
284 let mut decoded = Vec::new();
285 decode(&[0, 0, 0, 0], &mut decoded);
286 assert!(decoded.is_empty()); }
288
289 #[test]
290 fn test_parse_header() {
291 let frame = vec![1.0f32; 64];
292 let scales = quantizer::compute_scales(&frame, 64, 7);
293 let mut packed = Vec::new();
294 quantizer::quantize_and_pack(&frame, &scales, 64, 7, &mut packed);
295
296 let mut seg = Vec::new();
297 encode(7, 64, 64, 1, &scales, &packed, &mut seg);
298
299 let header = parse_header(&seg).unwrap();
300 assert_eq!(header.bits, 7);
301 assert_eq!(header.group_len, 64);
302 assert_eq!(header.tensor_len, 64);
303 assert_eq!(header.frame_count, 1);
304 }
305
306 #[test]
307 fn test_multi_frame_roundtrip() {
308 let group_len = 32usize;
309 let bits = 5u8;
310 let tensor_len = 64;
311
312 let frame1: Vec<f32> = (0..tensor_len).map(|i| (i as f32) * 0.1).collect();
313 let frame2: Vec<f32> = (0..tensor_len).map(|i| (i as f32) * 0.09).collect();
314
315 let scales = quantizer::compute_scales(&frame1, group_len, bits);
316 let mut packed = Vec::new();
317 quantizer::quantize_and_pack(&frame1, &scales, group_len, bits, &mut packed);
318 quantizer::quantize_and_pack(&frame2, &scales, group_len, bits, &mut packed);
319
320 let mut seg = Vec::new();
321 encode(
322 bits,
323 group_len as u32,
324 tensor_len as u32,
325 2,
326 &scales,
327 &packed,
328 &mut seg,
329 );
330
331 let mut decoded = Vec::new();
332 decode(&seg, &mut decoded);
333 assert_eq!(decoded.len(), tensor_len * 2);
334 }
335}