1use crate::bitpack::BitPack;
37use crate::error::BuffError;
38use crate::precision::{get_decimal_length, get_precision_bound, PrecisionBound};
39
40const FORMAT_V1: u8 = 0x01;
42
43const FORMAT_V2: u8 = 0x02;
45
46const SPECIAL_POS_INF: u8 = 1;
48
49const SPECIAL_NEG_INF: u8 = 2;
51
52const SPECIAL_NAN: u8 = 3;
54
55#[derive(Debug, Clone, Copy, PartialEq)]
57pub struct SpecialValue {
58 pub index: u32,
60 pub kind: SpecialValueKind,
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum SpecialValueKind {
67 PositiveInfinity,
69 NegativeInfinity,
71 NaN,
73}
74
75impl SpecialValueKind {
76 fn to_byte(self) -> u8 {
77 match self {
78 SpecialValueKind::PositiveInfinity => SPECIAL_POS_INF,
79 SpecialValueKind::NegativeInfinity => SPECIAL_NEG_INF,
80 SpecialValueKind::NaN => SPECIAL_NAN,
81 }
82 }
83
84 fn from_byte(b: u8) -> Option<Self> {
85 match b {
86 SPECIAL_POS_INF => Some(SpecialValueKind::PositiveInfinity),
87 SPECIAL_NEG_INF => Some(SpecialValueKind::NegativeInfinity),
88 SPECIAL_NAN => Some(SpecialValueKind::NaN),
89 _ => None,
90 }
91 }
92
93 pub fn to_f64(self) -> f64 {
95 match self {
96 SpecialValueKind::PositiveInfinity => f64::INFINITY,
97 SpecialValueKind::NegativeInfinity => f64::NEG_INFINITY,
98 SpecialValueKind::NaN => f64::NAN,
99 }
100 }
101}
102
103pub fn classify_float(v: f64) -> Option<SpecialValueKind> {
105 if v.is_nan() {
106 Some(SpecialValueKind::NaN)
107 } else if v == f64::INFINITY {
108 Some(SpecialValueKind::PositiveInfinity)
109 } else if v == f64::NEG_INFINITY {
110 Some(SpecialValueKind::NegativeInfinity)
111 } else {
112 None
113 }
114}
115
116#[inline]
121pub fn flip(x: u8) -> u8 {
122 x ^ (1u8 << 7)
123}
124
125#[inline]
127fn ceil_div(x: u32, y: u32) -> u32 {
128 (x.saturating_sub(1)) / y + 1
129}
130
131#[derive(Clone, Debug)]
137pub struct BuffCodec {
138 scale: usize,
140}
141
142impl BuffCodec {
143 pub fn new(scale: usize) -> Self {
156 BuffCodec { scale }
157 }
158
159 pub fn precision(&self) -> i32 {
161 if self.scale == 0 {
162 0
163 } else {
164 (self.scale as f32).log10() as i32
165 }
166 }
167
168 pub fn encode(&self, data: &[f64]) -> Result<Vec<u8>, BuffError> {
185 if data.is_empty() {
186 return Err(BuffError::EmptyInput);
187 }
188
189 let len = data.len() as u32;
190 let prec = self.precision();
191 let prec_delta = get_precision_bound(prec);
192 let dec_len = get_decimal_length(prec);
193
194 let mut bound = PrecisionBound::new(prec_delta);
195 bound.set_length(0, dec_len);
196
197 let mut fixed_vec = Vec::with_capacity(data.len());
199 let mut min = i64::MAX;
200 let mut max = i64::MIN;
201
202 for &val in data {
203 let fixed = bound.fetch_fixed_aligned(val);
204 if fixed < min {
205 min = fixed;
206 }
207 if fixed > max {
208 max = fixed;
209 }
210 fixed_vec.push(fixed);
211 }
212
213 let delta = max - min;
214 let base_fixed = min;
215
216 let cal_int_length = if delta == 0 {
220 0.0
221 } else {
222 ((delta + 1) as f64).log2().ceil()
223 };
224
225 let fixed_len = cal_int_length as u32;
226 let ilen = fixed_len.saturating_sub(dec_len as u32);
227 let dlen = dec_len as u32;
228
229 let mut bitpack = BitPack::<Vec<u8>>::with_capacity(20 + data.len() * 8);
231 let ubase_fixed = base_fixed as u64;
232
233 bitpack.write(ubase_fixed as u32, 32)?;
234 bitpack.write((ubase_fixed >> 32) as u32, 32)?;
235 bitpack.write(len, 32)?;
236 bitpack.write(ilen, 32)?;
237 bitpack.write(dlen, 32)?;
238
239 let total_bits = ilen + dlen;
241 let mut remain = total_bits;
242
243 if remain < 8 {
244 let padding = 8 - remain;
246 for &fixed in &fixed_vec {
247 let val = (fixed - base_fixed) as u64;
248 bitpack.write_byte(flip(((val << padding) & 0xFF) as u8))?;
249 }
250 } else {
251 remain -= 8;
253 let fixed_u64: Vec<u64> = if remain > 0 {
254 fixed_vec
255 .iter()
256 .map(|&x| {
257 let val = (x - base_fixed) as u64;
258 bitpack
259 .write_byte(flip((val >> remain) as u8))
260 .expect("write failed");
261 val
262 })
263 .collect()
264 } else {
265 fixed_vec
266 .iter()
267 .map(|&x| {
268 let val = (x - base_fixed) as u64;
269 bitpack.write_byte(flip(val as u8)).expect("write failed");
270 val
271 })
272 .collect()
273 };
274
275 while remain >= 8 {
277 remain -= 8;
278 if remain > 0 {
279 for &d in &fixed_u64 {
280 bitpack.write_byte(flip((d >> remain) as u8))?;
281 }
282 } else {
283 for &d in &fixed_u64 {
284 bitpack.write_byte(flip(d as u8))?;
285 }
286 }
287 }
288
289 if remain > 0 {
291 let padding = 8 - remain;
292 for &d in &fixed_u64 {
293 bitpack.write_byte(flip(((d << padding) & 0xFF) as u8))?;
294 }
295 }
296 }
297
298 Ok(bitpack.into_vec())
299 }
300
301 pub fn encode_with_special(&self, data: &[f64]) -> Result<Vec<u8>, BuffError> {
325 if data.is_empty() {
326 return Err(BuffError::EmptyInput);
327 }
328
329 let mut regular_values: Vec<f64> = Vec::with_capacity(data.len());
331 let mut special_values: Vec<SpecialValue> = Vec::new();
332 let mut index_map: Vec<usize> = Vec::with_capacity(data.len()); for (i, &val) in data.iter().enumerate() {
335 if let Some(kind) = classify_float(val) {
336 special_values.push(SpecialValue {
337 index: i as u32,
338 kind,
339 });
340 } else {
341 index_map.push(regular_values.len());
342 regular_values.push(val);
343 }
344 }
345
346 if special_values.is_empty() {
348 return self.encode(data);
349 }
350
351 if regular_values.is_empty() {
353 let mut result = Vec::with_capacity(1 + 4 + 5 * special_values.len());
354 result.push(FORMAT_V2);
355
356 result.extend_from_slice(&0u64.to_le_bytes()); result.extend_from_slice(&0u32.to_le_bytes()); result.extend_from_slice(&0u32.to_le_bytes()); result.extend_from_slice(&0u32.to_le_bytes()); result.extend_from_slice(&(special_values.len() as u32).to_le_bytes());
364 for sv in &special_values {
365 result.extend_from_slice(&sv.index.to_le_bytes());
366 result.push(sv.kind.to_byte());
367 }
368
369 return Ok(result);
370 }
371
372 let prec = self.precision();
374 let prec_delta = get_precision_bound(prec);
375 let dec_len = get_decimal_length(prec);
376
377 let mut bound = PrecisionBound::new(prec_delta);
378 bound.set_length(0, dec_len);
379
380 let mut fixed_vec = Vec::with_capacity(regular_values.len());
381 let mut min = i64::MAX;
382 let mut max = i64::MIN;
383
384 for &val in ®ular_values {
385 let fixed = bound.fetch_fixed_aligned(val);
386 if fixed < min {
387 min = fixed;
388 }
389 if fixed > max {
390 max = fixed;
391 }
392 fixed_vec.push(fixed);
393 }
394
395 let delta = max - min;
396 let base_fixed = min;
397
398 let cal_int_length = if delta == 0 {
399 0.0
400 } else {
401 ((delta + 1) as f64).log2().ceil()
402 };
403
404 let fixed_len = cal_int_length as u32;
405 let ilen = fixed_len.saturating_sub(dec_len as u32);
406 let dlen = dec_len as u32;
407
408 let mut result =
410 Vec::with_capacity(1 + 20 + 4 + 5 * special_values.len() + regular_values.len() * 8);
411
412 result.push(FORMAT_V2);
414
415 let ubase_fixed = base_fixed as u64;
417 result.extend_from_slice(&ubase_fixed.to_le_bytes());
418 result.extend_from_slice(&(regular_values.len() as u32).to_le_bytes());
419 result.extend_from_slice(&ilen.to_le_bytes());
420 result.extend_from_slice(&dlen.to_le_bytes());
421
422 result.extend_from_slice(&(special_values.len() as u32).to_le_bytes());
424 for sv in &special_values {
425 result.extend_from_slice(&sv.index.to_le_bytes());
426 result.push(sv.kind.to_byte());
427 }
428
429 let total_bits = ilen + dlen;
431 let mut remain = total_bits;
432
433 if remain == 0 {
434 } else if remain < 8 {
436 let padding = 8 - remain;
437 for &fixed in &fixed_vec {
438 let val = (fixed - base_fixed) as u64;
439 result.push(flip(((val << padding) & 0xFF) as u8));
440 }
441 } else {
442 remain -= 8;
443 let fixed_u64: Vec<u64> = fixed_vec
444 .iter()
445 .map(|&x| {
446 let val = (x - base_fixed) as u64;
447 if remain > 0 {
448 result.push(flip((val >> remain) as u8));
449 } else {
450 result.push(flip(val as u8));
451 }
452 val
453 })
454 .collect();
455
456 while remain >= 8 {
457 remain -= 8;
458 if remain > 0 {
459 for &d in &fixed_u64 {
460 result.push(flip((d >> remain) as u8));
461 }
462 } else {
463 for &d in &fixed_u64 {
464 result.push(flip(d as u8));
465 }
466 }
467 }
468
469 if remain > 0 {
470 let padding = 8 - remain;
471 for &d in &fixed_u64 {
472 result.push(flip(((d << padding) & 0xFF) as u8));
473 }
474 }
475 }
476
477 Ok(result)
478 }
479
480 pub fn has_special_values(&self, bytes: &[u8]) -> bool {
482 !bytes.is_empty() && bytes[0] == FORMAT_V2
483 }
484
485 pub fn decode(&self, bytes: &[u8]) -> Result<Vec<f64>, BuffError> {
506 if !bytes.is_empty() && bytes[0] == FORMAT_V2 {
508 return self.decode_v2(bytes);
509 }
510
511 self.decode_v1(bytes)
513 }
514
515 fn decode_v1(&self, bytes: &[u8]) -> Result<Vec<f64>, BuffError> {
517 if bytes.len() < 20 {
518 return Err(BuffError::InvalidData("header too short".into()));
519 }
520
521 let prec = self.precision();
522 let prec_delta = get_precision_bound(prec);
523
524 let mut bitpack = BitPack::<&[u8]>::new(bytes);
525 let _bound = PrecisionBound::new(prec_delta);
526
527 let lower = bitpack.read(32)?;
529 let higher = bitpack.read(32)?;
530 let ubase_int = (lower as u64) | ((higher as u64) << 32);
531 let base_int = ubase_int as i64;
532
533 let len = bitpack.read(32)? as usize;
534 let ilen = bitpack.read(32)?;
535 let dlen = bitpack.read(32)?;
536
537 let dec_scl = 2.0f64.powi(dlen as i32);
538 let remain = dlen + ilen;
539 let num_chunks = ceil_div(remain, 8);
540 let padding = num_chunks * 8 - ilen - dlen;
541
542 let mut result = Vec::with_capacity(len);
543
544 match num_chunks {
545 0 => {
546 result.resize(len, base_int as f64 / dec_scl);
548 }
549 1 => {
550 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
551 for &byte in chunk0.iter().take(len) {
552 let val = (flip(byte) as u64) >> padding;
553 result.push((base_int + val as i64) as f64 / dec_scl);
554 }
555 }
556 2 => {
557 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
558 let chunk1 = bitpack.read_n_byte_unmut(len, len)?;
559 for (&b0, &b1) in chunk0.iter().zip(chunk1.iter()).take(len) {
560 let val = ((flip(b0) as u64) << (8 - padding)) | ((flip(b1) as u64) >> padding);
561 result.push((base_int + val as i64) as f64 / dec_scl);
562 }
563 }
564 3 => {
565 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
566 let chunk1 = bitpack.read_n_byte_unmut(len, len)?;
567 let chunk2 = bitpack.read_n_byte_unmut(2 * len, len)?;
568 for ((&b0, &b1), &b2) in chunk0
569 .iter()
570 .zip(chunk1.iter())
571 .zip(chunk2.iter())
572 .take(len)
573 {
574 let val = ((flip(b0) as u64) << (16 - padding))
575 | ((flip(b1) as u64) << (8 - padding))
576 | ((flip(b2) as u64) >> padding);
577 result.push((base_int + val as i64) as f64 / dec_scl);
578 }
579 }
580 4 => {
581 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
582 let chunk1 = bitpack.read_n_byte_unmut(len, len)?;
583 let chunk2 = bitpack.read_n_byte_unmut(2 * len, len)?;
584 let chunk3 = bitpack.read_n_byte_unmut(3 * len, len)?;
585 for (((&b0, &b1), &b2), &b3) in chunk0
586 .iter()
587 .zip(chunk1.iter())
588 .zip(chunk2.iter())
589 .zip(chunk3.iter())
590 .take(len)
591 {
592 let val = ((flip(b0) as u64) << (24 - padding))
593 | ((flip(b1) as u64) << (16 - padding))
594 | ((flip(b2) as u64) << (8 - padding))
595 | ((flip(b3) as u64) >> padding);
596 result.push((base_int + val as i64) as f64 / dec_scl);
597 }
598 }
599 _ => {
600 return Err(BuffError::InvalidData(format!(
601 "bit length {} (>{} chunks) not supported",
602 remain, num_chunks
603 )));
604 }
605 }
606
607 Ok(result)
608 }
609
610 fn decode_v2(&self, bytes: &[u8]) -> Result<Vec<f64>, BuffError> {
612 if bytes.len() < 22 {
613 return Err(BuffError::InvalidData("v2 header too short".into()));
615 }
616
617 let mut pos = 1; let base_int = i64::from_le_bytes(bytes[pos..pos + 8].try_into().unwrap());
621 pos += 8;
622
623 let regular_count = u32::from_le_bytes(bytes[pos..pos + 4].try_into().unwrap()) as usize;
624 pos += 4;
625
626 let ilen = u32::from_le_bytes(bytes[pos..pos + 4].try_into().unwrap());
627 pos += 4;
628
629 let dlen = u32::from_le_bytes(bytes[pos..pos + 4].try_into().unwrap());
630 pos += 4;
631
632 let special_count = u32::from_le_bytes(bytes[pos..pos + 4].try_into().unwrap()) as usize;
634 pos += 4;
635
636 let mut special_values: Vec<SpecialValue> = Vec::with_capacity(special_count);
638 for _ in 0..special_count {
639 if pos + 5 > bytes.len() {
640 return Err(BuffError::InvalidData("truncated special values".into()));
641 }
642 let index = u32::from_le_bytes(bytes[pos..pos + 4].try_into().unwrap());
643 pos += 4;
644 let kind = SpecialValueKind::from_byte(bytes[pos])
645 .ok_or_else(|| BuffError::InvalidData("invalid special value type".into()))?;
646 pos += 1;
647 special_values.push(SpecialValue { index, kind });
648 }
649
650 let total_count = regular_count + special_count;
652
653 if regular_count == 0 {
655 let mut result = vec![0.0f64; total_count];
656 for sv in &special_values {
657 result[sv.index as usize] = sv.kind.to_f64();
658 }
659 return Ok(result);
660 }
661
662 let dec_scl = 2.0f64.powi(dlen as i32);
664 let remain = dlen + ilen;
665 let num_chunks = ceil_div(remain, 8);
666 let padding = num_chunks * 8 - ilen - dlen;
667
668 let data_start = pos;
669 let mut regular_values: Vec<f64> = Vec::with_capacity(regular_count);
670
671 match num_chunks {
672 0 => {
673 regular_values.resize(regular_count, base_int as f64 / dec_scl);
674 }
675 1 => {
676 let chunk0 = &bytes[data_start..data_start + regular_count];
677 for &byte in chunk0.iter() {
678 let val = (flip(byte) as u64) >> padding;
679 regular_values.push((base_int + val as i64) as f64 / dec_scl);
680 }
681 }
682 2 => {
683 let chunk0 = &bytes[data_start..data_start + regular_count];
684 let chunk1 = &bytes[data_start + regular_count..data_start + 2 * regular_count];
685 for (&b0, &b1) in chunk0.iter().zip(chunk1.iter()) {
686 let val = ((flip(b0) as u64) << (8 - padding)) | ((flip(b1) as u64) >> padding);
687 regular_values.push((base_int + val as i64) as f64 / dec_scl);
688 }
689 }
690 3 => {
691 let chunk0 = &bytes[data_start..data_start + regular_count];
692 let chunk1 = &bytes[data_start + regular_count..data_start + 2 * regular_count];
693 let chunk2 = &bytes[data_start + 2 * regular_count..data_start + 3 * regular_count];
694 for ((&b0, &b1), &b2) in chunk0.iter().zip(chunk1.iter()).zip(chunk2.iter()) {
695 let val = ((flip(b0) as u64) << (16 - padding))
696 | ((flip(b1) as u64) << (8 - padding))
697 | ((flip(b2) as u64) >> padding);
698 regular_values.push((base_int + val as i64) as f64 / dec_scl);
699 }
700 }
701 4 => {
702 let chunk0 = &bytes[data_start..data_start + regular_count];
703 let chunk1 = &bytes[data_start + regular_count..data_start + 2 * regular_count];
704 let chunk2 = &bytes[data_start + 2 * regular_count..data_start + 3 * regular_count];
705 let chunk3 = &bytes[data_start + 3 * regular_count..data_start + 4 * regular_count];
706 for (((&b0, &b1), &b2), &b3) in chunk0
707 .iter()
708 .zip(chunk1.iter())
709 .zip(chunk2.iter())
710 .zip(chunk3.iter())
711 {
712 let val = ((flip(b0) as u64) << (24 - padding))
713 | ((flip(b1) as u64) << (16 - padding))
714 | ((flip(b2) as u64) << (8 - padding))
715 | ((flip(b3) as u64) >> padding);
716 regular_values.push((base_int + val as i64) as f64 / dec_scl);
717 }
718 }
719 _ => {
720 return Err(BuffError::InvalidData(format!(
721 "bit length {} not supported",
722 remain
723 )));
724 }
725 }
726
727 let mut result = vec![0.0f64; total_count];
729 let mut regular_idx = 0;
730
731 let special_indices: std::collections::HashSet<u32> =
733 special_values.iter().map(|sv| sv.index).collect();
734
735 for (i, slot) in result.iter_mut().enumerate() {
736 if special_indices.contains(&(i as u32)) {
737 if let Some(sv) = special_values.iter().find(|sv| sv.index == i as u32) {
739 *slot = sv.kind.to_f64();
740 }
741 } else {
742 *slot = regular_values[regular_idx];
743 regular_idx += 1;
744 }
745 }
746
747 Ok(result)
748 }
749
750 pub fn sum(&self, bytes: &[u8]) -> Result<f64, BuffError> {
754 if bytes.len() < 20 {
755 return Err(BuffError::InvalidData("header too short".into()));
756 }
757
758 let prec = self.precision();
759 let prec_delta = get_precision_bound(prec);
760
761 let mut bitpack = BitPack::<&[u8]>::new(bytes);
762 let _bound = PrecisionBound::new(prec_delta);
763
764 let lower = bitpack.read(32)?;
766 let higher = bitpack.read(32)?;
767 let ubase_int = (lower as u64) | ((higher as u64) << 32);
768 let base_int = ubase_int as i64;
769
770 let len = bitpack.read(32)? as usize;
771 let ilen = bitpack.read(32)?;
772 let dlen = bitpack.read(32)?;
773
774 let dec_scl = 2.0f64.powi(dlen as i32);
775 let remain = dlen + ilen;
776 let num_chunks = ceil_div(remain, 8);
777 let padding = num_chunks * 8 - ilen - dlen;
778
779 let mut sum = 0.0f64;
780
781 match num_chunks {
782 0 => {
783 sum = (base_int as f64 / dec_scl) * len as f64;
784 }
785 1 => {
786 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
787 for &byte in chunk0.iter().take(len) {
788 let val = (flip(byte) as u64) >> padding;
789 sum += (base_int + val as i64) as f64 / dec_scl;
790 }
791 }
792 2 => {
793 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
794 let chunk1 = bitpack.read_n_byte_unmut(len, len)?;
795 for (&b0, &b1) in chunk0.iter().zip(chunk1.iter()).take(len) {
796 let val = ((flip(b0) as u64) << (8 - padding)) | ((flip(b1) as u64) >> padding);
797 sum += (base_int + val as i64) as f64 / dec_scl;
798 }
799 }
800 3 => {
801 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
802 let chunk1 = bitpack.read_n_byte_unmut(len, len)?;
803 let chunk2 = bitpack.read_n_byte_unmut(2 * len, len)?;
804 for ((&b0, &b1), &b2) in chunk0
805 .iter()
806 .zip(chunk1.iter())
807 .zip(chunk2.iter())
808 .take(len)
809 {
810 let val = ((flip(b0) as u64) << (16 - padding))
811 | ((flip(b1) as u64) << (8 - padding))
812 | ((flip(b2) as u64) >> padding);
813 sum += (base_int + val as i64) as f64 / dec_scl;
814 }
815 }
816 4 => {
817 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
818 let chunk1 = bitpack.read_n_byte_unmut(len, len)?;
819 let chunk2 = bitpack.read_n_byte_unmut(2 * len, len)?;
820 let chunk3 = bitpack.read_n_byte_unmut(3 * len, len)?;
821 for (((&b0, &b1), &b2), &b3) in chunk0
822 .iter()
823 .zip(chunk1.iter())
824 .zip(chunk2.iter())
825 .zip(chunk3.iter())
826 .take(len)
827 {
828 let val = ((flip(b0) as u64) << (24 - padding))
829 | ((flip(b1) as u64) << (16 - padding))
830 | ((flip(b2) as u64) << (8 - padding))
831 | ((flip(b3) as u64) >> padding);
832 sum += (base_int + val as i64) as f64 / dec_scl;
833 }
834 }
835 _ => {
836 return Err(BuffError::InvalidData(format!(
837 "bit length {} not supported",
838 remain
839 )));
840 }
841 }
842
843 Ok(sum)
844 }
845
846 pub fn max(&self, bytes: &[u8]) -> Result<f64, BuffError> {
850 if bytes.len() < 20 {
851 return Err(BuffError::InvalidData("header too short".into()));
852 }
853
854 let prec = self.precision();
855 let prec_delta = get_precision_bound(prec);
856
857 let mut bitpack = BitPack::<&[u8]>::new(bytes);
858 let _bound = PrecisionBound::new(prec_delta);
859
860 let lower = bitpack.read(32)?;
862 let higher = bitpack.read(32)?;
863 let ubase_int = (lower as u64) | ((higher as u64) << 32);
864 let base_int = ubase_int as i64;
865
866 let len = bitpack.read(32)? as usize;
867 let ilen = bitpack.read(32)?;
868 let dlen = bitpack.read(32)?;
869
870 let dec_scl = 2.0f64.powi(dlen as i32);
871 let remain = dlen + ilen;
872 let num_chunks = ceil_div(remain, 8);
873 let padding = num_chunks * 8 - ilen - dlen;
874
875 let mut max_val = f64::MIN;
876
877 match num_chunks {
878 0 => {
879 max_val = base_int as f64 / dec_scl;
880 }
881 1 => {
882 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
883 for &byte in chunk0.iter().take(len) {
884 let val = (flip(byte) as u64) >> padding;
885 let f = (base_int + val as i64) as f64 / dec_scl;
886 if f > max_val {
887 max_val = f;
888 }
889 }
890 }
891 2 => {
892 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
893 let chunk1 = bitpack.read_n_byte_unmut(len, len)?;
894 for (&b0, &b1) in chunk0.iter().zip(chunk1.iter()).take(len) {
895 let val = ((flip(b0) as u64) << (8 - padding)) | ((flip(b1) as u64) >> padding);
896 let f = (base_int + val as i64) as f64 / dec_scl;
897 if f > max_val {
898 max_val = f;
899 }
900 }
901 }
902 3 => {
903 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
904 let chunk1 = bitpack.read_n_byte_unmut(len, len)?;
905 let chunk2 = bitpack.read_n_byte_unmut(2 * len, len)?;
906 for ((&b0, &b1), &b2) in chunk0
907 .iter()
908 .zip(chunk1.iter())
909 .zip(chunk2.iter())
910 .take(len)
911 {
912 let val = ((flip(b0) as u64) << (16 - padding))
913 | ((flip(b1) as u64) << (8 - padding))
914 | ((flip(b2) as u64) >> padding);
915 let f = (base_int + val as i64) as f64 / dec_scl;
916 if f > max_val {
917 max_val = f;
918 }
919 }
920 }
921 4 => {
922 let chunk0 = bitpack.read_n_byte_unmut(0, len)?;
923 let chunk1 = bitpack.read_n_byte_unmut(len, len)?;
924 let chunk2 = bitpack.read_n_byte_unmut(2 * len, len)?;
925 let chunk3 = bitpack.read_n_byte_unmut(3 * len, len)?;
926 for (((&b0, &b1), &b2), &b3) in chunk0
927 .iter()
928 .zip(chunk1.iter())
929 .zip(chunk2.iter())
930 .zip(chunk3.iter())
931 .take(len)
932 {
933 let val = ((flip(b0) as u64) << (24 - padding))
934 | ((flip(b1) as u64) << (16 - padding))
935 | ((flip(b2) as u64) << (8 - padding))
936 | ((flip(b3) as u64) >> padding);
937 let f = (base_int + val as i64) as f64 / dec_scl;
938 if f > max_val {
939 max_val = f;
940 }
941 }
942 }
943 _ => {
944 return Err(BuffError::InvalidData(format!(
945 "bit length {} not supported",
946 remain
947 )));
948 }
949 }
950
951 Ok(max_val)
952 }
953
954 pub fn count_greater_than(&self, bytes: &[u8], threshold: f64) -> Result<usize, BuffError> {
959 let decoded = self.decode(bytes)?;
961 Ok(decoded.iter().filter(|&&v| v > threshold).count())
962 }
963
964 pub fn count_equal(&self, bytes: &[u8], target: f64) -> Result<usize, BuffError> {
966 let decoded = self.decode(bytes)?;
967 Ok(decoded
968 .iter()
969 .filter(|&&v| (v - target).abs() < f64::EPSILON)
970 .count())
971 }
972
973 pub fn metadata(&self, bytes: &[u8]) -> Result<BuffMetadata, BuffError> {
975 if bytes.len() < 20 {
976 return Err(BuffError::InvalidData("header too short".into()));
977 }
978
979 let mut bitpack = BitPack::<&[u8]>::new(bytes);
980
981 let lower = bitpack.read(32)?;
982 let higher = bitpack.read(32)?;
983 let ubase_int = (lower as u64) | ((higher as u64) << 32);
984 let base_int = ubase_int as i64;
985
986 let len = bitpack.read(32)?;
987 let ilen = bitpack.read(32)?;
988 let dlen = bitpack.read(32)?;
989
990 Ok(BuffMetadata {
991 base_value: base_int,
992 count: len,
993 integer_bits: ilen,
994 decimal_bits: dlen,
995 total_bytes: bytes.len(),
996 })
997 }
998}
999
1000#[derive(Debug, Clone, PartialEq, Eq)]
1002pub struct BuffMetadata {
1003 pub base_value: i64,
1005 pub count: u32,
1007 pub integer_bits: u32,
1009 pub decimal_bits: u32,
1011 pub total_bytes: usize,
1013}
1014
1015impl BuffMetadata {
1016 pub fn compression_ratio(&self) -> f64 {
1018 let original_size = self.count as usize * std::mem::size_of::<f64>();
1019 self.total_bytes as f64 / original_size as f64
1020 }
1021}
1022
1023#[cfg(test)]
1024mod tests {
1025 use super::*;
1026
1027 #[test]
1028 fn test_flip() {
1029 assert_eq!(flip(0), 128);
1030 assert_eq!(flip(128), 0);
1031 assert_eq!(flip(255), 127);
1032 }
1033
1034 #[test]
1035 fn test_encode_decode_roundtrip() {
1036 let codec = BuffCodec::new(1000);
1037 let data = vec![1.234, 5.678, 9.012, -3.456, 0.0];
1038 let encoded = codec.encode(&data).unwrap();
1039 let decoded = codec.decode(&encoded).unwrap();
1040
1041 assert_eq!(data.len(), decoded.len());
1042 for (orig, dec) in data.iter().zip(decoded.iter()) {
1043 assert!((orig - dec).abs() < 0.001, "orig={}, dec={}", orig, dec);
1044 }
1045 }
1046
1047 #[test]
1048 fn test_encode_decode_high_precision() {
1049 let codec = BuffCodec::new(100000); let data = vec![1.23456, 5.67890, 9.01234];
1051 let encoded = codec.encode(&data).unwrap();
1052 let decoded = codec.decode(&encoded).unwrap();
1053
1054 for (orig, dec) in data.iter().zip(decoded.iter()) {
1055 assert!((orig - dec).abs() < 0.00001, "orig={}, dec={}", orig, dec);
1056 }
1057 }
1058
1059 #[test]
1060 fn test_empty_input() {
1061 let codec = BuffCodec::new(1000);
1062 let result = codec.encode(&[]);
1063 assert!(matches!(result, Err(BuffError::EmptyInput)));
1064 }
1065
1066 #[test]
1067 fn test_single_value() {
1068 let codec = BuffCodec::new(1000);
1069 let data = vec![42.123];
1070 let encoded = codec.encode(&data).unwrap();
1071 let decoded = codec.decode(&encoded).unwrap();
1072
1073 assert_eq!(decoded.len(), 1);
1074 assert!((data[0] - decoded[0]).abs() < 0.001);
1075 }
1076
1077 #[test]
1078 fn test_identical_values() {
1079 let codec = BuffCodec::new(1000);
1080 let data = vec![3.14159; 100];
1081 let encoded = codec.encode(&data).unwrap();
1082 let decoded = codec.decode(&encoded).unwrap();
1083
1084 assert_eq!(decoded.len(), 100);
1085 for &val in &decoded {
1086 assert!((val - 3.14159).abs() < 0.001);
1087 }
1088 }
1089
1090 #[test]
1091 fn test_sum() {
1092 let codec = BuffCodec::new(1000);
1093 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
1094 let encoded = codec.encode(&data).unwrap();
1095 let sum = codec.sum(&encoded).unwrap();
1096
1097 assert!((sum - 15.0).abs() < 0.01);
1098 }
1099
1100 #[test]
1101 fn test_max() {
1102 let codec = BuffCodec::new(1000);
1103 let data = vec![1.5, 9.9, 3.2, 7.1, 2.8];
1104 let encoded = codec.encode(&data).unwrap();
1105 let max = codec.max(&encoded).unwrap();
1106
1107 assert!((max - 9.9).abs() < 0.01);
1108 }
1109
1110 #[test]
1111 fn test_metadata() {
1112 let codec = BuffCodec::new(1000);
1113 let data = vec![1.0, 2.0, 3.0];
1114 let encoded = codec.encode(&data).unwrap();
1115 let metadata = codec.metadata(&encoded).unwrap();
1116
1117 assert_eq!(metadata.count, 3);
1118 assert!(metadata.compression_ratio() < 1.5); }
1120
1121 #[test]
1122 fn test_negative_values() {
1123 let codec = BuffCodec::new(1000);
1124 let data = vec![-10.5, -5.25, 0.0, 5.25, 10.5];
1125 let encoded = codec.encode(&data).unwrap();
1126 let decoded = codec.decode(&encoded).unwrap();
1127
1128 for (orig, dec) in data.iter().zip(decoded.iter()) {
1129 assert!((orig - dec).abs() < 0.001, "orig={}, dec={}", orig, dec);
1130 }
1131 }
1132
1133 #[test]
1134 fn test_large_values() {
1135 let codec = BuffCodec::new(100);
1136 let data = vec![1000000.0, 2000000.0, 3000000.0];
1137 let encoded = codec.encode(&data).unwrap();
1138 let decoded = codec.decode(&encoded).unwrap();
1139
1140 for (orig, dec) in data.iter().zip(decoded.iter()) {
1141 assert!((orig - dec).abs() < 1.0, "orig={}, dec={}", orig, dec);
1142 }
1143 }
1144
1145 #[test]
1146 fn test_special_values_infinity() {
1147 let codec = BuffCodec::new(1000);
1148 let data = vec![1.0, f64::INFINITY, 2.0, f64::NEG_INFINITY, 3.0];
1149 let encoded = codec.encode_with_special(&data).unwrap();
1150
1151 assert!(codec.has_special_values(&encoded));
1152
1153 let decoded = codec.decode(&encoded).unwrap();
1154
1155 assert_eq!(decoded.len(), 5);
1156 assert!((decoded[0] - 1.0).abs() < 0.001);
1157 assert!(decoded[1].is_infinite() && decoded[1].is_sign_positive());
1158 assert!((decoded[2] - 2.0).abs() < 0.001);
1159 assert!(decoded[3].is_infinite() && decoded[3].is_sign_negative());
1160 assert!((decoded[4] - 3.0).abs() < 0.001);
1161 }
1162
1163 #[test]
1164 fn test_special_values_nan() {
1165 let codec = BuffCodec::new(1000);
1166 let data = vec![1.0, f64::NAN, 2.0];
1167 let encoded = codec.encode_with_special(&data).unwrap();
1168
1169 let decoded = codec.decode(&encoded).unwrap();
1170
1171 assert_eq!(decoded.len(), 3);
1172 assert!((decoded[0] - 1.0).abs() < 0.001);
1173 assert!(decoded[1].is_nan());
1174 assert!((decoded[2] - 2.0).abs() < 0.001);
1175 }
1176
1177 #[test]
1178 fn test_all_special_values() {
1179 let codec = BuffCodec::new(1000);
1180 let data = vec![f64::INFINITY, f64::NAN, f64::NEG_INFINITY];
1181 let encoded = codec.encode_with_special(&data).unwrap();
1182 let decoded = codec.decode(&encoded).unwrap();
1183
1184 assert_eq!(decoded.len(), 3);
1185 assert!(decoded[0].is_infinite() && decoded[0].is_sign_positive());
1186 assert!(decoded[1].is_nan());
1187 assert!(decoded[2].is_infinite() && decoded[2].is_sign_negative());
1188 }
1189
1190 #[test]
1191 fn test_no_special_values_uses_v1() {
1192 let codec = BuffCodec::new(1000);
1193 let data = vec![1.0, 2.0, 3.0];
1194
1195 let encoded = codec.encode_with_special(&data).unwrap();
1197 assert!(!codec.has_special_values(&encoded));
1198
1199 let decoded = codec.decode(&encoded).unwrap();
1200 assert_eq!(decoded.len(), 3);
1201 }
1202
1203 #[test]
1204 fn test_special_value_kind() {
1205 assert_eq!(SpecialValueKind::PositiveInfinity.to_f64(), f64::INFINITY);
1206 assert_eq!(
1207 SpecialValueKind::NegativeInfinity.to_f64(),
1208 f64::NEG_INFINITY
1209 );
1210 assert!(SpecialValueKind::NaN.to_f64().is_nan());
1211 }
1212
1213 #[test]
1214 fn test_classify_float() {
1215 assert_eq!(classify_float(1.0), None);
1216 assert_eq!(
1217 classify_float(f64::INFINITY),
1218 Some(SpecialValueKind::PositiveInfinity)
1219 );
1220 assert_eq!(
1221 classify_float(f64::NEG_INFINITY),
1222 Some(SpecialValueKind::NegativeInfinity)
1223 );
1224 assert_eq!(classify_float(f64::NAN), Some(SpecialValueKind::NaN));
1225 }
1226
1227 #[test]
1228 fn test_special_value_kind_from_byte() {
1229 assert_eq!(
1230 SpecialValueKind::from_byte(SPECIAL_POS_INF),
1231 Some(SpecialValueKind::PositiveInfinity)
1232 );
1233 assert_eq!(
1234 SpecialValueKind::from_byte(SPECIAL_NEG_INF),
1235 Some(SpecialValueKind::NegativeInfinity)
1236 );
1237 assert_eq!(
1238 SpecialValueKind::from_byte(SPECIAL_NAN),
1239 Some(SpecialValueKind::NaN)
1240 );
1241 assert_eq!(SpecialValueKind::from_byte(0), None);
1242 assert_eq!(SpecialValueKind::from_byte(99), None);
1243 }
1244
1245 #[test]
1246 fn test_special_value_kind_to_byte() {
1247 assert_eq!(
1248 SpecialValueKind::PositiveInfinity.to_byte(),
1249 SPECIAL_POS_INF
1250 );
1251 assert_eq!(
1252 SpecialValueKind::NegativeInfinity.to_byte(),
1253 SPECIAL_NEG_INF
1254 );
1255 assert_eq!(SpecialValueKind::NaN.to_byte(), SPECIAL_NAN);
1256 }
1257
1258 #[test]
1259 fn test_ceil_div() {
1260 assert_eq!(ceil_div(0, 8), 1);
1262 assert_eq!(ceil_div(1, 8), 1);
1263 assert_eq!(ceil_div(8, 8), 1);
1264 assert_eq!(ceil_div(9, 8), 2);
1265 assert_eq!(ceil_div(16, 8), 2);
1266 assert_eq!(ceil_div(17, 8), 3);
1267 }
1268
1269 #[test]
1270 fn test_count_greater_than() {
1271 let codec = BuffCodec::new(1000);
1272 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
1273 let encoded = codec.encode(&data).unwrap();
1274
1275 assert_eq!(codec.count_greater_than(&encoded, 0.0).unwrap(), 5);
1276 assert_eq!(codec.count_greater_than(&encoded, 2.5).unwrap(), 3);
1277 assert_eq!(codec.count_greater_than(&encoded, 5.0).unwrap(), 0);
1278 }
1279
1280 #[test]
1281 fn test_count_equal() {
1282 let codec = BuffCodec::new(1000);
1283 let data = vec![1.0, 2.0, 2.0, 3.0, 2.0];
1284 let encoded = codec.encode(&data).unwrap();
1285
1286 assert_eq!(codec.count_equal(&encoded, 2.0).unwrap(), 3);
1287 assert_eq!(codec.count_equal(&encoded, 1.0).unwrap(), 1);
1288 assert_eq!(codec.count_equal(&encoded, 99.0).unwrap(), 0);
1289 }
1290
1291 #[test]
1292 fn test_precision_method() {
1293 let codec1 = BuffCodec::new(1000);
1294 assert_eq!(codec1.precision(), 3);
1295
1296 let codec2 = BuffCodec::new(100);
1297 assert_eq!(codec2.precision(), 2);
1298
1299 let codec3 = BuffCodec::new(10);
1300 assert_eq!(codec3.precision(), 1);
1301
1302 let codec0 = BuffCodec::new(0);
1303 assert_eq!(codec0.precision(), 0);
1304 }
1305
1306 #[test]
1307 fn test_has_special_values() {
1308 let codec = BuffCodec::new(1000);
1309
1310 let data_v1 = vec![1.0, 2.0, 3.0];
1312 let encoded_v1 = codec.encode(&data_v1).unwrap();
1313 assert!(!codec.has_special_values(&encoded_v1));
1314
1315 let data_v2 = vec![1.0, f64::INFINITY, 3.0];
1317 let encoded_v2 = codec.encode_with_special(&data_v2).unwrap();
1318 assert!(codec.has_special_values(&encoded_v2));
1319
1320 assert!(!codec.has_special_values(&[]));
1322 }
1323
1324 #[test]
1325 fn test_decode_invalid_data_v1() {
1326 let codec = BuffCodec::new(1000);
1327
1328 let short_data = vec![0u8; 10];
1330 assert!(codec.decode(&short_data).is_err());
1331 }
1332
1333 #[test]
1334 fn test_decode_invalid_data_v2() {
1335 let codec = BuffCodec::new(1000);
1336
1337 let mut short_v2 = vec![FORMAT_V2];
1339 short_v2.extend_from_slice(&[0u8; 10]);
1340 assert!(codec.decode(&short_v2).is_err());
1341 }
1342
1343 #[test]
1344 fn test_encode_with_special_empty() {
1345 let codec = BuffCodec::new(1000);
1346 let result = codec.encode_with_special(&[]);
1347 assert!(matches!(result, Err(BuffError::EmptyInput)));
1348 }
1349
1350 #[test]
1351 fn test_metadata_compression_ratio() {
1352 let codec = BuffCodec::new(1000);
1353 let data: Vec<f64> = (0..100).map(|i| i as f64 / 10.0).collect();
1354 let encoded = codec.encode(&data).unwrap();
1355 let metadata = codec.metadata(&encoded).unwrap();
1356
1357 let ratio = metadata.compression_ratio();
1359 assert!(ratio > 0.0);
1360 assert!(ratio < 2.0); }
1362
1363 #[test]
1364 fn test_special_value_struct() {
1365 let sv = SpecialValue {
1366 index: 42,
1367 kind: SpecialValueKind::NaN,
1368 };
1369 assert_eq!(sv.index, 42);
1370 assert_eq!(sv.kind, SpecialValueKind::NaN);
1371 }
1372
1373 #[test]
1374 fn test_buff_metadata_debug() {
1375 let metadata = BuffMetadata {
1376 base_value: 100,
1377 count: 10,
1378 integer_bits: 8,
1379 decimal_bits: 4,
1380 total_bytes: 50,
1381 };
1382 let debug_str = format!("{:?}", metadata);
1383 assert!(debug_str.contains("BuffMetadata"));
1384 }
1385
1386 #[test]
1387 fn test_encode_decode_wide_range() {
1388 let codec = BuffCodec::new(100);
1389 let data: Vec<f64> = (0..100).map(|i| i as f64 * 1000.0).collect();
1391 let encoded = codec.encode(&data).unwrap();
1392 let decoded = codec.decode(&encoded).unwrap();
1393
1394 assert_eq!(data.len(), decoded.len());
1395 for (orig, dec) in data.iter().zip(decoded.iter()) {
1396 assert!((orig - dec).abs() < 10.0);
1397 }
1398 }
1399
1400 #[test]
1401 fn test_encode_decode_zero_delta() {
1402 let codec = BuffCodec::new(1000);
1403 let data = vec![42.0; 50];
1405 let encoded = codec.encode(&data).unwrap();
1406 let decoded = codec.decode(&encoded).unwrap();
1407
1408 assert_eq!(decoded.len(), 50);
1409 for val in decoded {
1410 assert!((val - 42.0).abs() < 0.001);
1411 }
1412 }
1413
1414 #[test]
1415 fn test_sum_identical_values() {
1416 let codec = BuffCodec::new(1000);
1417 let data = vec![5.0; 100];
1418 let encoded = codec.encode(&data).unwrap();
1419 let sum = codec.sum(&encoded).unwrap();
1420
1421 assert!((sum - 500.0).abs() < 0.1);
1422 }
1423
1424 #[test]
1425 fn test_max_identical_values() {
1426 let codec = BuffCodec::new(1000);
1427 let data = vec![7.5; 100];
1428 let encoded = codec.encode(&data).unwrap();
1429 let max = codec.max(&encoded).unwrap();
1430
1431 assert!((max - 7.5).abs() < 0.01);
1432 }
1433
1434 #[test]
1435 fn test_encode_decode_three_chunks() {
1436 let codec = BuffCodec::new(10000); let data: Vec<f64> = (0..100).map(|i| i as f64 * 100.0 + 0.1234).collect();
1439 let encoded = codec.encode(&data).unwrap();
1440 let decoded = codec.decode(&encoded).unwrap();
1441
1442 assert_eq!(data.len(), decoded.len());
1443 for (orig, dec) in data.iter().zip(decoded.iter()) {
1444 assert!((orig - dec).abs() < 0.001);
1445 }
1446 }
1447
1448 #[test]
1449 fn test_encode_decode_four_chunks() {
1450 let codec = BuffCodec::new(1000); let data: Vec<f64> = (0..100).map(|i| i as f64 * 1000.0).collect();
1454 let encoded = codec.encode(&data).unwrap();
1455 let decoded = codec.decode(&encoded).unwrap();
1456
1457 assert_eq!(data.len(), decoded.len());
1458 for (orig, dec) in data.iter().zip(decoded.iter()) {
1459 assert!((orig - dec).abs() < 0.1);
1460 }
1461 }
1462
1463 #[test]
1464 fn test_sum_three_chunks() {
1465 let codec = BuffCodec::new(10000);
1466 let data: Vec<f64> = (1..=10).map(|i| i as f64 * 100.0).collect();
1467 let encoded = codec.encode(&data).unwrap();
1468 let sum = codec.sum(&encoded).unwrap();
1469
1470 let expected: f64 = (1..=10).map(|i| i as f64 * 100.0).sum();
1471 assert!((sum - expected).abs() < 1.0);
1472 }
1473
1474 #[test]
1475 fn test_sum_four_chunks() {
1476 let codec = BuffCodec::new(1000);
1477 let data: Vec<f64> = (1..=10).map(|i| i as f64 * 1000.0).collect();
1478 let encoded = codec.encode(&data).unwrap();
1479 let sum = codec.sum(&encoded).unwrap();
1480
1481 let expected: f64 = (1..=10).map(|i| i as f64 * 1000.0).sum();
1482 assert!((sum - expected).abs() < 10.0);
1483 }
1484
1485 #[test]
1486 fn test_max_three_chunks() {
1487 let codec = BuffCodec::new(10000);
1488 let data: Vec<f64> = vec![100.0, 200.0, 5000.0, 300.0];
1489 let encoded = codec.encode(&data).unwrap();
1490 let max = codec.max(&encoded).unwrap();
1491
1492 assert!((max - 5000.0).abs() < 1.0);
1493 }
1494
1495 #[test]
1496 fn test_max_four_chunks() {
1497 let codec = BuffCodec::new(1000);
1498 let data: Vec<f64> = vec![100.0, 50000.0, 3000.0, 4000.0];
1499 let encoded = codec.encode(&data).unwrap();
1500 let max = codec.max(&encoded).unwrap();
1501
1502 assert!((max - 50000.0).abs() < 1.0);
1503 }
1504
1505 #[test]
1506 fn test_decode_v2_truncated_special_values() {
1507 let codec = BuffCodec::new(1000);
1508
1509 let mut data = vec![FORMAT_V2];
1511 data.extend_from_slice(&0i64.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&5u32.to_le_bytes()); let result = codec.decode(&data);
1519 assert!(result.is_err());
1520 }
1521
1522 #[test]
1523 fn test_decode_v2_invalid_special_type() {
1524 let codec = BuffCodec::new(1000);
1525
1526 let mut data = vec![FORMAT_V2];
1528 data.extend_from_slice(&0i64.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&1u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.push(99); let result = codec.decode(&data);
1537 assert!(result.is_err());
1538 }
1539
1540 #[test]
1541 fn test_sum_error_handling() {
1542 let codec = BuffCodec::new(1000);
1543 let short_data = vec![0u8; 10]; let result = codec.sum(&short_data);
1545 assert!(result.is_err());
1546 }
1547
1548 #[test]
1549 fn test_max_error_handling() {
1550 let codec = BuffCodec::new(1000);
1551 let short_data = vec![0u8; 10]; let result = codec.max(&short_data);
1553 assert!(result.is_err());
1554 }
1555
1556 #[test]
1557 fn test_metadata_error_handling() {
1558 let codec = BuffCodec::new(1000);
1559 let short_data = vec![0u8; 10]; let result = codec.metadata(&short_data);
1561 assert!(result.is_err());
1562 }
1563
1564 #[test]
1565 fn test_count_greater_than_with_special() {
1566 let codec = BuffCodec::new(1000);
1567 let data = vec![1.0, f64::INFINITY, 3.0, f64::NAN, 5.0];
1568 let encoded = codec.encode_with_special(&data).unwrap();
1569
1570 let count = codec.count_greater_than(&encoded, 2.0).unwrap();
1572 assert!(count >= 2); }
1574
1575 #[test]
1576 fn test_encode_decode_two_chunks() {
1577 let codec = BuffCodec::new(100);
1579 let data: Vec<f64> = (0..100).map(|i| i as f64 * 10.0).collect();
1580 let encoded = codec.encode(&data).unwrap();
1581 let decoded = codec.decode(&encoded).unwrap();
1582
1583 assert_eq!(data.len(), decoded.len());
1584 for (orig, dec) in data.iter().zip(decoded.iter()) {
1585 assert!((orig - dec).abs() < 0.1);
1586 }
1587 }
1588
1589 #[test]
1590 fn test_sum_two_chunks() {
1591 let codec = BuffCodec::new(100);
1592 let data: Vec<f64> = (1..=10).map(|i| i as f64 * 10.0).collect();
1593 let encoded = codec.encode(&data).unwrap();
1594 let sum = codec.sum(&encoded).unwrap();
1595
1596 let expected: f64 = (1..=10).map(|i| i as f64 * 10.0).sum();
1597 assert!((sum - expected).abs() < 1.0);
1598 }
1599
1600 #[test]
1601 fn test_max_two_chunks() {
1602 let codec = BuffCodec::new(100);
1603 let data: Vec<f64> = vec![10.0, 50.0, 30.0, 40.0];
1604 let encoded = codec.encode(&data).unwrap();
1605 let max = codec.max(&encoded).unwrap();
1606
1607 assert!((max - 50.0).abs() < 0.1);
1608 }
1609
1610 #[test]
1611 fn test_encode_with_special_mixed_regular_and_special() {
1612 let codec = BuffCodec::new(1000);
1613
1614 let data = vec![
1616 f64::NEG_INFINITY, 1.0,
1618 2.0,
1619 f64::NAN,
1620 3.0,
1621 f64::INFINITY, ];
1623
1624 let encoded = codec.encode_with_special(&data).unwrap();
1625 let decoded = codec.decode(&encoded).unwrap();
1626
1627 assert_eq!(decoded.len(), 6);
1628 assert!(decoded[0].is_infinite() && decoded[0].is_sign_negative());
1629 assert!((decoded[1] - 1.0).abs() < 0.001);
1630 assert!((decoded[2] - 2.0).abs() < 0.001);
1631 assert!(decoded[3].is_nan());
1632 assert!((decoded[4] - 3.0).abs() < 0.001);
1633 assert!(decoded[5].is_infinite() && decoded[5].is_sign_positive());
1634 }
1635
1636 #[test]
1637 fn test_buff_codec_clone() {
1638 let codec1 = BuffCodec::new(1000);
1639 let codec2 = codec1.clone();
1640 assert_eq!(codec1.precision(), codec2.precision());
1641 }
1642
1643 #[test]
1644 fn test_buff_codec_debug() {
1645 let codec = BuffCodec::new(1000);
1646 let debug_str = format!("{:?}", codec);
1647 assert!(debug_str.contains("BuffCodec"));
1648 }
1649
1650 #[test]
1651 fn test_special_value_debug() {
1652 let sv = SpecialValue {
1653 index: 5,
1654 kind: SpecialValueKind::NaN,
1655 };
1656 let debug_str = format!("{:?}", sv);
1657 assert!(debug_str.contains("SpecialValue"));
1658 assert!(debug_str.contains("NaN"));
1659 }
1660
1661 #[test]
1662 fn test_special_value_clone() {
1663 let sv1 = SpecialValue {
1664 index: 5,
1665 kind: SpecialValueKind::PositiveInfinity,
1666 };
1667 let sv2 = sv1;
1668 assert_eq!(sv1, sv2);
1669 }
1670
1671 #[test]
1672 fn test_special_value_kind_eq() {
1673 assert_eq!(SpecialValueKind::NaN, SpecialValueKind::NaN);
1674 assert_eq!(
1675 SpecialValueKind::PositiveInfinity,
1676 SpecialValueKind::PositiveInfinity
1677 );
1678 assert_ne!(SpecialValueKind::NaN, SpecialValueKind::PositiveInfinity);
1679 }
1680
1681 #[test]
1682 fn test_buff_metadata_eq() {
1683 let m1 = BuffMetadata {
1684 base_value: 100,
1685 count: 10,
1686 integer_bits: 8,
1687 decimal_bits: 4,
1688 total_bytes: 50,
1689 };
1690 let m2 = BuffMetadata {
1691 base_value: 100,
1692 count: 10,
1693 integer_bits: 8,
1694 decimal_bits: 4,
1695 total_bytes: 50,
1696 };
1697 assert_eq!(m1, m2);
1698 }
1699
1700 #[test]
1701 fn test_buff_metadata_clone() {
1702 let m1 = BuffMetadata {
1703 base_value: 100,
1704 count: 10,
1705 integer_bits: 8,
1706 decimal_bits: 4,
1707 total_bytes: 50,
1708 };
1709 let m2 = m1.clone();
1710 assert_eq!(m1, m2);
1711 }
1712
1713 #[test]
1714 fn test_encode_decode_small_delta_less_than_byte() {
1715 let codec = BuffCodec::new(10);
1717 let data = vec![1.0, 1.1, 1.2, 1.3]; let encoded = codec.encode(&data).unwrap();
1719 let decoded = codec.decode(&encoded).unwrap();
1720
1721 assert_eq!(data.len(), decoded.len());
1722 for (orig, dec) in data.iter().zip(decoded.iter()) {
1723 assert!((orig - dec).abs() < 0.2);
1724 }
1725 }
1726
1727 #[test]
1728 fn test_v2_format_with_zero_regular_values_decoding() {
1729 let codec = BuffCodec::new(1000);
1730
1731 let data = vec![f64::INFINITY, f64::NAN];
1733 let encoded = codec.encode_with_special(&data).unwrap();
1734 let decoded = codec.decode(&encoded).unwrap();
1735
1736 assert_eq!(decoded.len(), 2);
1737 assert!(decoded[0].is_infinite());
1738 assert!(decoded[1].is_nan());
1739 }
1740
1741 #[test]
1742 fn test_encode_with_special_small_delta_less_than_byte() {
1743 let codec = BuffCodec::new(10);
1745 let data = vec![1.0, f64::INFINITY, 1.1, 1.2]; let encoded = codec.encode_with_special(&data).unwrap();
1747 let decoded = codec.decode(&encoded).unwrap();
1748
1749 assert_eq!(decoded.len(), 4);
1750 assert!((decoded[0] - 1.0).abs() < 0.2);
1751 assert!(decoded[1].is_infinite());
1752 assert!((decoded[2] - 1.1).abs() < 0.2);
1753 assert!((decoded[3] - 1.2).abs() < 0.2);
1754 }
1755
1756 #[test]
1757 fn test_encode_with_special_exactly_8_bits() {
1758 let codec = BuffCodec::new(1);
1760 let data = vec![0.0, f64::NAN, 10.0]; let encoded = codec.encode_with_special(&data).unwrap();
1762 let decoded = codec.decode(&encoded).unwrap();
1763
1764 assert_eq!(decoded.len(), 3);
1765 assert!((decoded[0] - 0.0).abs() < 1.0);
1766 assert!(decoded[1].is_nan());
1767 assert!((decoded[2] - 10.0).abs() < 1.0);
1768 }
1769
1770 #[test]
1771 fn test_encode_with_special_multi_byte() {
1772 let codec = BuffCodec::new(100);
1774 let data = vec![0.0, f64::INFINITY, 1000.0, f64::NEG_INFINITY, 500.0];
1775 let encoded = codec.encode_with_special(&data).unwrap();
1776 let decoded = codec.decode(&encoded).unwrap();
1777
1778 assert_eq!(decoded.len(), 5);
1779 assert!((decoded[0] - 0.0).abs() < 1.0);
1780 assert!(decoded[1].is_infinite() && decoded[1].is_sign_positive());
1781 assert!((decoded[2] - 1000.0).abs() < 1.0);
1782 assert!(decoded[3].is_infinite() && decoded[3].is_sign_negative());
1783 assert!((decoded[4] - 500.0).abs() < 1.0);
1784 }
1785
1786 #[test]
1787 fn test_encode_with_special_remain_zero_after_loop() {
1788 let codec = BuffCodec::new(10);
1790 let data = vec![0.0, f64::NAN, 100.0, 200.0]; let encoded = codec.encode_with_special(&data).unwrap();
1792 let decoded = codec.decode(&encoded).unwrap();
1793
1794 assert_eq!(decoded.len(), 4);
1795 assert!(decoded[1].is_nan());
1796 }
1797
1798 #[test]
1799 fn test_encode_with_special_partial_byte_remainder() {
1800 let codec = BuffCodec::new(100);
1802 let data = vec![0.0, f64::INFINITY, 50.0, 100.0, 150.0];
1803 let encoded = codec.encode_with_special(&data).unwrap();
1804 let decoded = codec.decode(&encoded).unwrap();
1805
1806 assert_eq!(decoded.len(), 5);
1807 assert!(decoded[1].is_infinite());
1808 }
1809
1810 #[test]
1811 fn test_encode_exactly_8_bits() {
1812 let codec = BuffCodec::new(1);
1814 let data = vec![0.0, 10.0, 5.0]; let encoded = codec.encode(&data).unwrap();
1816 let decoded = codec.decode(&encoded).unwrap();
1817
1818 assert_eq!(decoded.len(), 3);
1819 for (orig, dec) in data.iter().zip(decoded.iter()) {
1820 assert!((orig - dec).abs() < 1.0);
1821 }
1822 }
1823
1824 #[test]
1825 fn test_decode_v2_two_chunks() {
1826 let codec = BuffCodec::new(100);
1828 let data = vec![0.0, f64::NAN, 500.0];
1829 let encoded = codec.encode_with_special(&data).unwrap();
1830 let decoded = codec.decode(&encoded).unwrap();
1831
1832 assert_eq!(decoded.len(), 3);
1833 assert!(decoded[1].is_nan());
1834 }
1835
1836 #[test]
1837 fn test_decode_v2_three_chunks() {
1838 let codec = BuffCodec::new(1000);
1840 let data = vec![0.0, f64::INFINITY, 50000.0];
1841 let encoded = codec.encode_with_special(&data).unwrap();
1842 let decoded = codec.decode(&encoded).unwrap();
1843
1844 assert_eq!(decoded.len(), 3);
1845 assert!(decoded[1].is_infinite());
1846 }
1847
1848 #[test]
1849 fn test_decode_v2_four_chunks() {
1850 let codec = BuffCodec::new(1000);
1852 let data = vec![0.0, f64::NEG_INFINITY, 100000.0, 50000.0];
1853 let encoded = codec.encode_with_special(&data).unwrap();
1854 let decoded = codec.decode(&encoded).unwrap();
1855
1856 assert_eq!(decoded.len(), 4);
1857 assert!(decoded[1].is_infinite() && decoded[1].is_sign_negative());
1858 }
1859
1860 #[test]
1861 fn test_sum_v2_format() {
1862 let codec = BuffCodec::new(1000);
1864 let data = vec![1.0, 2.0, 3.0]; let encoded = codec.encode(&data).unwrap();
1866 let sum = codec.sum(&encoded).unwrap();
1867 assert!((sum - 6.0).abs() < 0.01);
1868 }
1869
1870 #[test]
1871 fn test_max_v2_format() {
1872 let codec = BuffCodec::new(1000);
1874 let data = vec![1.0, 5.0, 3.0];
1875 let encoded = codec.encode(&data).unwrap();
1876 let max = codec.max(&encoded).unwrap();
1877 assert!((max - 5.0).abs() < 0.01);
1878 }
1879
1880 #[test]
1881 fn test_decode_v1_unsupported_bit_length() {
1882 let codec = BuffCodec::new(1000);
1884
1885 let mut data = Vec::new();
1887 data.extend_from_slice(&0u64.to_le_bytes());
1889 data.extend_from_slice(&10u32.to_le_bytes());
1891 data.extend_from_slice(&20u32.to_le_bytes());
1893 data.extend_from_slice(&20u32.to_le_bytes());
1895
1896 let result = codec.decode(&data);
1897 assert!(result.is_err());
1898 }
1899
1900 #[test]
1901 fn test_decode_v2_unsupported_bit_length() {
1902 let codec = BuffCodec::new(1000);
1904
1905 let mut data = vec![FORMAT_V2];
1907 data.extend_from_slice(&0i64.to_le_bytes());
1909 data.extend_from_slice(&5u32.to_le_bytes());
1911 data.extend_from_slice(&20u32.to_le_bytes());
1913 data.extend_from_slice(&20u32.to_le_bytes());
1915 data.extend_from_slice(&0u32.to_le_bytes());
1917 data.extend_from_slice(&[0u8; 50]);
1919
1920 let result = codec.decode(&data);
1921 assert!(result.is_err());
1922 }
1923
1924 #[test]
1925 fn test_sum_unsupported_bit_length() {
1926 let codec = BuffCodec::new(1000);
1928
1929 let mut data = Vec::new();
1931 data.extend_from_slice(&0u64.to_le_bytes()); data.extend_from_slice(&10u32.to_le_bytes()); data.extend_from_slice(&20u32.to_le_bytes()); data.extend_from_slice(&20u32.to_le_bytes()); let result = codec.sum(&data);
1937 assert!(result.is_err());
1938 }
1939
1940 #[test]
1941 fn test_max_unsupported_bit_length() {
1942 let codec = BuffCodec::new(1000);
1944
1945 let mut data = Vec::new();
1947 data.extend_from_slice(&0u64.to_le_bytes()); data.extend_from_slice(&10u32.to_le_bytes()); data.extend_from_slice(&20u32.to_le_bytes()); data.extend_from_slice(&20u32.to_le_bytes()); let result = codec.max(&data);
1953 assert!(result.is_err());
1954 }
1955}