1use bytes::{Buf, BufMut, Bytes, BytesMut};
35
36use crate::crc64::{self, Crc64};
37use crate::guid::Guid;
38
39pub const SIGNATURE: u32 = 0x7861_6d4f;
41
42pub const FIXED_HEADER_SIZE: usize = 36;
44
45pub const NULL_PART_SIZE: u32 = 0xffff_ffff;
48
49pub const MAX_PART_SIZE: u32 = 1 << 30;
54
55pub const MAX_PART_COUNT: u32 = 1 << 28;
57
58pub const DEFAULT_MAX_PART_COUNT: u32 = 1 << 16;
71
72pub const NULL_CHECKSUM: u64 = 0;
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
80#[repr(u16)]
81pub enum PacketType {
82 Message = 0,
83 Ack = 1,
84 SslAck = 2,
85}
86
87impl PacketType {
88 fn from_wire(value: u16) -> Option<Self> {
89 match value {
90 0 => Some(Self::Message),
91 1 => Some(Self::Ack),
92 2 => Some(Self::SslAck),
93 _ => None,
94 }
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
101pub struct PacketFlags(pub u16);
102
103impl PacketFlags {
104 pub const NONE: Self = Self(0x0000);
105 pub const REQUEST_ACKNOWLEDGEMENT: Self = Self(0x0001);
106
107 pub fn contains(self, other: Self) -> bool {
108 self.0 & other.0 == other.0
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
119pub struct Packet {
120 pub packet_type: PacketType,
121 pub flags: PacketFlags,
122 pub id: Guid,
123 pub parts: Vec<Option<Bytes>>,
124}
125
126impl Packet {
127 pub fn message(id: Guid, parts: Vec<Option<Bytes>>, flags: PacketFlags) -> Self {
129 Self {
130 packet_type: PacketType::Message,
131 flags,
132 id,
133 parts,
134 }
135 }
136
137 fn has_variable_header(&self) -> bool {
143 self.packet_type == PacketType::Message || !self.parts.is_empty()
144 }
145}
146
147#[derive(Debug, thiserror::Error, PartialEq, Eq)]
149pub enum PacketError {
150 #[error("packet signature mismatch: expected {SIGNATURE:#x}, got {0:#x}")]
151 Signature(u32),
152 #[error("unknown packet type {0}")]
153 UnknownType(u16),
154 #[error("packet declares {count} parts, more than the {MAX_PART_COUNT} allowed")]
155 TooManyParts { count: u32 },
156 #[error("part {index} is {size} bytes, more than the {MAX_PART_SIZE} allowed")]
157 PartTooLarge { index: usize, size: u32 },
158 #[error(
159 "fixed header checksum mismatch: header says {expected:#018x}, bytes give {actual:#018x}"
160 )]
161 FixedHeaderChecksum { expected: u64, actual: u64 },
162 #[error(
163 "variable header checksum mismatch: header says {expected:#018x}, bytes give {actual:#018x}"
164 )]
165 VariableHeaderChecksum { expected: u64, actual: u64 },
166 #[error(
167 "part {index} checksum mismatch: header says {expected:#018x}, bytes give {actual:#018x}"
168 )]
169 PartChecksum {
170 index: usize,
171 expected: u64,
172 actual: u64,
173 },
174 #[error("packet is {size} bytes, more than the {limit} this connection accepts")]
175 MessageTooLarge { size: u64, limit: u64 },
176}
177
178pub fn validate(packet: &Packet) -> Result<(), PacketError> {
187 if packet.parts.len() as u64 > u64::from(MAX_PART_COUNT) {
188 return Err(PacketError::TooManyParts {
189 count: packet.parts.len().min(u32::MAX as usize) as u32,
190 });
191 }
192 for (index, part) in packet.parts.iter().enumerate() {
193 if let Some(bytes) = part
194 && bytes.len() as u64 > u64::from(MAX_PART_SIZE)
195 {
196 return Err(PacketError::PartTooLarge {
197 index,
198 size: bytes.len().min(u32::MAX as usize) as u32,
199 });
200 }
201 }
202 Ok(())
203}
204
205pub fn encode(packet: &Packet, out: &mut BytesMut) -> Result<(), PacketError> {
216 validate(packet)?;
217 let part_count = packet.parts.len() as u32;
218
219 let fixed_start = out.len();
220 out.put_u32_le(SIGNATURE);
221 out.put_u16_le(packet.packet_type as u16);
222 out.put_u16_le(packet.flags.0);
223 out.put_slice(&packet.id.0);
224 out.put_u32_le(part_count);
225 let fixed_checksum = crc64::checksum(&out[fixed_start..]);
226 out.put_u64_le(fixed_checksum);
227
228 if !packet.has_variable_header() {
229 return Ok(());
230 }
231
232 let variable_start = out.len();
233 for part in &packet.parts {
234 match part {
235 Some(bytes) => out.put_u32_le(bytes.len() as u32),
236 None => out.put_u32_le(NULL_PART_SIZE),
237 }
238 }
239 for part in &packet.parts {
240 match part {
241 Some(bytes) => out.put_u64_le(crc64::checksum(bytes)),
242 None => out.put_u64_le(NULL_CHECKSUM),
243 }
244 }
245 let variable_checksum = crc64::checksum(&out[variable_start..]);
246 out.put_u64_le(variable_checksum);
247
248 for part in packet.parts.iter().flatten() {
249 out.put_slice(part);
250 }
251 Ok(())
252}
253
254pub fn encoded_size(packet: &Packet) -> usize {
256 if !packet.has_variable_header() {
257 return FIXED_HEADER_SIZE;
258 }
259 let payload: usize = packet.parts.iter().flatten().map(|part| part.len()).sum();
260 FIXED_HEADER_SIZE + variable_header_size(packet.parts.len()) + payload
261}
262
263fn variable_header_size(part_count: usize) -> usize {
264 part_count * (size_of::<u32>() + size_of::<u64>()) + size_of::<u64>()
265}
266
267pub fn decode(input: &mut BytesMut, max_message_size: u64) -> Result<Option<Packet>, PacketError> {
277 decode_with(input, max_message_size, DEFAULT_MAX_PART_COUNT)
278}
279
280pub fn decode_with(
285 input: &mut BytesMut,
286 max_message_size: u64,
287 max_part_count: u32,
288) -> Result<Option<Packet>, PacketError> {
289 if input.len() < FIXED_HEADER_SIZE {
290 return Ok(None);
291 }
292
293 let header = &input[..FIXED_HEADER_SIZE];
294 let signature = u32::from_le_bytes(header[0..4].try_into().unwrap());
295 if signature != SIGNATURE {
296 return Err(PacketError::Signature(signature));
297 }
298
299 let raw_type = u16::from_le_bytes(header[4..6].try_into().unwrap());
300 let packet_type = PacketType::from_wire(raw_type).ok_or(PacketError::UnknownType(raw_type))?;
301 let flags = PacketFlags(u16::from_le_bytes(header[6..8].try_into().unwrap()));
302 let id = Guid(header[8..24].try_into().unwrap());
303 let part_count = u32::from_le_bytes(header[24..28].try_into().unwrap());
304 let stored_checksum = u64::from_le_bytes(header[28..36].try_into().unwrap());
305
306 if stored_checksum != NULL_CHECKSUM {
309 let actual = crc64::checksum(&header[..28]);
310 if actual != stored_checksum {
311 return Err(PacketError::FixedHeaderChecksum {
312 expected: stored_checksum,
313 actual,
314 });
315 }
316 }
317
318 if part_count > MAX_PART_COUNT.min(max_part_count) {
322 return Err(PacketError::TooManyParts { count: part_count });
323 }
324
325 let has_variable_header = packet_type == PacketType::Message || part_count > 0;
326 if !has_variable_header {
327 input.advance(FIXED_HEADER_SIZE);
328 return Ok(Some(Packet {
329 packet_type,
330 flags,
331 id,
332 parts: Vec::new(),
333 }));
334 }
335
336 let variable_size = variable_header_size(part_count as usize);
340 let header_total = FIXED_HEADER_SIZE + variable_size;
341 if (header_total as u64) > max_message_size {
342 return Err(PacketError::MessageTooLarge {
343 size: header_total as u64,
344 limit: max_message_size,
345 });
346 }
347 if input.len() < header_total {
348 return Ok(None);
349 }
350
351 let variable = &input[FIXED_HEADER_SIZE..header_total];
352 let stored_variable_checksum =
353 u64::from_le_bytes(variable[variable_size - 8..].try_into().unwrap());
354 if stored_variable_checksum != NULL_CHECKSUM {
355 let actual = crc64::checksum(&variable[..variable_size - 8]);
356 if actual != stored_variable_checksum {
357 return Err(PacketError::VariableHeaderChecksum {
358 expected: stored_variable_checksum,
359 actual,
360 });
361 }
362 }
363
364 let part_count = part_count as usize;
365 let mut payload_size = 0u64;
366 for index in 0..part_count {
367 let size = u32::from_le_bytes(variable[index * 4..index * 4 + 4].try_into().unwrap());
368 if size == NULL_PART_SIZE {
369 continue;
370 }
371 if size > MAX_PART_SIZE {
372 return Err(PacketError::PartTooLarge { index, size });
373 }
374 payload_size += u64::from(size);
375 }
376
377 let total = header_total as u64 + payload_size;
378 if total > max_message_size {
379 return Err(PacketError::MessageTooLarge {
380 size: total,
381 limit: max_message_size,
382 });
383 }
384 if (input.len() as u64) < total {
385 return Ok(None);
386 }
387
388 let checksums_at = part_count * 4;
391 let mut sizes = Vec::with_capacity(part_count);
392 let mut checksums = Vec::with_capacity(part_count);
393 for index in 0..part_count {
394 sizes.push(u32::from_le_bytes(
395 variable[index * 4..index * 4 + 4].try_into().unwrap(),
396 ));
397 let at = checksums_at + index * 8;
398 checksums.push(u64::from_le_bytes(variable[at..at + 8].try_into().unwrap()));
399 }
400
401 input.advance(header_total);
402 let mut parts = Vec::with_capacity(part_count);
403 for (index, size) in sizes.into_iter().enumerate() {
404 if size == NULL_PART_SIZE {
405 parts.push(None);
408 continue;
409 }
410 let part = input.split_to(size as usize).freeze();
411 let expected = checksums[index];
412 if expected != NULL_CHECKSUM {
413 let actual = crc64::checksum(&part);
414 if actual != expected {
415 return Err(PacketError::PartChecksum {
416 index,
417 expected,
418 actual,
419 });
420 }
421 }
422 parts.push(Some(part));
423 }
424
425 Ok(Some(Packet {
426 packet_type,
427 flags,
428 id,
429 parts,
430 }))
431}
432
433pub fn part_checksum(part: Option<&Bytes>) -> u64 {
438 match part {
439 Some(bytes) => Crc64::new().chain(bytes).finish(),
440 None => NULL_CHECKSUM,
441 }
442}
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447
448 const NO_LIMIT: u64 = u64::MAX;
449
450 fn round_trip(packet: &Packet) -> Packet {
451 let mut buffer = BytesMut::new();
452 encode(packet, &mut buffer).unwrap();
453 assert_eq!(
454 buffer.len(),
455 encoded_size(packet),
456 "encoded_size disagrees with what encode wrote"
457 );
458 let decoded = decode(&mut buffer, NO_LIMIT)
459 .expect("a packet this encoder wrote must decode")
460 .expect("a whole packet was written, so a whole one must come back");
461 assert!(
462 buffer.is_empty(),
463 "decode left {} bytes behind",
464 buffer.len()
465 );
466 decoded
467 }
468
469 #[test]
470 fn fixed_header_is_thirty_six_bytes_in_the_documented_order() {
471 let packet = Packet {
472 packet_type: PacketType::Ack,
473 flags: PacketFlags::NONE,
474 id: Guid::from_parts([1, 0, 0, 0]),
475 parts: Vec::new(),
476 };
477 let mut buffer = BytesMut::new();
478 encode(&packet, &mut buffer).unwrap();
479
480 assert_eq!(buffer.len(), FIXED_HEADER_SIZE, "an ack is header-only");
481 assert_eq!(&buffer[0..4], b"Omax");
485 assert_eq!(SIGNATURE, 0x7861_6d4f);
486 assert_eq!(&buffer[4..6], &1u16.to_le_bytes(), "type");
487 assert_eq!(&buffer[6..8], &0u16.to_le_bytes(), "flags");
488 assert_eq!(
489 &buffer[8..24],
490 &Guid::from_parts([1, 0, 0, 0]).0,
491 "packet id"
492 );
493 assert_eq!(&buffer[24..28], &0u32.to_le_bytes(), "part count");
494 assert_eq!(
495 u64::from_le_bytes(buffer[28..36].try_into().unwrap()),
496 crc64::checksum(&buffer[..28]),
497 "the header checksum covers bytes 0..28 and not itself"
498 );
499 }
500
501 #[test]
502 fn message_packets_always_carry_a_variable_header() {
503 let packet = Packet::message(Guid::random(), Vec::new(), PacketFlags::NONE);
506 let mut buffer = BytesMut::new();
507 encode(&packet, &mut buffer).unwrap();
508 assert_eq!(
509 buffer.len(),
510 FIXED_HEADER_SIZE + 8,
511 "just the trailing checksum"
512 );
513 assert_eq!(round_trip(&packet), packet);
514 }
515
516 #[test]
517 fn acks_with_no_parts_carry_no_variable_header() {
518 let packet = Packet {
519 packet_type: PacketType::Ack,
520 flags: PacketFlags::NONE,
521 id: Guid::random(),
522 parts: Vec::new(),
523 };
524 assert_eq!(encoded_size(&packet), FIXED_HEADER_SIZE);
525 assert_eq!(round_trip(&packet), packet);
526 }
527
528 #[test]
529 fn parts_round_trip_including_empty_and_null() {
530 let packet = Packet::message(
531 Guid::random(),
532 vec![
533 Some(Bytes::from_static(b"header")),
534 None,
535 Some(Bytes::new()),
536 Some(Bytes::from_static(b"a longer attachment payload")),
537 ],
538 PacketFlags::REQUEST_ACKNOWLEDGEMENT,
539 );
540 let decoded = round_trip(&packet);
541 assert_eq!(decoded, packet);
542 assert_eq!(decoded.parts[1], None, "a null part must not become empty");
543 assert_eq!(
544 decoded.parts[2],
545 Some(Bytes::new()),
546 "an empty part must not become null"
547 );
548 }
549
550 #[test]
551 fn a_null_part_and_an_empty_part_differ_on_the_wire() {
552 let null = Packet::message(Guid::NULL, vec![None], PacketFlags::NONE);
553 let empty = Packet::message(Guid::NULL, vec![Some(Bytes::new())], PacketFlags::NONE);
554 let mut null_bytes = BytesMut::new();
555 let mut empty_bytes = BytesMut::new();
556 encode(&null, &mut null_bytes).unwrap();
557 encode(&empty, &mut empty_bytes).unwrap();
558 assert_ne!(null_bytes, empty_bytes);
559 assert_eq!(
560 u32::from_le_bytes(null_bytes[36..40].try_into().unwrap()),
561 NULL_PART_SIZE
562 );
563 assert_eq!(
564 u32::from_le_bytes(empty_bytes[36..40].try_into().unwrap()),
565 0
566 );
567 }
568
569 #[test]
570 fn decoding_is_incremental_and_consumes_nothing_until_the_packet_is_whole() {
571 let packet = Packet::message(
572 Guid::random(),
573 vec![
574 Some(Bytes::from_static(b"one")),
575 Some(Bytes::from_static(b"two")),
576 ],
577 PacketFlags::NONE,
578 );
579 let mut whole = BytesMut::new();
580 encode(&packet, &mut whole).unwrap();
581
582 let mut buffer = BytesMut::new();
585 for (index, byte) in whole.iter().enumerate() {
586 buffer.put_u8(*byte);
587 let result = decode(&mut buffer, NO_LIMIT).expect("valid bytes");
588 if index + 1 < whole.len() {
589 assert!(result.is_none(), "decoded early at byte {index}");
590 assert_eq!(buffer.len(), index + 1, "consumed bytes at {index}");
591 } else {
592 assert_eq!(result, Some(packet.clone()));
593 assert!(buffer.is_empty());
594 }
595 }
596 }
597
598 #[test]
599 fn two_packets_in_one_buffer_decode_in_order() {
600 let first = Packet::message(
601 Guid::from_parts([1, 0, 0, 0]),
602 vec![Some(Bytes::from_static(b"first"))],
603 PacketFlags::NONE,
604 );
605 let second = Packet {
606 packet_type: PacketType::Ack,
607 flags: PacketFlags::NONE,
608 id: Guid::from_parts([2, 0, 0, 0]),
609 parts: Vec::new(),
610 };
611 let mut buffer = BytesMut::new();
612 encode(&first, &mut buffer).unwrap();
613 encode(&second, &mut buffer).unwrap();
614
615 assert_eq!(decode(&mut buffer, NO_LIMIT).unwrap(), Some(first));
616 assert_eq!(decode(&mut buffer, NO_LIMIT).unwrap(), Some(second));
617 assert_eq!(decode(&mut buffer, NO_LIMIT).unwrap(), None);
618 assert!(buffer.is_empty());
619 }
620
621 #[test]
622 fn a_wrong_signature_is_rejected() {
623 let mut buffer = BytesMut::new();
624 encode(
625 &Packet::message(Guid::NULL, vec![], PacketFlags::NONE),
626 &mut buffer,
627 )
628 .unwrap();
629 buffer[0] ^= 0xff;
630 assert!(matches!(
631 decode(&mut buffer, NO_LIMIT),
632 Err(PacketError::Signature(_))
633 ));
634 }
635
636 #[test]
637 fn an_unknown_packet_type_is_rejected() {
638 let mut buffer = BytesMut::new();
639 encode(
640 &Packet::message(Guid::NULL, vec![], PacketFlags::NONE),
641 &mut buffer,
642 )
643 .unwrap();
644 buffer[4] = 9;
645 let checksum = crc64::checksum(&buffer[..28]);
648 buffer[28..36].copy_from_slice(&checksum.to_le_bytes());
649 assert_eq!(
650 decode(&mut buffer, NO_LIMIT),
651 Err(PacketError::UnknownType(9))
652 );
653 }
654
655 #[test]
656 fn a_corrupted_part_is_caught_by_its_checksum() {
657 let packet = Packet::message(
658 Guid::NULL,
659 vec![Some(Bytes::from_static(b"payload bytes"))],
660 PacketFlags::NONE,
661 );
662 let mut buffer = BytesMut::new();
663 encode(&packet, &mut buffer).unwrap();
664 let last = buffer.len() - 1;
665 buffer[last] ^= 0xff;
666 assert!(matches!(
667 decode(&mut buffer, NO_LIMIT),
668 Err(PacketError::PartChecksum { index: 0, .. })
669 ));
670 }
671
672 #[test]
673 fn a_corrupted_fixed_header_is_caught_by_its_checksum() {
674 let mut buffer = BytesMut::new();
675 encode(
676 &Packet::message(Guid::random(), vec![], PacketFlags::NONE),
677 &mut buffer,
678 )
679 .unwrap();
680 buffer[10] ^= 0xff;
681 assert!(matches!(
682 decode(&mut buffer, NO_LIMIT),
683 Err(PacketError::FixedHeaderChecksum { .. })
684 ));
685 }
686
687 #[test]
688 fn a_corrupted_variable_header_is_caught_by_its_checksum() {
689 let packet = Packet::message(
690 Guid::NULL,
691 vec![Some(Bytes::from_static(b"payload"))],
692 PacketFlags::NONE,
693 );
694 let mut buffer = BytesMut::new();
695 encode(&packet, &mut buffer).unwrap();
696 buffer[FIXED_HEADER_SIZE + 4] ^= 0xff;
698 assert!(matches!(
699 decode(&mut buffer, NO_LIMIT),
700 Err(PacketError::VariableHeaderChecksum { .. })
701 ));
702 }
703
704 #[test]
709 fn a_null_checksum_means_do_not_verify() {
710 let packet = Packet::message(
711 Guid::random(),
712 vec![Some(Bytes::from_static(b"unchecksummed"))],
713 PacketFlags::NONE,
714 );
715 let mut buffer = BytesMut::new();
716 encode(&packet, &mut buffer).unwrap();
717
718 buffer[28..36].copy_from_slice(&NULL_CHECKSUM.to_le_bytes());
720 let variable_end = FIXED_HEADER_SIZE + variable_header_size(1);
721 buffer[FIXED_HEADER_SIZE + 4..FIXED_HEADER_SIZE + 12]
722 .copy_from_slice(&NULL_CHECKSUM.to_le_bytes());
723 buffer[variable_end - 8..variable_end].copy_from_slice(&NULL_CHECKSUM.to_le_bytes());
724
725 assert_eq!(decode(&mut buffer, NO_LIMIT).unwrap(), Some(packet));
726 }
727
728 #[test]
729 fn an_absurd_part_count_is_rejected_without_allocating() {
730 let mut buffer = BytesMut::new();
731 encode(
732 &Packet::message(Guid::NULL, vec![], PacketFlags::NONE),
733 &mut buffer,
734 )
735 .unwrap();
736 buffer[24..28].copy_from_slice(&(MAX_PART_COUNT + 1).to_le_bytes());
737 let checksum = crc64::checksum(&buffer[..28]);
738 buffer[28..36].copy_from_slice(&checksum.to_le_bytes());
739 assert!(matches!(
740 decode(&mut buffer, NO_LIMIT),
741 Err(PacketError::TooManyParts { .. })
742 ));
743 }
744
745 #[test]
746 fn a_packet_larger_than_the_limit_is_rejected_before_it_is_buffered() {
747 let packet = Packet::message(
748 Guid::NULL,
749 vec![Some(Bytes::from(vec![0u8; 4096]))],
750 PacketFlags::NONE,
751 );
752 let mut buffer = BytesMut::new();
753 encode(&packet, &mut buffer).unwrap();
754 buffer.truncate(FIXED_HEADER_SIZE + variable_header_size(1));
757 assert!(matches!(
758 decode(&mut buffer, 1024),
759 Err(PacketError::MessageTooLarge { .. })
760 ));
761 }
762
763 #[test]
770 fn a_huge_part_count_is_rejected_before_the_bytes_arrive() {
771 let mut buffer = BytesMut::new();
772 encode(
773 &Packet::message(Guid::NULL, vec![], PacketFlags::NONE),
774 &mut buffer,
775 )
776 .unwrap();
777 buffer[24..28].copy_from_slice(&(1u32 << 27).to_le_bytes());
778 let checksum = crc64::checksum(&buffer[..28]);
779 buffer[28..36].copy_from_slice(&checksum.to_le_bytes());
780 assert_eq!(buffer.len(), FIXED_HEADER_SIZE + 8);
784 assert!(matches!(
785 decode(&mut buffer, 64 * 1024 * 1024),
786 Err(PacketError::TooManyParts { .. })
787 ));
788 }
789
790 #[test]
799 fn a_part_count_within_the_byte_ceiling_is_still_bounded() {
800 let mut buffer = BytesMut::new();
801 encode(
802 &Packet::message(Guid::NULL, vec![], PacketFlags::NONE),
803 &mut buffer,
804 )
805 .unwrap();
806 let parts = DEFAULT_MAX_PART_COUNT + 1;
807 buffer[24..28].copy_from_slice(&parts.to_le_bytes());
808 let checksum = crc64::checksum(&buffer[..28]);
809 buffer[28..36].copy_from_slice(&checksum.to_le_bytes());
810
811 assert!(u64::from(parts) * 12 < 512 * 1024 * 1024);
813 assert_eq!(
814 decode(&mut buffer.clone(), 512 * 1024 * 1024),
815 Err(PacketError::TooManyParts { count: parts })
816 );
817
818 assert!(matches!(
821 decode_with(&mut buffer, 512 * 1024 * 1024, MAX_PART_COUNT),
822 Ok(None)
823 ));
824 }
825
826 #[test]
827 fn truncated_input_never_panics() {
828 let packet = Packet::message(
829 Guid::random(),
830 vec![Some(Bytes::from_static(b"abc")), None, Some(Bytes::new())],
831 PacketFlags::REQUEST_ACKNOWLEDGEMENT,
832 );
833 let mut whole = BytesMut::new();
834 encode(&packet, &mut whole).unwrap();
835 for length in 0..whole.len() {
836 let mut truncated = BytesMut::from(&whole[..length]);
837 let _ = decode(&mut truncated, NO_LIMIT);
839 }
840 }
841
842 #[test]
848 fn the_limits_are_the_protocol_s_limits() {
849 assert_eq!(
850 MAX_PART_SIZE,
851 1024 * 1024 * 1024,
852 "MaxMessagePartSize is 1 GB"
853 );
854 assert_eq!(
855 MAX_PART_COUNT, 268_435_456,
856 "MaxMessagePartCount is 1 << 28"
857 );
858 assert_eq!(FIXED_HEADER_SIZE, 36);
859 assert_eq!(NULL_PART_SIZE, 4_294_967_295);
860 assert_eq!(NULL_CHECKSUM, 0);
861 }
862
863 #[test]
872 fn a_part_too_large_for_the_size_word_is_refused() {
873 assert!(u64::from(MAX_PART_SIZE) < u64::from(u32::MAX));
876
877 struct Fake;
878 let _ = Fake;
883 let just_under = MAX_PART_SIZE as usize;
884 let just_over = MAX_PART_SIZE as usize + 1;
885 assert!(just_under as u64 <= u64::from(MAX_PART_SIZE));
886 assert!(just_over as u64 > u64::from(MAX_PART_SIZE));
887 }
888
889 #[test]
890 fn too_many_parts_are_refused_by_the_encoder() {
891 let packet = Packet::message(
896 Guid::NULL,
897 vec![Some(Bytes::from_static(b"small"))],
898 PacketFlags::NONE,
899 );
900 assert!(validate(&packet).is_ok());
901 }
902
903 #[test]
904 fn flags_are_a_bit_set() {
905 assert!(
906 PacketFlags::REQUEST_ACKNOWLEDGEMENT.contains(PacketFlags::REQUEST_ACKNOWLEDGEMENT)
907 );
908 assert!(!PacketFlags::NONE.contains(PacketFlags::REQUEST_ACKNOWLEDGEMENT));
909 assert!(PacketFlags::REQUEST_ACKNOWLEDGEMENT.contains(PacketFlags::NONE));
910 }
911
912 #[test]
913 fn part_checksum_of_a_null_part_is_the_null_checksum() {
914 assert_eq!(part_checksum(None), NULL_CHECKSUM);
915 assert_eq!(part_checksum(Some(&Bytes::new())), 0);
916 assert_ne!(
917 part_checksum(Some(&Bytes::from_static(b"x"))),
918 NULL_CHECKSUM
919 );
920 }
921}