1use super::error::BinaryError;
9use super::types::{BinaryValue, TypeTag};
10use super::varint;
11use lnmp_core::{FieldId, LnmpField};
12use lnmp_embedding::{Decoder as EmbeddingDecoder, Encoder as EmbeddingEncoder};
13
14#[derive(Debug, Clone, PartialEq)]
16pub struct BinaryEntry {
17 pub fid: FieldId,
19 pub tag: TypeTag,
21 pub value: BinaryValue,
23}
24
25impl BinaryEntry {
26 pub fn new(fid: FieldId, value: BinaryValue) -> Self {
28 Self {
29 fid,
30 tag: value.type_tag(),
31 value,
32 }
33 }
34
35 pub fn from_field(field: &LnmpField) -> Result<Self, BinaryError> {
42 let value = BinaryValue::from_lnmp_value(&field.value).map_err(|e| match e {
43 BinaryError::InvalidValue {
44 type_tag, reason, ..
45 } => BinaryError::InvalidValue {
46 field_id: field.fid,
47 type_tag,
48 reason,
49 },
50 other => other,
51 })?;
52
53 Ok(Self {
54 fid: field.fid,
55 tag: value.type_tag(),
56 value,
57 })
58 }
59
60 pub fn to_field(&self) -> LnmpField {
62 LnmpField {
63 fid: self.fid,
64 value: self.value.to_lnmp_value(),
65 }
66 }
67
68 pub fn type_tag(&self) -> TypeTag {
70 self.tag
71 }
72
73 pub fn encode(&self) -> Vec<u8> {
83 let mut bytes = Vec::new();
84
85 bytes.extend_from_slice(&self.fid.to_le_bytes());
87
88 bytes.push(self.tag.to_u8());
90
91 match &self.value {
93 BinaryValue::Int(i) => {
94 bytes.extend_from_slice(&varint::encode(*i));
96 }
97 BinaryValue::Float(f) => {
98 bytes.extend_from_slice(&f.to_le_bytes());
100 }
101 BinaryValue::Bool(b) => {
102 bytes.push(if *b { 0x01 } else { 0x00 });
104 }
105 BinaryValue::String(s) => {
106 let utf8_bytes = s.as_bytes();
108 bytes.extend_from_slice(&varint::encode(utf8_bytes.len() as i64));
109 bytes.extend_from_slice(utf8_bytes);
110 }
111 BinaryValue::StringArray(arr) => {
112 bytes.extend_from_slice(&varint::encode(arr.len() as i64));
114 for s in arr {
115 let utf8_bytes = s.as_bytes();
116 bytes.extend_from_slice(&varint::encode(utf8_bytes.len() as i64));
117 bytes.extend_from_slice(utf8_bytes);
118 }
119 }
120 BinaryValue::NestedRecord(_) | BinaryValue::NestedArray(_) => {
121 panic!("Nested structure encoding not yet implemented - use BinaryNestedEncoder");
125 }
126 BinaryValue::Embedding(vec) => {
127 let encoded = EmbeddingEncoder::encode(vec).expect("Failed to encode embedding");
132 bytes.extend_from_slice(&varint::encode(encoded.len() as i64));
134 bytes.extend_from_slice(&encoded);
135 }
136 }
137
138 bytes
139 }
140
141 pub fn decode(bytes: &[u8]) -> Result<(Self, usize), BinaryError> {
154 let mut offset = 0;
155
156 if bytes.len() < 2 {
158 return Err(BinaryError::UnexpectedEof {
159 expected: 2,
160 found: bytes.len(),
161 });
162 }
163 let fid = u16::from_le_bytes([bytes[0], bytes[1]]);
164 offset += 2;
165
166 if bytes.len() < offset + 1 {
168 return Err(BinaryError::UnexpectedEof {
169 expected: offset + 1,
170 found: bytes.len(),
171 });
172 }
173 let tag = TypeTag::from_u8(bytes[offset])?;
174 offset += 1;
175
176 let value = match tag {
178 TypeTag::NestedRecord | TypeTag::NestedArray => {
179 return Err(BinaryError::InvalidValue {
181 field_id: fid,
182 type_tag: tag.to_u8(),
183 reason:
184 "Nested structure decoding not yet implemented - use BinaryNestedDecoder"
185 .to_string(),
186 });
187 }
188 TypeTag::Reserved09
189 | TypeTag::Reserved0A
190 | TypeTag::Reserved0B
191 | TypeTag::Reserved0C
192 | TypeTag::Reserved0D
193 | TypeTag::Reserved0E
194 | TypeTag::Reserved0F => {
195 return Err(BinaryError::InvalidValue {
196 field_id: fid,
197 type_tag: tag.to_u8(),
198 reason: format!("Reserved type tag 0x{:02X} cannot be used", tag.to_u8()),
199 });
200 }
201 TypeTag::Int => {
202 let (int_val, consumed) =
203 varint::decode(&bytes[offset..]).map_err(|_| BinaryError::InvalidValue {
204 field_id: fid,
205 type_tag: tag.to_u8(),
206 reason: "Invalid VarInt encoding".to_string(),
207 })?;
208 offset += consumed;
209 BinaryValue::Int(int_val)
210 }
211 TypeTag::Float => {
212 if bytes.len() < offset + 8 {
213 return Err(BinaryError::UnexpectedEof {
214 expected: offset + 8,
215 found: bytes.len(),
216 });
217 }
218 let float_bytes: [u8; 8] = bytes[offset..offset + 8]
219 .try_into()
220 .expect("slice length checked");
221 let float_val = f64::from_le_bytes(float_bytes);
222 offset += 8;
223 BinaryValue::Float(float_val)
224 }
225 TypeTag::Bool => {
226 if bytes.len() < offset + 1 {
227 return Err(BinaryError::UnexpectedEof {
228 expected: offset + 1,
229 found: bytes.len(),
230 });
231 }
232 let bool_val = match bytes[offset] {
233 0x00 => false,
234 0x01 => true,
235 other => {
236 return Err(BinaryError::InvalidValue {
237 field_id: fid,
238 type_tag: tag.to_u8(),
239 reason: format!(
240 "Invalid boolean value: 0x{:02X} (expected 0x00 or 0x01)",
241 other
242 ),
243 });
244 }
245 };
246 offset += 1;
247 BinaryValue::Bool(bool_val)
248 }
249 TypeTag::String => {
250 let (length, consumed) =
251 varint::decode(&bytes[offset..]).map_err(|_| BinaryError::InvalidValue {
252 field_id: fid,
253 type_tag: tag.to_u8(),
254 reason: "Invalid string length VarInt".to_string(),
255 })?;
256 offset += consumed;
257
258 if length < 0 {
259 return Err(BinaryError::InvalidValue {
260 field_id: fid,
261 type_tag: tag.to_u8(),
262 reason: format!("Negative string length: {}", length),
263 });
264 }
265
266 let length = length as usize;
267 if bytes.len() < offset + length {
268 return Err(BinaryError::UnexpectedEof {
269 expected: offset + length,
270 found: bytes.len(),
271 });
272 }
273
274 let string_val = std::str::from_utf8(&bytes[offset..offset + length])
275 .map_err(|_| BinaryError::InvalidUtf8 { field_id: fid })?
276 .to_string();
277 offset += length;
278 BinaryValue::String(string_val)
279 }
280 TypeTag::StringArray => {
281 let (count, consumed) =
282 varint::decode(&bytes[offset..]).map_err(|_| BinaryError::InvalidValue {
283 field_id: fid,
284 type_tag: tag.to_u8(),
285 reason: "Invalid array count VarInt".to_string(),
286 })?;
287 offset += consumed;
288
289 if count < 0 {
290 return Err(BinaryError::InvalidValue {
291 field_id: fid,
292 type_tag: tag.to_u8(),
293 reason: format!("Negative array count: {}", count),
294 });
295 }
296
297 let count = count as usize;
298 let mut strings = Vec::with_capacity(count);
299
300 for _ in 0..count {
301 let (length, consumed) = varint::decode(&bytes[offset..]).map_err(|_| {
302 BinaryError::InvalidValue {
303 field_id: fid,
304 type_tag: tag.to_u8(),
305 reason: "Invalid string length in array".to_string(),
306 }
307 })?;
308 offset += consumed;
309
310 if length < 0 {
311 return Err(BinaryError::InvalidValue {
312 field_id: fid,
313 type_tag: tag.to_u8(),
314 reason: format!("Negative string length in array: {}", length),
315 });
316 }
317
318 let length = length as usize;
319 if bytes.len() < offset + length {
320 return Err(BinaryError::UnexpectedEof {
321 expected: offset + length,
322 found: bytes.len(),
323 });
324 }
325
326 let string_val = std::str::from_utf8(&bytes[offset..offset + length])
327 .map_err(|_| BinaryError::InvalidUtf8 { field_id: fid })?
328 .to_string();
329 offset += length;
330 strings.push(string_val);
331 }
332
333 BinaryValue::StringArray(strings)
334 }
335 TypeTag::Embedding => {
336 let (length, consumed) =
337 varint::decode(&bytes[offset..]).map_err(|_| BinaryError::InvalidValue {
338 field_id: fid,
339 type_tag: tag.to_u8(),
340 reason: "Invalid embedding length VarInt".to_string(),
341 })?;
342 offset += consumed;
343
344 if length < 0 {
345 return Err(BinaryError::InvalidValue {
346 field_id: fid,
347 type_tag: tag.to_u8(),
348 reason: format!("Negative embedding length: {}", length),
349 });
350 }
351
352 let length = length as usize;
353 if bytes.len() < offset + length {
354 return Err(BinaryError::UnexpectedEof {
355 expected: offset + length,
356 found: bytes.len(),
357 });
358 }
359
360 let embedding_bytes = &bytes[offset..offset + length];
361 let vector = EmbeddingDecoder::decode(embedding_bytes).map_err(|e| {
362 BinaryError::InvalidValue {
363 field_id: fid,
364 type_tag: tag.to_u8(),
365 reason: format!("Failed to decode embedding: {}", e),
366 }
367 })?;
368 offset += length;
369
370 BinaryValue::Embedding(vector)
371 }
372 };
373
374 Ok((Self { fid, tag, value }, offset))
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 #![allow(clippy::approx_constant)]
381
382 use super::*;
383 use lnmp_core::LnmpValue;
384
385 #[test]
386 fn test_from_field_int() {
387 let field = LnmpField {
388 fid: 12,
389 value: LnmpValue::Int(14532),
390 };
391
392 let entry = BinaryEntry::from_field(&field).unwrap();
393 assert_eq!(entry.fid, 12);
394 assert_eq!(entry.tag, TypeTag::Int);
395 assert_eq!(entry.value, BinaryValue::Int(14532));
396 }
397
398 #[test]
399 fn test_from_field_float() {
400 let field = LnmpField {
401 fid: 5,
402 value: LnmpValue::Float(3.14),
403 };
404
405 let entry = BinaryEntry::from_field(&field).unwrap();
406 assert_eq!(entry.fid, 5);
407 assert_eq!(entry.tag, TypeTag::Float);
408 assert_eq!(entry.value, BinaryValue::Float(3.14));
409 }
410
411 #[test]
412 fn test_from_field_bool() {
413 let field = LnmpField {
414 fid: 7,
415 value: LnmpValue::Bool(true),
416 };
417
418 let entry = BinaryEntry::from_field(&field).unwrap();
419 assert_eq!(entry.fid, 7);
420 assert_eq!(entry.tag, TypeTag::Bool);
421 assert_eq!(entry.value, BinaryValue::Bool(true));
422 }
423
424 #[test]
425 fn test_from_field_string() {
426 let field = LnmpField {
427 fid: 1,
428 value: LnmpValue::String("hello".to_string()),
429 };
430
431 let entry = BinaryEntry::from_field(&field).unwrap();
432 assert_eq!(entry.fid, 1);
433 assert_eq!(entry.tag, TypeTag::String);
434 assert_eq!(entry.value, BinaryValue::String("hello".to_string()));
435 }
436
437 #[test]
438 fn test_from_field_string_array() {
439 let field = LnmpField {
440 fid: 23,
441 value: LnmpValue::StringArray(vec!["admin".to_string(), "dev".to_string()]),
442 };
443
444 let entry = BinaryEntry::from_field(&field).unwrap();
445 assert_eq!(entry.fid, 23);
446 assert_eq!(entry.tag, TypeTag::StringArray);
447 assert_eq!(
448 entry.value,
449 BinaryValue::StringArray(vec!["admin".to_string(), "dev".to_string()])
450 );
451 }
452
453 #[test]
454 fn test_to_field_int() {
455 let entry = BinaryEntry {
456 fid: 12,
457 tag: TypeTag::Int,
458 value: BinaryValue::Int(42),
459 };
460
461 let field = entry.to_field();
462 assert_eq!(field.fid, 12);
463 assert_eq!(field.value, LnmpValue::Int(42));
464 }
465
466 #[test]
467 fn test_to_field_float() {
468 let entry = BinaryEntry {
469 fid: 5,
470 tag: TypeTag::Float,
471 value: BinaryValue::Float(2.718),
472 };
473
474 let field = entry.to_field();
475 assert_eq!(field.fid, 5);
476 assert_eq!(field.value, LnmpValue::Float(2.718));
477 }
478
479 #[test]
480 fn test_to_field_bool() {
481 let entry = BinaryEntry {
482 fid: 7,
483 tag: TypeTag::Bool,
484 value: BinaryValue::Bool(false),
485 };
486
487 let field = entry.to_field();
488 assert_eq!(field.fid, 7);
489 assert_eq!(field.value, LnmpValue::Bool(false));
490 }
491
492 #[test]
493 fn test_to_field_string() {
494 let entry = BinaryEntry {
495 fid: 1,
496 tag: TypeTag::String,
497 value: BinaryValue::String("world".to_string()),
498 };
499
500 let field = entry.to_field();
501 assert_eq!(field.fid, 1);
502 assert_eq!(field.value, LnmpValue::String("world".to_string()));
503 }
504
505 #[test]
506 fn test_to_field_string_array() {
507 let entry = BinaryEntry {
508 fid: 23,
509 tag: TypeTag::StringArray,
510 value: BinaryValue::StringArray(vec!["x".to_string(), "y".to_string()]),
511 };
512
513 let field = entry.to_field();
514 assert_eq!(field.fid, 23);
515 assert_eq!(
516 field.value,
517 LnmpValue::StringArray(vec!["x".to_string(), "y".to_string()])
518 );
519 }
520
521 #[test]
522 fn test_encode_int() {
523 let entry = BinaryEntry {
524 fid: 12,
525 tag: TypeTag::Int,
526 value: BinaryValue::Int(14532),
527 };
528
529 let bytes = entry.encode();
530
531 assert_eq!(bytes[0], 0x0C);
533 assert_eq!(bytes[1], 0x00);
534 assert_eq!(bytes[2], 0x01);
536 let varint_bytes = varint::encode(14532);
538 assert_eq!(&bytes[3..], &varint_bytes[..]);
539 }
540
541 #[test]
542 fn test_encode_float() {
543 let entry = BinaryEntry {
544 fid: 5,
545 tag: TypeTag::Float,
546 value: BinaryValue::Float(3.14),
547 };
548
549 let bytes = entry.encode();
550
551 assert_eq!(bytes[0], 0x05);
553 assert_eq!(bytes[1], 0x00);
554 assert_eq!(bytes[2], 0x02);
556 let float_bytes = 3.14f64.to_le_bytes();
558 assert_eq!(&bytes[3..11], &float_bytes[..]);
559 }
560
561 #[test]
562 fn test_encode_bool_true() {
563 let entry = BinaryEntry {
564 fid: 7,
565 tag: TypeTag::Bool,
566 value: BinaryValue::Bool(true),
567 };
568
569 let bytes = entry.encode();
570
571 assert_eq!(bytes[0], 0x07);
573 assert_eq!(bytes[1], 0x00);
574 assert_eq!(bytes[2], 0x03);
576 assert_eq!(bytes[3], 0x01);
578 }
579
580 #[test]
581 fn test_encode_bool_false() {
582 let entry = BinaryEntry {
583 fid: 7,
584 tag: TypeTag::Bool,
585 value: BinaryValue::Bool(false),
586 };
587
588 let bytes = entry.encode();
589
590 assert_eq!(bytes[0], 0x07);
592 assert_eq!(bytes[1], 0x00);
593 assert_eq!(bytes[2], 0x03);
595 assert_eq!(bytes[3], 0x00);
597 }
598
599 #[test]
600 fn test_encode_string() {
601 let entry = BinaryEntry {
602 fid: 1,
603 tag: TypeTag::String,
604 value: BinaryValue::String("hello".to_string()),
605 };
606
607 let bytes = entry.encode();
608
609 assert_eq!(bytes[0], 0x01);
611 assert_eq!(bytes[1], 0x00);
612 assert_eq!(bytes[2], 0x04);
614 let length_varint = varint::encode(5);
616 assert_eq!(&bytes[3..3 + length_varint.len()], &length_varint[..]);
617 let offset = 3 + length_varint.len();
618 assert_eq!(&bytes[offset..], b"hello");
619 }
620
621 #[test]
622 fn test_encode_string_array() {
623 let entry = BinaryEntry {
624 fid: 23,
625 tag: TypeTag::StringArray,
626 value: BinaryValue::StringArray(vec!["admin".to_string(), "dev".to_string()]),
627 };
628
629 let bytes = entry.encode();
630
631 assert_eq!(bytes[0], 0x17);
633 assert_eq!(bytes[1], 0x00);
634 assert_eq!(bytes[2], 0x05);
636
637 let mut offset = 3;
638 let count_varint = varint::encode(2);
640 assert_eq!(
641 &bytes[offset..offset + count_varint.len()],
642 &count_varint[..]
643 );
644 offset += count_varint.len();
645
646 let len1_varint = varint::encode(5);
648 assert_eq!(&bytes[offset..offset + len1_varint.len()], &len1_varint[..]);
649 offset += len1_varint.len();
650 assert_eq!(&bytes[offset..offset + 5], b"admin");
651 offset += 5;
652
653 let len2_varint = varint::encode(3);
655 assert_eq!(&bytes[offset..offset + len2_varint.len()], &len2_varint[..]);
656 offset += len2_varint.len();
657 assert_eq!(&bytes[offset..offset + 3], b"dev");
658 }
659
660 #[test]
661 fn test_decode_int() {
662 let entry = BinaryEntry {
663 fid: 12,
664 tag: TypeTag::Int,
665 value: BinaryValue::Int(14532),
666 };
667
668 let bytes = entry.encode();
669 let (decoded, consumed) = BinaryEntry::decode(&bytes).unwrap();
670
671 assert_eq!(decoded, entry);
672 assert_eq!(consumed, bytes.len());
673 }
674
675 #[test]
676 fn test_decode_float() {
677 let entry = BinaryEntry {
678 fid: 5,
679 tag: TypeTag::Float,
680 value: BinaryValue::Float(3.14),
681 };
682
683 let bytes = entry.encode();
684 let (decoded, consumed) = BinaryEntry::decode(&bytes).unwrap();
685
686 assert_eq!(decoded, entry);
687 assert_eq!(consumed, bytes.len());
688 }
689
690 #[test]
691 fn test_decode_bool() {
692 let entry = BinaryEntry {
693 fid: 7,
694 tag: TypeTag::Bool,
695 value: BinaryValue::Bool(true),
696 };
697
698 let bytes = entry.encode();
699 let (decoded, consumed) = BinaryEntry::decode(&bytes).unwrap();
700
701 assert_eq!(decoded, entry);
702 assert_eq!(consumed, bytes.len());
703 }
704
705 #[test]
706 fn test_decode_string() {
707 let entry = BinaryEntry {
708 fid: 1,
709 tag: TypeTag::String,
710 value: BinaryValue::String("hello".to_string()),
711 };
712
713 let bytes = entry.encode();
714 let (decoded, consumed) = BinaryEntry::decode(&bytes).unwrap();
715
716 assert_eq!(decoded, entry);
717 assert_eq!(consumed, bytes.len());
718 }
719
720 #[test]
721 fn test_decode_string_array() {
722 let entry = BinaryEntry {
723 fid: 23,
724 tag: TypeTag::StringArray,
725 value: BinaryValue::StringArray(vec!["admin".to_string(), "dev".to_string()]),
726 };
727
728 let bytes = entry.encode();
729 let (decoded, consumed) = BinaryEntry::decode(&bytes).unwrap();
730
731 assert_eq!(decoded, entry);
732 assert_eq!(consumed, bytes.len());
733 }
734
735 #[test]
736 fn test_decode_with_trailing_data() {
737 let entry = BinaryEntry {
738 fid: 1,
739 tag: TypeTag::Int,
740 value: BinaryValue::Int(42),
741 };
742
743 let mut bytes = entry.encode();
744 bytes.extend_from_slice(&[0xFF, 0xFF, 0xFF]); let (decoded, consumed) = BinaryEntry::decode(&bytes).unwrap();
747
748 assert_eq!(decoded, entry);
749 assert_eq!(consumed, bytes.len() - 3); }
751
752 #[test]
753 fn test_decode_insufficient_data_fid() {
754 let bytes = vec![0x01]; let result = BinaryEntry::decode(&bytes);
756 assert!(matches!(result, Err(BinaryError::UnexpectedEof { .. })));
757 }
758
759 #[test]
760 fn test_decode_insufficient_data_tag() {
761 let bytes = vec![0x01, 0x00]; let result = BinaryEntry::decode(&bytes);
763 assert!(matches!(result, Err(BinaryError::UnexpectedEof { .. })));
764 }
765
766 #[test]
767 fn test_decode_invalid_type_tag() {
768 let bytes = vec![0x01, 0x00, 0xFF]; let result = BinaryEntry::decode(&bytes);
770 assert!(matches!(result, Err(BinaryError::InvalidTypeTag { .. })));
771 }
772
773 #[test]
774 fn test_decode_invalid_bool_value() {
775 let bytes = vec![0x01, 0x00, 0x03, 0x02]; let result = BinaryEntry::decode(&bytes);
777 assert!(matches!(result, Err(BinaryError::InvalidValue { .. })));
778 }
779
780 #[test]
781 fn test_decode_invalid_utf8() {
782 let mut bytes = vec![0x01, 0x00, 0x04]; bytes.extend_from_slice(&varint::encode(3)); bytes.extend_from_slice(&[0xFF, 0xFE, 0xFD]); let result = BinaryEntry::decode(&bytes);
787 assert!(matches!(result, Err(BinaryError::InvalidUtf8 { .. })));
788 }
789
790 #[test]
791 fn test_roundtrip_all_types() {
792 let test_cases = vec![
793 BinaryEntry {
794 fid: 1,
795 tag: TypeTag::Int,
796 value: BinaryValue::Int(-42),
797 },
798 BinaryEntry {
799 fid: 2,
800 tag: TypeTag::Float,
801 value: BinaryValue::Float(3.14159),
802 },
803 BinaryEntry {
804 fid: 3,
805 tag: TypeTag::Bool,
806 value: BinaryValue::Bool(true),
807 },
808 BinaryEntry {
809 fid: 4,
810 tag: TypeTag::String,
811 value: BinaryValue::String("test".to_string()),
812 },
813 BinaryEntry {
814 fid: 5,
815 tag: TypeTag::StringArray,
816 value: BinaryValue::StringArray(vec!["a".to_string(), "b".to_string()]),
817 },
818 ];
819
820 for entry in test_cases {
821 let bytes = entry.encode();
822 let (decoded, _) = BinaryEntry::decode(&bytes).unwrap();
823 assert_eq!(decoded, entry);
824 }
825 }
826
827 #[test]
828 fn test_fid_boundary_values() {
829 let entry0 = BinaryEntry {
831 fid: 0,
832 tag: TypeTag::Int,
833 value: BinaryValue::Int(1),
834 };
835 let bytes0 = entry0.encode();
836 let (decoded0, _) = BinaryEntry::decode(&bytes0).unwrap();
837 assert_eq!(decoded0.fid, 0);
838
839 let entry_max = BinaryEntry {
841 fid: 65535,
842 tag: TypeTag::Int,
843 value: BinaryValue::Int(1),
844 };
845 let bytes_max = entry_max.encode();
846 let (decoded_max, _) = BinaryEntry::decode(&bytes_max).unwrap();
847 assert_eq!(decoded_max.fid, 65535);
848 }
849
850 #[test]
851 fn test_empty_string() {
852 let entry = BinaryEntry {
853 fid: 1,
854 tag: TypeTag::String,
855 value: BinaryValue::String("".to_string()),
856 };
857
858 let bytes = entry.encode();
859 let (decoded, _) = BinaryEntry::decode(&bytes).unwrap();
860 assert_eq!(decoded, entry);
861 }
862
863 #[test]
864 fn test_empty_string_array() {
865 let entry = BinaryEntry {
866 fid: 1,
867 tag: TypeTag::StringArray,
868 value: BinaryValue::StringArray(vec![]),
869 };
870
871 let bytes = entry.encode();
872 let (decoded, _) = BinaryEntry::decode(&bytes).unwrap();
873 assert_eq!(decoded, entry);
874 }
875
876 #[test]
877 fn test_string_with_unicode() {
878 let entry = BinaryEntry {
879 fid: 1,
880 tag: TypeTag::String,
881 value: BinaryValue::String("Hello 🎯 World".to_string()),
882 };
883
884 let bytes = entry.encode();
885 let (decoded, _) = BinaryEntry::decode(&bytes).unwrap();
886 assert_eq!(decoded, entry);
887 }
888
889 #[test]
890 fn test_negative_int() {
891 let entry = BinaryEntry {
892 fid: 1,
893 tag: TypeTag::Int,
894 value: BinaryValue::Int(-9999),
895 };
896
897 let bytes = entry.encode();
898 let (decoded, _) = BinaryEntry::decode(&bytes).unwrap();
899 assert_eq!(decoded, entry);
900 }
901
902 #[test]
903 fn test_special_floats() {
904 let entry_nan = BinaryEntry {
906 fid: 1,
907 tag: TypeTag::Float,
908 value: BinaryValue::Float(f64::NAN),
909 };
910 let bytes_nan = entry_nan.encode();
911 let (decoded_nan, _) = BinaryEntry::decode(&bytes_nan).unwrap();
912 match decoded_nan.value {
913 BinaryValue::Float(f) => assert!(f.is_nan()),
914 _ => panic!("Expected Float variant"),
915 }
916
917 let entry_inf = BinaryEntry {
919 fid: 2,
920 tag: TypeTag::Float,
921 value: BinaryValue::Float(f64::INFINITY),
922 };
923 let bytes_inf = entry_inf.encode();
924 let (decoded_inf, _) = BinaryEntry::decode(&bytes_inf).unwrap();
925 assert_eq!(decoded_inf, entry_inf);
926
927 let entry_neg_inf = BinaryEntry {
929 fid: 3,
930 tag: TypeTag::Float,
931 value: BinaryValue::Float(f64::NEG_INFINITY),
932 };
933 let bytes_neg_inf = entry_neg_inf.encode();
934 let (decoded_neg_inf, _) = BinaryEntry::decode(&bytes_neg_inf).unwrap();
935 assert_eq!(decoded_neg_inf, entry_neg_inf);
936 }
937}