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}