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