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