1use crate::key_dictionary::KeyDictionary;
28use crate::types::Value;
29use crate::value_codec;
30
31pub const MAGIC: &[u8; 4] = b"RDOC";
33
34pub const VERSION: u8 = 0x01;
36
37pub const VERSION_DICT: u8 = 0x02;
43
44const ENTRY_SIZE: usize = 6;
46
47const DICT_ENTRY_SIZE: usize = 9;
53
54const KEY_KIND_DICT: u8 = 0x00;
56
57const KEY_KIND_INLINE: u8 = 0x01;
59
60pub type DictEntry = (u8, u32, u32);
65
66#[derive(Debug, PartialEq)]
68pub enum DocBodyError {
69 TruncatedData,
71 BadMagic,
73 UnsupportedVersion(u8),
75 OffsetOutOfBounds,
77 InvalidFieldName,
79 FieldLimitExceeded,
81 UnknownKeyId(u32),
83 BadKeyKind(u8),
85 ValueCodecError(crate::types::ValueError),
87}
88
89impl From<crate::types::ValueError> for DocBodyError {
90 fn from(e: crate::types::ValueError) -> Self {
91 DocBodyError::ValueCodecError(e)
92 }
93}
94
95impl std::fmt::Display for DocBodyError {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 match self {
98 Self::TruncatedData => write!(f, "document body: truncated data"),
99 Self::BadMagic => write!(f, "document body: bad magic bytes (expected RDOC)"),
100 Self::UnsupportedVersion(v) => write!(f, "document body: unsupported version {v}"),
101 Self::OffsetOutOfBounds => write!(f, "document body: offset points outside buffer"),
102 Self::InvalidFieldName => write!(f, "document body: field name is not valid UTF-8"),
103 Self::FieldLimitExceeded => {
104 write!(f, "document body: field or key-length limit exceeded")
105 }
106 Self::UnknownKeyId(id) => {
107 write!(f, "document body: key-id {id} not found in dictionary")
108 }
109 Self::BadKeyKind(k) => write!(f, "document body: unrecognised key kind {k:#04x}"),
110 Self::ValueCodecError(e) => write!(f, "document body: value codec error: {e}"),
111 }
112 }
113}
114
115impl std::error::Error for DocBodyError {}
116
117pub fn encode(fields: &[(&str, &Value)], out: &mut Vec<u8>) -> Result<(), DocBodyError> {
125 let n = fields.len();
126 if n > u16::MAX as usize {
127 return Err(DocBodyError::FieldLimitExceeded);
128 }
129
130 let mut key_buf: Vec<u8> = Vec::new();
133 let mut val_buf: Vec<u8> = Vec::new();
134 let mut key_lens: Vec<u16> = Vec::with_capacity(n);
135 let mut val_starts: Vec<u32> = Vec::with_capacity(n);
136
137 for (key, value) in fields {
138 let kb = key.as_bytes();
139 if kb.len() > u16::MAX as usize {
140 return Err(DocBodyError::FieldLimitExceeded);
141 }
142 key_lens.push(kb.len() as u16);
143 key_buf.extend_from_slice(kb);
144
145 val_starts.push(val_buf.len() as u32); value_codec::encode(value, &mut val_buf);
147 }
148
149 let vals_abs_start = 4 + 1 + 2 + n * ENTRY_SIZE + key_buf.len();
152
153 out.extend_from_slice(MAGIC);
155 out.push(VERSION);
156 out.extend_from_slice(&(n as u16).to_le_bytes());
157
158 for i in 0..n {
160 let abs_val_offset = vals_abs_start + val_starts[i] as usize;
161 out.extend_from_slice(&key_lens[i].to_le_bytes());
162 out.extend_from_slice(&(abs_val_offset as u32).to_le_bytes());
163 }
164
165 out.extend_from_slice(&key_buf);
167 out.extend_from_slice(&val_buf);
168
169 Ok(())
170}
171
172pub fn decode(data: &[u8]) -> Result<Vec<(String, Value)>, DocBodyError> {
176 let (n, table) = parse_header(data)?;
177 let header_end = 7 + n * ENTRY_SIZE; let mut key_cursor = header_end;
179 let mut result = Vec::with_capacity(n);
180
181 for &(key_len, val_offset) in &table {
182 let key_end = key_cursor + key_len as usize;
184 if key_end > data.len() {
185 return Err(DocBodyError::OffsetOutOfBounds);
186 }
187 let key = std::str::from_utf8(&data[key_cursor..key_end])
188 .map_err(|_| DocBodyError::InvalidFieldName)?
189 .to_string();
190 key_cursor = key_end;
191
192 let value = decode_value_at_offset(data, val_offset)?;
194 result.push((key, value));
195 }
196
197 Ok(result)
198}
199
200pub fn field_names(data: &[u8]) -> Result<Vec<String>, DocBodyError> {
207 let (n, table) = parse_header(data)?;
208 let header_end = 7 + n * ENTRY_SIZE; let mut key_cursor = header_end;
210 let mut names = Vec::with_capacity(n);
211
212 for &(key_len, _val_offset) in &table {
213 let key_end = key_cursor + key_len as usize;
214 if key_end > data.len() {
215 return Err(DocBodyError::OffsetOutOfBounds);
216 }
217 let key = std::str::from_utf8(&data[key_cursor..key_end])
218 .map_err(|_| DocBodyError::InvalidFieldName)?
219 .to_string();
220 key_cursor = key_end;
221 names.push(key);
222 }
223
224 Ok(names)
225}
226
227pub fn read_field_by_name(data: &[u8], name: &str) -> Result<Option<Value>, DocBodyError> {
233 let (n, table) = parse_header(data)?;
234 let header_end = 7 + n * ENTRY_SIZE;
235 let mut key_cursor = header_end;
236
237 for &(key_len, val_offset) in &table {
238 let key_end = key_cursor + key_len as usize;
239 if key_end > data.len() {
240 return Err(DocBodyError::OffsetOutOfBounds);
241 }
242 let key_bytes = &data[key_cursor..key_end];
243 key_cursor = key_end;
244
245 if key_bytes == name.as_bytes() {
246 let value = decode_value_at_offset(data, val_offset)?;
247 return Ok(Some(value));
248 }
249 }
250
251 Ok(None)
252}
253
254pub fn decode_value_at_offset(data: &[u8], val_offset: u32) -> Result<Value, DocBodyError> {
260 let off = val_offset as usize;
261 if off >= data.len() {
262 return Err(DocBodyError::OffsetOutOfBounds);
263 }
264 let (value, _) = value_codec::decode(&data[off..])?;
265 Ok(value)
266}
267
268pub fn parse_header(data: &[u8]) -> Result<(usize, Vec<(u16, u32)>), DocBodyError> {
276 if data.len() < 7 {
277 return Err(DocBodyError::TruncatedData);
278 }
279 if &data[0..4] != MAGIC.as_slice() {
280 return Err(DocBodyError::BadMagic);
281 }
282 if data[4] != VERSION {
283 return Err(DocBodyError::UnsupportedVersion(data[4]));
284 }
285
286 let n = u16::from_le_bytes([data[5], data[6]]) as usize;
287 let table_end = 7 + n * ENTRY_SIZE;
288 if data.len() < table_end {
289 return Err(DocBodyError::TruncatedData);
290 }
291
292 let mut table = Vec::with_capacity(n);
293 for i in 0..n {
294 let base = 7 + i * ENTRY_SIZE;
295 let key_len = u16::from_le_bytes([data[base], data[base + 1]]);
296 let val_offset = u32::from_le_bytes([
297 data[base + 2],
298 data[base + 3],
299 data[base + 4],
300 data[base + 5],
301 ]);
302 table.push((key_len, val_offset));
303 }
304
305 Ok((n, table))
306}
307
308pub fn encode_with_dictionary(
321 fields: &[(&str, &Value)],
322 dict: &mut KeyDictionary,
323 classify: impl Fn(&str) -> bool,
324 out: &mut Vec<u8>,
325) -> Result<(), DocBodyError> {
326 let n = fields.len();
327 if n > u16::MAX as usize {
328 return Err(DocBodyError::FieldLimitExceeded);
329 }
330
331 let mut key_buf: Vec<u8> = Vec::new();
334 let mut val_buf: Vec<u8> = Vec::new();
335 let mut kinds: Vec<u8> = Vec::with_capacity(n);
336 let mut refs: Vec<u32> = Vec::with_capacity(n);
337 let mut val_starts: Vec<u32> = Vec::with_capacity(n);
338
339 for (key, value) in fields {
340 if classify(key) {
341 let id = dict.intern(key);
342 kinds.push(KEY_KIND_DICT);
343 refs.push(id);
344 } else {
345 let kb = key.as_bytes();
346 if kb.len() > u16::MAX as usize {
347 return Err(DocBodyError::FieldLimitExceeded);
348 }
349 kinds.push(KEY_KIND_INLINE);
350 refs.push(kb.len() as u32);
351 key_buf.extend_from_slice(kb);
352 }
353 val_starts.push(val_buf.len() as u32); value_codec::encode(value, &mut val_buf);
355 }
356
357 let vals_abs_start = 4 + 1 + 2 + n * DICT_ENTRY_SIZE + key_buf.len();
360
361 out.extend_from_slice(MAGIC);
362 out.push(VERSION_DICT);
363 out.extend_from_slice(&(n as u16).to_le_bytes());
364
365 for i in 0..n {
366 let abs_val_offset = vals_abs_start + val_starts[i] as usize;
367 out.push(kinds[i]);
368 out.extend_from_slice(&refs[i].to_le_bytes());
369 out.extend_from_slice(&(abs_val_offset as u32).to_le_bytes());
370 }
371
372 out.extend_from_slice(&key_buf);
373 out.extend_from_slice(&val_buf);
374
375 Ok(())
376}
377
378pub fn decode_with_dictionary(
385 data: &[u8],
386 dict: &KeyDictionary,
387) -> Result<Vec<(String, Value)>, DocBodyError> {
388 let (n, table) = parse_dict_header(data)?;
389 let header_end = 7 + n * DICT_ENTRY_SIZE; let mut key_cursor = header_end;
391 let mut result = Vec::with_capacity(n);
392
393 for &(kind, key_ref, val_offset) in &table {
394 let key = match kind {
395 KEY_KIND_DICT => dict
396 .name_of(key_ref)
397 .ok_or(DocBodyError::UnknownKeyId(key_ref))?
398 .to_string(),
399 KEY_KIND_INLINE => {
400 let key_end = key_cursor + key_ref as usize;
401 if key_end > data.len() {
402 return Err(DocBodyError::OffsetOutOfBounds);
403 }
404 let name = std::str::from_utf8(&data[key_cursor..key_end])
405 .map_err(|_| DocBodyError::InvalidFieldName)?
406 .to_string();
407 key_cursor = key_end;
408 name
409 }
410 other => return Err(DocBodyError::BadKeyKind(other)),
411 };
412
413 let value = decode_value_at_offset(data, val_offset)?;
414 result.push((key, value));
415 }
416
417 Ok(result)
418}
419
420pub fn parse_dict_header(data: &[u8]) -> Result<(usize, Vec<DictEntry>), DocBodyError> {
426 if data.len() < 7 {
427 return Err(DocBodyError::TruncatedData);
428 }
429 if &data[0..4] != MAGIC.as_slice() {
430 return Err(DocBodyError::BadMagic);
431 }
432 if data[4] != VERSION_DICT {
433 return Err(DocBodyError::UnsupportedVersion(data[4]));
434 }
435
436 let n = u16::from_le_bytes([data[5], data[6]]) as usize;
437 let table_end = 7 + n * DICT_ENTRY_SIZE;
438 if data.len() < table_end {
439 return Err(DocBodyError::TruncatedData);
440 }
441
442 let mut table = Vec::with_capacity(n);
443 for i in 0..n {
444 let base = 7 + i * DICT_ENTRY_SIZE;
445 let kind = data[base];
446 let key_ref = u32::from_le_bytes([
447 data[base + 1],
448 data[base + 2],
449 data[base + 3],
450 data[base + 4],
451 ]);
452 let val_offset = u32::from_le_bytes([
453 data[base + 5],
454 data[base + 6],
455 data[base + 7],
456 data[base + 8],
457 ]);
458 table.push((kind, key_ref, val_offset));
459 }
460
461 Ok((n, table))
462}
463
464#[cfg(test)]
465mod tests {
466 use super::*;
467 use crate::types::Value;
468 use std::net::{IpAddr, Ipv4Addr};
469
470 fn round_trip(fields: &[(&str, Value)]) -> Vec<(String, Value)> {
471 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
472 let mut buf = Vec::new();
473 encode(&refs, &mut buf).expect("encode");
474 decode(&buf).expect("decode")
475 }
476
477 #[test]
478 fn empty_document_round_trips() {
479 let got = round_trip(&[]);
480 assert!(got.is_empty());
481 }
482
483 #[test]
484 fn single_field_round_trip() {
485 let fields = [("name", Value::text("Alice"))];
486 let got = round_trip(&fields);
487 assert_eq!(got.len(), 1);
488 assert_eq!(got[0].0, "name");
489 assert_eq!(got[0].1, Value::text("Alice"));
490 }
491
492 #[test]
493 fn multi_field_round_trip() {
494 let fields = [
495 ("id", Value::Integer(42)),
496 ("email", Value::Email("a@example.com".to_string())),
497 ("active", Value::Boolean(true)),
498 ("score", Value::Float(9.5)),
499 ];
500 let got = round_trip(&fields);
501 assert_eq!(got.len(), 4);
502 for (i, (k, v)) in fields.iter().enumerate() {
503 assert_eq!(got[i].0, *k);
504 assert_eq!(got[i].1, *v);
505 }
506 }
507
508 #[test]
510 fn rich_semantic_types_round_trip() {
511 let fields = [
512 ("email", Value::Email("user@example.com".to_string())),
513 ("ipv4", Value::Ipv4(0x7f000001)),
514 ("subnet", Value::Subnet(0x0a000000, 0xff000000)),
515 ("color", Value::Color([0xDE, 0xAD, 0xBE])),
516 ("phone", Value::Phone(5511999000000)),
517 ("semver", Value::Semver(1_002_003)),
518 ("uuid", Value::Uuid([0xAB; 16])),
519 (
520 "money",
521 Value::Money {
522 asset_code: "USD".to_string(),
523 minor_units: 9999,
524 scale: 2,
525 },
526 ),
527 ("geo", Value::GeoPoint(-23_550_520, -46_633_308)),
528 (
529 "ip_mixed",
530 Value::IpAddr(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))),
531 ),
532 ("url", Value::Url("https://reddb.io".to_string())),
533 ("color_alpha", Value::ColorAlpha([1, 2, 3, 255])),
534 ("lang", Value::Lang2(*b"en")),
535 ("country", Value::Country3(*b"USA")),
536 ];
537 let got = round_trip(&fields);
538 assert_eq!(got.len(), fields.len());
539 for (i, (k, v)) in fields.iter().enumerate() {
540 assert_eq!(got[i].0, *k, "key mismatch at {i}");
541 assert_eq!(got[i].1, *v, "value mismatch for field {k}");
542 }
543 }
544
545 #[test]
547 fn read_field_by_name_skips_other_fields() {
548 let fields = [
549 ("a", Value::Integer(1)),
550 ("b", Value::text("hello")),
551 ("c", Value::Boolean(false)),
552 ];
553 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
554 let mut buf = Vec::new();
555 encode(&refs, &mut buf).expect("encode");
556
557 let v = read_field_by_name(&buf, "b")
558 .expect("lookup")
559 .expect("found");
560 assert_eq!(v, Value::text("hello"));
561
562 let missing = read_field_by_name(&buf, "z").expect("lookup");
563 assert!(missing.is_none());
564 }
565
566 #[test]
568 fn field_names_lists_keys_in_encode_order() {
569 let fields = [
570 ("name", Value::text("Alice")),
571 ("score", Value::Integer(30)),
572 ("active", Value::Boolean(true)),
573 ];
574 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
575 let mut buf = Vec::new();
576 encode(&refs, &mut buf).expect("encode");
577
578 let names = field_names(&buf).expect("field_names");
579 assert_eq!(names, vec!["name", "score", "active"]);
580
581 assert!(field_names(&[]).is_err());
582 }
583
584 #[test]
586 fn decode_value_at_offset_matches_full_decode() {
587 let fields = [("x", Value::Integer(100)), ("y", Value::Float(1.5))];
588 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
589 let mut buf = Vec::new();
590 encode(&refs, &mut buf).expect("encode");
591
592 let (n, table) = parse_header(&buf).expect("parse_header");
593 assert_eq!(n, 2);
594
595 for (i, (k, v)) in fields.iter().enumerate() {
596 let (_key_len, val_offset) = table[i];
597 let got = decode_value_at_offset(&buf, val_offset).expect("decode_at_offset");
598 assert_eq!(got, *v, "field {k} mismatch");
599 }
600 }
601
602 #[test]
603 fn rejects_bad_magic() {
604 let mut buf = vec![b'X', b'X', b'X', b'X', VERSION, 0, 0];
605 assert_eq!(decode(&buf), Err(DocBodyError::BadMagic));
606 buf[0..4].copy_from_slice(MAGIC);
607 buf[4] = 0x99;
608 assert_eq!(decode(&buf), Err(DocBodyError::UnsupportedVersion(0x99)));
609 }
610
611 #[test]
612 fn rejects_truncated_buffer() {
613 assert_eq!(decode(&[]), Err(DocBodyError::TruncatedData));
614 assert_eq!(
615 decode(&[b'R', b'D', b'O', b'C', 1, 0]),
616 Err(DocBodyError::TruncatedData)
617 );
618 }
619
620 #[test]
621 fn null_values_round_trip() {
622 let fields = [("nothing", Value::Null), ("something", Value::Integer(7))];
623 let got = round_trip(&fields);
624 assert_eq!(got[0].1, Value::Null);
625 assert_eq!(got[1].1, Value::Integer(7));
626 }
627
628 #[test]
629 fn array_value_round_trip() {
630 let fields = [(
631 "tags",
632 Value::Array(vec![Value::text("a"), Value::text("b"), Value::Integer(3)]),
633 )];
634 let got = round_trip(&fields);
635 assert_eq!(
636 got[0].1,
637 Value::Array(vec![Value::text("a"), Value::text("b"), Value::Integer(3)])
638 );
639 }
640
641 #[test]
643 fn offset_table_offsets_are_valid() {
644 let fields = [("k", Value::Boolean(true))];
645 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
646 let mut buf = Vec::new();
647 encode(&refs, &mut buf).expect("encode");
648
649 let (n, table) = parse_header(&buf).expect("header");
650 assert_eq!(n, 1);
651 let (_klen, val_offset) = table[0];
652 let (v, _) = value_codec::decode(&buf[val_offset as usize..]).expect("decode at offset");
654 assert_eq!(v, Value::Boolean(true));
655 }
656
657 fn all_common(_: &str) -> bool {
661 true
662 }
663
664 #[test]
667 fn common_keys_are_interned_as_key_ids() {
668 let fields = [
669 ("id", Value::Integer(1)),
670 ("name", Value::text("Alice")),
671 ("active", Value::Boolean(true)),
672 ];
673 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
674 let mut dict = KeyDictionary::new();
675 let mut buf = Vec::new();
676 encode_with_dictionary(&refs, &mut dict, all_common, &mut buf).expect("encode");
677
678 assert_eq!(dict.len(), 3);
680 assert_eq!(dict.id_of("id"), Some(0));
681 assert_eq!(dict.id_of("name"), Some(1));
682 assert_eq!(dict.id_of("active"), Some(2));
683
684 let (n, table) = parse_dict_header(&buf).expect("header");
686 assert_eq!(n, 3);
687 for (kind, _key_ref, _off) in &table {
688 assert_eq!(*kind, KEY_KIND_DICT);
689 }
690 assert!(!buf.windows(4).any(|w| w == b"name"));
692 }
693
694 #[test]
697 fn new_common_key_appends_to_dictionary() {
698 let mut dict = KeyDictionary::new();
699
700 let doc1 = [("id", Value::Integer(1)), ("name", Value::text("Alice"))];
701 let r1: Vec<(&str, &Value)> = doc1.iter().map(|(k, v)| (*k, v)).collect();
702 let mut b1 = Vec::new();
703 encode_with_dictionary(&r1, &mut dict, all_common, &mut b1).expect("encode 1");
704 assert_eq!(dict.len(), 2);
705
706 let doc2 = [
708 ("id", Value::Integer(2)),
709 ("name", Value::text("Bob")),
710 ("email", Value::Email("bob@example.com".to_string())),
711 ];
712 let r2: Vec<(&str, &Value)> = doc2.iter().map(|(k, v)| (*k, v)).collect();
713 let mut b2 = Vec::new();
714 encode_with_dictionary(&r2, &mut dict, all_common, &mut b2).expect("encode 2");
715
716 assert_eq!(dict.len(), 3);
718 assert_eq!(dict.id_of("id"), Some(0));
719 assert_eq!(dict.id_of("name"), Some(1));
720 assert_eq!(dict.id_of("email"), Some(2));
721
722 let g1 = decode_with_dictionary(&b1, &dict).expect("decode 1");
724 assert_eq!(g1[1], ("name".to_string(), Value::text("Alice")));
725 let g2 = decode_with_dictionary(&b2, &dict).expect("decode 2");
726 assert_eq!(
727 g2[2],
728 (
729 "email".to_string(),
730 Value::Email("bob@example.com".to_string())
731 )
732 );
733 }
734
735 #[test]
737 fn rare_key_stays_inline_and_out_of_dictionary() {
738 let common = |k: &str| k == "id" || k == "name";
740 let fields = [
741 ("id", Value::Integer(7)),
742 ("name", Value::text("Carol")),
743 ("x9f3_one_off_attr", Value::text("rare-value")),
744 ];
745 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
746 let mut dict = KeyDictionary::new();
747 let mut buf = Vec::new();
748 encode_with_dictionary(&refs, &mut dict, common, &mut buf).expect("encode");
749
750 assert_eq!(dict.len(), 2);
752 assert_eq!(dict.id_of("x9f3_one_off_attr"), None);
753
754 let (_n, table) = parse_dict_header(&buf).expect("header");
756 assert_eq!(table[0].0, KEY_KIND_DICT);
757 assert_eq!(table[1].0, KEY_KIND_DICT);
758 assert_eq!(table[2].0, KEY_KIND_INLINE);
759 assert!(buf
760 .windows("x9f3_one_off_attr".len())
761 .any(|w| w == b"x9f3_one_off_attr"));
762
763 let got = decode_with_dictionary(&buf, &dict).expect("decode");
765 assert_eq!(
766 got[2],
767 ("x9f3_one_off_attr".to_string(), Value::text("rare-value"))
768 );
769 }
770
771 #[test]
774 fn mixed_dictionary_and_inline_round_trip() {
775 let common = |k: &str| matches!(k, "id" | "email" | "active");
776 let fields = [
777 ("id", Value::Integer(42)),
778 ("email", Value::Email("a@example.com".to_string())),
779 ("active", Value::Boolean(true)),
780 ("one_off_color", Value::Color([0xDE, 0xAD, 0xBE])),
781 ("rare_geo", Value::GeoPoint(-23_550_520, -46_633_308)),
782 ];
783 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
784 let mut dict = KeyDictionary::new();
785 let mut buf = Vec::new();
786 encode_with_dictionary(&refs, &mut dict, common, &mut buf).expect("encode");
787
788 let mut dict_bytes = Vec::new();
790 dict.encode(&mut dict_bytes);
791 let reloaded = KeyDictionary::decode(&dict_bytes).expect("reload dict");
792
793 let got = decode_with_dictionary(&buf, &reloaded).expect("decode");
794 assert_eq!(got.len(), fields.len());
795 for (i, (k, v)) in fields.iter().enumerate() {
796 assert_eq!(got[i].0, *k, "key mismatch at {i}");
797 assert_eq!(got[i].1, *v, "value mismatch for field {k}");
798 }
799 }
800
801 #[test]
802 fn empty_dictionary_document_round_trips() {
803 let mut dict = KeyDictionary::new();
804 let mut buf = Vec::new();
805 encode_with_dictionary(&[], &mut dict, all_common, &mut buf).expect("encode");
806 let got = decode_with_dictionary(&buf, &dict).expect("decode");
807 assert!(got.is_empty());
808 assert!(dict.is_empty());
809 }
810
811 #[test]
814 fn unknown_key_id_is_rejected() {
815 let fields = [("only_key", Value::Integer(1))];
816 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
817 let mut dict = KeyDictionary::new();
818 let mut buf = Vec::new();
819 encode_with_dictionary(&refs, &mut dict, all_common, &mut buf).expect("encode");
820
821 let empty = KeyDictionary::new();
822 assert_eq!(
823 decode_with_dictionary(&buf, &empty),
824 Err(DocBodyError::UnknownKeyId(0))
825 );
826 }
827
828 #[test]
831 fn v1_and_v2_versions_do_not_alias() {
832 let fields = [("k", Value::Integer(1))];
833 let refs: Vec<(&str, &Value)> = fields.iter().map(|(k, v)| (*k, v)).collect();
834
835 let mut v1 = Vec::new();
836 encode(&refs, &mut v1).expect("v1");
837 assert_eq!(v1[4], VERSION);
838
839 let mut dict = KeyDictionary::new();
840 let mut v2 = Vec::new();
841 encode_with_dictionary(&refs, &mut dict, all_common, &mut v2).expect("v2");
842 assert_eq!(v2[4], VERSION_DICT);
843
844 assert_eq!(
846 decode(&v2),
847 Err(DocBodyError::UnsupportedVersion(VERSION_DICT))
848 );
849 assert_eq!(
850 parse_dict_header(&v1),
851 Err(DocBodyError::UnsupportedVersion(VERSION))
852 );
853 }
854}