1use super::error::BinaryError;
8use super::types::TypeTag;
9use super::varint;
10use lnmp_core::{LnmpRecord, LnmpValue};
11
12#[derive(Debug, Clone)]
14pub struct NestedEncoderConfig {
15 pub max_depth: usize,
17 pub max_record_size: Option<usize>,
19 pub validate_canonical: bool,
21}
22
23impl Default for NestedEncoderConfig {
24 fn default() -> Self {
25 Self {
26 max_depth: 32,
27 max_record_size: None,
28 validate_canonical: false,
29 }
30 }
31}
32
33impl NestedEncoderConfig {
34 pub fn new() -> Self {
36 Self::default()
37 }
38
39 pub fn with_max_depth(mut self, max_depth: usize) -> Self {
41 self.max_depth = max_depth;
42 self
43 }
44
45 pub fn with_max_record_size(mut self, max_size: Option<usize>) -> Self {
47 self.max_record_size = max_size;
48 self
49 }
50
51 pub fn with_validate_canonical(mut self, validate: bool) -> Self {
53 self.validate_canonical = validate;
54 self
55 }
56}
57
58#[derive(Debug)]
62pub struct BinaryNestedEncoder {
63 config: NestedEncoderConfig,
64}
65
66impl BinaryNestedEncoder {
67 pub fn new() -> Self {
69 Self {
70 config: NestedEncoderConfig::default(),
71 }
72 }
73
74 pub fn with_config(config: NestedEncoderConfig) -> Self {
76 Self { config }
77 }
78
79 pub fn encode_nested_record(&self, record: &LnmpRecord) -> Result<Vec<u8>, BinaryError> {
104 self.encode_nested_record_with_depth(record, 0)
105 }
106
107 fn encode_nested_record_with_depth(
109 &self,
110 record: &LnmpRecord,
111 current_depth: usize,
112 ) -> Result<Vec<u8>, BinaryError> {
113 if current_depth >= self.config.max_depth {
115 return Err(BinaryError::NestingDepthExceeded {
116 depth: current_depth,
117 max: self.config.max_depth,
118 });
119 }
120
121 let mut buffer = Vec::new();
122
123 buffer.push(TypeTag::NestedRecord.to_u8());
125
126 let fields = record.sorted_fields();
128
129 let field_count = fields.len() as i64;
131 buffer.extend_from_slice(&varint::encode(field_count));
132
133 for field in fields {
135 buffer.extend_from_slice(&varint::encode(field.fid as i64));
137
138 let value_bytes = self.encode_value_recursive(&field.value, current_depth + 1)?;
140 buffer.extend_from_slice(&value_bytes);
141
142 if let Some(max_size) = self.config.max_record_size {
144 if buffer.len() > max_size {
145 return Err(BinaryError::RecordSizeExceeded {
146 size: buffer.len(),
147 max: max_size,
148 });
149 }
150 }
151 }
152
153 Ok(buffer)
154 }
155
156 pub fn encode_nested_array(&self, records: &[LnmpRecord]) -> Result<Vec<u8>, BinaryError> {
181 self.encode_nested_array_with_depth(records, 0)
182 }
183
184 fn encode_nested_array_with_depth(
186 &self,
187 records: &[LnmpRecord],
188 current_depth: usize,
189 ) -> Result<Vec<u8>, BinaryError> {
190 if current_depth >= self.config.max_depth {
192 return Err(BinaryError::NestingDepthExceeded {
193 depth: current_depth,
194 max: self.config.max_depth,
195 });
196 }
197
198 let mut buffer = Vec::new();
199
200 buffer.push(TypeTag::NestedArray.to_u8());
202
203 let element_count = records.len() as i64;
205 buffer.extend_from_slice(&varint::encode(element_count));
206
207 for record in records {
209 let record_bytes = self.encode_nested_record_with_depth(record, current_depth + 1)?;
211 buffer.extend_from_slice(&record_bytes);
212
213 if let Some(max_size) = self.config.max_record_size {
215 if buffer.len() > max_size {
216 return Err(BinaryError::RecordSizeExceeded {
217 size: buffer.len(),
218 max: max_size,
219 });
220 }
221 }
222 }
223
224 Ok(buffer)
225 }
226
227 fn encode_value_recursive(
229 &self,
230 value: &LnmpValue,
231 current_depth: usize,
232 ) -> Result<Vec<u8>, BinaryError> {
233 if current_depth >= self.config.max_depth
235 && matches!(
236 value,
237 LnmpValue::NestedRecord(_) | LnmpValue::NestedArray(_)
238 )
239 {
240 return Err(BinaryError::NestingDepthExceeded {
241 depth: current_depth,
242 max: self.config.max_depth,
243 });
244 }
245
246 match value {
247 LnmpValue::Int(i) => {
248 let mut buffer = Vec::new();
249 buffer.push(TypeTag::Int.to_u8());
250 buffer.extend_from_slice(&varint::encode(*i));
251 Ok(buffer)
252 }
253 LnmpValue::Float(f) => {
254 let mut buffer = Vec::new();
255 buffer.push(TypeTag::Float.to_u8());
256 buffer.extend_from_slice(&f.to_le_bytes());
257 Ok(buffer)
258 }
259 LnmpValue::Bool(b) => {
260 let mut buffer = Vec::new();
261 buffer.push(TypeTag::Bool.to_u8());
262 buffer.push(if *b { 0x01 } else { 0x00 });
263 Ok(buffer)
264 }
265 LnmpValue::String(s) => {
266 let mut buffer = Vec::new();
267 buffer.push(TypeTag::String.to_u8());
268 let bytes = s.as_bytes();
269 buffer.extend_from_slice(&varint::encode(bytes.len() as i64));
270 buffer.extend_from_slice(bytes);
271 Ok(buffer)
272 }
273 LnmpValue::StringArray(arr) => {
274 let mut buffer = Vec::new();
275 buffer.push(TypeTag::StringArray.to_u8());
276 buffer.extend_from_slice(&varint::encode(arr.len() as i64));
277 for s in arr {
278 let bytes = s.as_bytes();
279 buffer.extend_from_slice(&varint::encode(bytes.len() as i64));
280 buffer.extend_from_slice(bytes);
281 }
282 Ok(buffer)
283 }
284 LnmpValue::EmbeddingDelta(delta) => {
285 let mut buffer = Vec::new();
286 buffer.push(TypeTag::Embedding.to_u8()); let delta_bytes = delta.encode().map_err(|_| BinaryError::InvalidValue {
289 field_id: 0,
290 type_tag: TypeTag::Embedding.to_u8(),
291 reason: "Failed to encode delta".to_string(),
292 })?;
293 buffer.extend_from_slice(&(delta_bytes.len() as u32).to_le_bytes());
294 buffer.extend_from_slice(&delta_bytes);
295 Ok(buffer)
296 }
297 LnmpValue::Embedding(vec) => {
298 let encoded = lnmp_embedding::Encoder::encode(vec).map_err(|_| {
300 BinaryError::InvalidValue {
301 field_id: 0,
302 type_tag: TypeTag::Embedding.to_u8(),
303 reason: "Failed to encode embedding".to_string(),
304 }
305 })?;
306
307 let mut buffer = Vec::new();
308 buffer.push(TypeTag::Embedding.to_u8());
309 buffer.extend_from_slice(&varint::encode(encoded.len() as i64));
310 buffer.extend_from_slice(&encoded);
311 Ok(buffer)
312 }
313 LnmpValue::QuantizedEmbedding(qv) => {
314 let mut buffer = Vec::new();
316 buffer.push(TypeTag::QuantizedEmbedding.to_u8()); buffer.push(qv.scheme as u8);
320
321 buffer.extend_from_slice(&qv.scale.to_le_bytes());
323
324 buffer.push(qv.zero_point as u8);
326
327 buffer.extend_from_slice(&qv.min_val.to_le_bytes());
329
330 buffer.extend_from_slice(&qv.dim.to_le_bytes());
332
333 buffer.extend_from_slice(&varint::encode(qv.data.len() as i64));
335 buffer.extend_from_slice(&qv.data);
336
337 Ok(buffer)
338 }
339 LnmpValue::IntArray(arr) => {
340 let mut buffer = Vec::new();
341 buffer.push(TypeTag::IntArray.to_u8());
342 buffer.extend_from_slice(&varint::encode(arr.len() as i64));
343 for i in arr {
344 buffer.extend_from_slice(&varint::encode(*i));
345 }
346 Ok(buffer)
347 }
348 LnmpValue::FloatArray(arr) => {
349 let mut buffer = Vec::new();
350 buffer.push(TypeTag::FloatArray.to_u8());
351 buffer.extend_from_slice(&varint::encode(arr.len() as i64));
352 for f in arr {
353 buffer.extend_from_slice(&f.to_le_bytes());
354 }
355 Ok(buffer)
356 }
357 LnmpValue::BoolArray(arr) => {
358 let mut buffer = Vec::new();
359 buffer.push(TypeTag::BoolArray.to_u8());
360 buffer.extend_from_slice(&varint::encode(arr.len() as i64));
361 for b in arr {
362 buffer.push(if *b { 0x01 } else { 0x00 });
363 }
364 Ok(buffer)
365 }
366 LnmpValue::NestedRecord(record) => {
367 self.encode_nested_record_with_depth(record, current_depth)
368 }
369 LnmpValue::NestedArray(records) => {
370 self.encode_nested_array_with_depth(records, current_depth)
371 }
372 }
373 }
374}
375
376impl Default for BinaryNestedEncoder {
377 fn default() -> Self {
378 Self::new()
379 }
380}
381
382#[cfg(test)]
383mod tests {
384 #![allow(clippy::approx_constant)]
385
386 use super::*;
387 use lnmp_core::LnmpField;
388
389 #[test]
390 fn test_nested_encoder_config_default() {
391 let config = NestedEncoderConfig::default();
392 assert_eq!(config.max_depth, 32);
393 assert_eq!(config.max_record_size, None);
394 assert!(!config.validate_canonical);
395 }
396
397 #[test]
398 fn test_nested_encoder_config_builder() {
399 let config = NestedEncoderConfig::new()
400 .with_max_depth(16)
401 .with_max_record_size(Some(1024))
402 .with_validate_canonical(true);
403
404 assert_eq!(config.max_depth, 16);
405 assert_eq!(config.max_record_size, Some(1024));
406 assert!(config.validate_canonical);
407 }
408
409 #[test]
410 fn test_encode_empty_nested_record() {
411 let encoder = BinaryNestedEncoder::new();
412 let record = LnmpRecord::new();
413
414 let result = encoder.encode_nested_record(&record).unwrap();
415
416 assert_eq!(result[0], 0x06); assert_eq!(result[1], 0x00); assert_eq!(result.len(), 2);
420 }
421
422 #[test]
423 fn test_encode_single_level_nested_record() {
424 let encoder = BinaryNestedEncoder::new();
425 let mut record = LnmpRecord::new();
426 record.add_field(LnmpField {
427 fid: 1,
428 value: LnmpValue::Int(42),
429 });
430 record.add_field(LnmpField {
431 fid: 2,
432 value: LnmpValue::String("test".to_string()),
433 });
434
435 let result = encoder.encode_nested_record(&record).unwrap();
436
437 assert_eq!(result[0], 0x06); assert_eq!(result[1], 0x02); }
441
442 #[test]
443 fn test_encode_nested_record_canonical_ordering() {
444 let encoder = BinaryNestedEncoder::new();
445 let mut record = LnmpRecord::new();
446 record.add_field(LnmpField {
448 fid: 10,
449 value: LnmpValue::Int(3),
450 });
451 record.add_field(LnmpField {
452 fid: 2,
453 value: LnmpValue::Int(1),
454 });
455 record.add_field(LnmpField {
456 fid: 5,
457 value: LnmpValue::Int(2),
458 });
459
460 let result = encoder.encode_nested_record(&record).unwrap();
461
462 assert_eq!(result[0], 0x06); assert_eq!(result[1], 0x03); assert_eq!(result[2], 0x02); }
470
471 #[test]
472 fn test_encode_empty_nested_array() {
473 let encoder = BinaryNestedEncoder::new();
474 let records: Vec<LnmpRecord> = vec![];
475
476 let result = encoder.encode_nested_array(&records).unwrap();
477
478 assert_eq!(result[0], 0x07); assert_eq!(result[1], 0x00); assert_eq!(result.len(), 2);
482 }
483
484 #[test]
485 fn test_encode_nested_array_single_record() {
486 let encoder = BinaryNestedEncoder::new();
487 let mut record = LnmpRecord::new();
488 record.add_field(LnmpField {
489 fid: 1,
490 value: LnmpValue::Int(42),
491 });
492
493 let result = encoder.encode_nested_array(&[record]).unwrap();
494
495 assert_eq!(result[0], 0x07); assert_eq!(result[1], 0x01); assert_eq!(result[2], 0x06); }
501
502 #[test]
503 fn test_encode_nested_array_multiple_records() {
504 let encoder = BinaryNestedEncoder::new();
505 let mut record1 = LnmpRecord::new();
506 record1.add_field(LnmpField {
507 fid: 1,
508 value: LnmpValue::Int(1),
509 });
510
511 let mut record2 = LnmpRecord::new();
512 record2.add_field(LnmpField {
513 fid: 1,
514 value: LnmpValue::Int(2),
515 });
516
517 let result = encoder.encode_nested_array(&[record1, record2]).unwrap();
518
519 assert_eq!(result[0], 0x07); assert_eq!(result[1], 0x02); }
523
524 #[test]
525 fn test_encode_depth_limit_exceeded() {
526 let config = NestedEncoderConfig::new().with_max_depth(2);
527 let encoder = BinaryNestedEncoder::with_config(config);
528
529 let mut level3 = LnmpRecord::new();
531 level3.add_field(LnmpField {
532 fid: 1,
533 value: LnmpValue::Int(42),
534 });
535
536 let mut level2 = LnmpRecord::new();
537 level2.add_field(LnmpField {
538 fid: 2,
539 value: LnmpValue::NestedRecord(Box::new(level3)),
540 });
541
542 let mut level1 = LnmpRecord::new();
543 level1.add_field(LnmpField {
544 fid: 3,
545 value: LnmpValue::NestedRecord(Box::new(level2)),
546 });
547
548 let result = encoder.encode_nested_record(&level1);
549
550 assert!(result.is_err());
551 match result {
552 Err(BinaryError::NestingDepthExceeded { depth, max }) => {
553 assert_eq!(max, 2);
554 assert!(depth >= 2);
555 }
556 _ => panic!("Expected NestingDepthExceeded error"),
557 }
558 }
559
560 #[test]
561 fn test_encode_size_limit_exceeded() {
562 let config = NestedEncoderConfig::new().with_max_record_size(Some(10));
563 let encoder = BinaryNestedEncoder::with_config(config);
564
565 let mut record = LnmpRecord::new();
566 for i in 0..100 {
568 record.add_field(LnmpField {
569 fid: i,
570 value: LnmpValue::String("test".to_string()),
571 });
572 }
573
574 let result = encoder.encode_nested_record(&record);
575
576 assert!(result.is_err());
577 match result {
578 Err(BinaryError::RecordSizeExceeded { size, max }) => {
579 assert_eq!(max, 10);
580 assert!(size > 10);
581 }
582 _ => panic!("Expected RecordSizeExceeded error"),
583 }
584 }
585
586 #[test]
587 fn test_encode_multi_level_nested_record() {
588 let encoder = BinaryNestedEncoder::new();
589
590 let mut inner_record = LnmpRecord::new();
592 inner_record.add_field(LnmpField {
593 fid: 1,
594 value: LnmpValue::Int(42),
595 });
596
597 let mut outer_record = LnmpRecord::new();
598 outer_record.add_field(LnmpField {
599 fid: 2,
600 value: LnmpValue::NestedRecord(Box::new(inner_record)),
601 });
602
603 let result = encoder.encode_nested_record(&outer_record).unwrap();
604
605 assert_eq!(result[0], 0x06); assert_eq!(result[1], 0x01); assert_eq!(result[2], 0x02); assert_eq!(result[3], 0x06); }
613
614 #[test]
615 fn test_encode_nested_record_depth_2() {
616 let encoder = BinaryNestedEncoder::new();
617
618 let mut level2 = LnmpRecord::new();
620 level2.add_field(LnmpField {
621 fid: 1,
622 value: LnmpValue::Int(100),
623 });
624
625 let mut level1 = LnmpRecord::new();
626 level1.add_field(LnmpField {
627 fid: 2,
628 value: LnmpValue::NestedRecord(Box::new(level2)),
629 });
630
631 let result = encoder.encode_nested_record(&level1).unwrap();
632 assert!(!result.is_empty());
633 assert_eq!(result[0], 0x06); }
635
636 #[test]
637 fn test_encode_nested_record_depth_3() {
638 let encoder = BinaryNestedEncoder::new();
639
640 let mut level3 = LnmpRecord::new();
642 level3.add_field(LnmpField {
643 fid: 1,
644 value: LnmpValue::Int(100),
645 });
646
647 let mut level2 = LnmpRecord::new();
648 level2.add_field(LnmpField {
649 fid: 2,
650 value: LnmpValue::NestedRecord(Box::new(level3)),
651 });
652
653 let mut level1 = LnmpRecord::new();
654 level1.add_field(LnmpField {
655 fid: 3,
656 value: LnmpValue::NestedRecord(Box::new(level2)),
657 });
658
659 let result = encoder.encode_nested_record(&level1).unwrap();
660 assert!(!result.is_empty());
661 assert_eq!(result[0], 0x06); }
663
664 #[test]
665 fn test_encode_nested_record_depth_4() {
666 let encoder = BinaryNestedEncoder::new();
667
668 let mut level4 = LnmpRecord::new();
670 level4.add_field(LnmpField {
671 fid: 1,
672 value: LnmpValue::Int(100),
673 });
674
675 let mut level3 = LnmpRecord::new();
676 level3.add_field(LnmpField {
677 fid: 2,
678 value: LnmpValue::NestedRecord(Box::new(level4)),
679 });
680
681 let mut level2 = LnmpRecord::new();
682 level2.add_field(LnmpField {
683 fid: 3,
684 value: LnmpValue::NestedRecord(Box::new(level3)),
685 });
686
687 let mut level1 = LnmpRecord::new();
688 level1.add_field(LnmpField {
689 fid: 4,
690 value: LnmpValue::NestedRecord(Box::new(level2)),
691 });
692
693 let result = encoder.encode_nested_record(&level1).unwrap();
694 assert!(!result.is_empty());
695 assert_eq!(result[0], 0x06); }
697
698 #[test]
699 fn test_encode_nested_record_depth_5() {
700 let encoder = BinaryNestedEncoder::new();
701
702 let mut level5 = LnmpRecord::new();
704 level5.add_field(LnmpField {
705 fid: 1,
706 value: LnmpValue::Int(100),
707 });
708
709 let mut level4 = LnmpRecord::new();
710 level4.add_field(LnmpField {
711 fid: 2,
712 value: LnmpValue::NestedRecord(Box::new(level5)),
713 });
714
715 let mut level3 = LnmpRecord::new();
716 level3.add_field(LnmpField {
717 fid: 3,
718 value: LnmpValue::NestedRecord(Box::new(level4)),
719 });
720
721 let mut level2 = LnmpRecord::new();
722 level2.add_field(LnmpField {
723 fid: 4,
724 value: LnmpValue::NestedRecord(Box::new(level3)),
725 });
726
727 let mut level1 = LnmpRecord::new();
728 level1.add_field(LnmpField {
729 fid: 5,
730 value: LnmpValue::NestedRecord(Box::new(level2)),
731 });
732
733 let result = encoder.encode_nested_record(&level1).unwrap();
734 assert!(!result.is_empty());
735 assert_eq!(result[0], 0x06); }
737
738 #[test]
739 fn test_encode_depth_limit_enforced_at_exact_limit() {
740 let config = NestedEncoderConfig::new().with_max_depth(2);
741 let encoder = BinaryNestedEncoder::with_config(config);
742
743 let mut level1 = LnmpRecord::new();
745 level1.add_field(LnmpField {
746 fid: 1,
747 value: LnmpValue::Int(42),
748 });
749
750 let result = encoder.encode_nested_record(&level1);
752 assert!(result.is_ok());
753
754 let mut inner = LnmpRecord::new();
756 inner.add_field(LnmpField {
757 fid: 1,
758 value: LnmpValue::Int(42),
759 });
760
761 let mut outer = LnmpRecord::new();
762 outer.add_field(LnmpField {
763 fid: 2,
764 value: LnmpValue::NestedRecord(Box::new(inner)),
765 });
766
767 let result = encoder.encode_nested_record(&outer);
769 assert!(result.is_ok());
770
771 let mut level3 = LnmpRecord::new();
773 level3.add_field(LnmpField {
774 fid: 1,
775 value: LnmpValue::Int(42),
776 });
777
778 let mut level2 = LnmpRecord::new();
779 level2.add_field(LnmpField {
780 fid: 2,
781 value: LnmpValue::NestedRecord(Box::new(level3)),
782 });
783
784 let mut level1_deep = LnmpRecord::new();
785 level1_deep.add_field(LnmpField {
786 fid: 3,
787 value: LnmpValue::NestedRecord(Box::new(level2)),
788 });
789
790 let result = encoder.encode_nested_record(&level1_deep);
792 assert!(result.is_err());
793 }
794
795 #[test]
796 fn test_encode_size_limit_enforced_incrementally() {
797 let config = NestedEncoderConfig::new().with_max_record_size(Some(50));
798 let encoder = BinaryNestedEncoder::with_config(config);
799
800 let mut record = LnmpRecord::new();
801 for i in 0..20 {
803 record.add_field(LnmpField {
804 fid: i,
805 value: LnmpValue::String("test".to_string()),
806 });
807 }
808
809 let result = encoder.encode_nested_record(&record);
810 assert!(result.is_err());
811 match result {
812 Err(BinaryError::RecordSizeExceeded { .. }) => {}
813 _ => panic!("Expected RecordSizeExceeded error"),
814 }
815 }
816
817 #[test]
818 fn test_encode_canonical_ordering_at_all_levels() {
819 let encoder = BinaryNestedEncoder::new();
820
821 let mut inner = LnmpRecord::new();
823 inner.add_field(LnmpField {
824 fid: 10,
825 value: LnmpValue::Int(3),
826 });
827 inner.add_field(LnmpField {
828 fid: 2,
829 value: LnmpValue::Int(1),
830 });
831 inner.add_field(LnmpField {
832 fid: 5,
833 value: LnmpValue::Int(2),
834 });
835
836 let mut outer = LnmpRecord::new();
837 outer.add_field(LnmpField {
838 fid: 20,
839 value: LnmpValue::String("last".to_string()),
840 });
841 outer.add_field(LnmpField {
842 fid: 1,
843 value: LnmpValue::NestedRecord(Box::new(inner)),
844 });
845 outer.add_field(LnmpField {
846 fid: 15,
847 value: LnmpValue::String("middle".to_string()),
848 });
849
850 let result = encoder.encode_nested_record(&outer).unwrap();
851
852 assert_eq!(result[0], 0x06); assert_eq!(result[1], 0x03); assert_eq!(result[2], 0x01); }
857
858 #[test]
859 fn test_encode_empty_nested_records_at_multiple_levels() {
860 let encoder = BinaryNestedEncoder::new();
861
862 let inner = LnmpRecord::new(); let mut outer = LnmpRecord::new();
864 outer.add_field(LnmpField {
865 fid: 1,
866 value: LnmpValue::NestedRecord(Box::new(inner)),
867 });
868
869 let result = encoder.encode_nested_record(&outer).unwrap();
870
871 assert_eq!(result[0], 0x06); assert_eq!(result[1], 0x01); assert_eq!(result[2], 0x01); assert_eq!(result[3], 0x06); assert_eq!(result[4], 0x00); }
877
878 #[test]
879 fn test_encode_empty_nested_arrays() {
880 let encoder = BinaryNestedEncoder::new();
881
882 let mut record = LnmpRecord::new();
883 record.add_field(LnmpField {
884 fid: 1,
885 value: LnmpValue::NestedArray(vec![]),
886 });
887
888 let result = encoder.encode_nested_record(&record).unwrap();
889
890 assert_eq!(result[0], 0x06); assert_eq!(result[1], 0x01); assert_eq!(result[2], 0x01); assert_eq!(result[3], 0x07); assert_eq!(result[4], 0x00); }
896
897 #[test]
898 fn test_encode_nested_array_with_canonical_ordering() {
899 let encoder = BinaryNestedEncoder::new();
900
901 let mut record1 = LnmpRecord::new();
903 record1.add_field(LnmpField {
904 fid: 10,
905 value: LnmpValue::Int(2),
906 });
907 record1.add_field(LnmpField {
908 fid: 5,
909 value: LnmpValue::Int(1),
910 });
911
912 let mut record2 = LnmpRecord::new();
913 record2.add_field(LnmpField {
914 fid: 20,
915 value: LnmpValue::Int(4),
916 });
917 record2.add_field(LnmpField {
918 fid: 15,
919 value: LnmpValue::Int(3),
920 });
921
922 let result = encoder.encode_nested_array(&[record1, record2]).unwrap();
923
924 assert_eq!(result[0], 0x07); assert_eq!(result[1], 0x02); assert_eq!(result[2], 0x06); assert_eq!(result[3], 0x02); assert_eq!(result[4], 0x05); }
933
934 #[test]
935 fn test_encode_mixed_primitive_and_nested_fields() {
936 let encoder = BinaryNestedEncoder::new();
937
938 let mut inner = LnmpRecord::new();
939 inner.add_field(LnmpField {
940 fid: 1,
941 value: LnmpValue::String("inner".to_string()),
942 });
943
944 let mut outer = LnmpRecord::new();
945 outer.add_field(LnmpField {
946 fid: 1,
947 value: LnmpValue::Int(42),
948 });
949 outer.add_field(LnmpField {
950 fid: 2,
951 value: LnmpValue::NestedRecord(Box::new(inner)),
952 });
953 outer.add_field(LnmpField {
954 fid: 3,
955 value: LnmpValue::Bool(true),
956 });
957
958 let result = encoder.encode_nested_record(&outer).unwrap();
959
960 assert_eq!(result[0], 0x06); assert_eq!(result[1], 0x03); }
963
964 #[test]
965 fn test_encode_all_primitive_types_in_nested_record() {
966 let encoder = BinaryNestedEncoder::new();
967
968 let mut record = LnmpRecord::new();
969 record.add_field(LnmpField {
970 fid: 1,
971 value: LnmpValue::Int(-42),
972 });
973 record.add_field(LnmpField {
974 fid: 2,
975 value: LnmpValue::Float(3.14),
976 });
977 record.add_field(LnmpField {
978 fid: 3,
979 value: LnmpValue::Bool(false),
980 });
981 record.add_field(LnmpField {
982 fid: 4,
983 value: LnmpValue::String("test".to_string()),
984 });
985 record.add_field(LnmpField {
986 fid: 5,
987 value: LnmpValue::StringArray(vec!["a".to_string(), "b".to_string()]),
988 });
989
990 let result = encoder.encode_nested_record(&record).unwrap();
991
992 assert_eq!(result[0], 0x06); assert_eq!(result[1], 0x05); }
995}