1use super::error::{BinaryError, BinaryResult};
48use std::fmt;
49use std::io::{self, Read, Write};
50use std::str::FromStr;
51
52pub const BINARY_VERSION_1: u8 = 0x10;
55
56const FLAG_EXTERNAL_REFERENCES: u8 = 0b0001;
57const FLAG_EXPLICIT_LAYOUT: u8 = 0b0010;
58const WIDTH_SHIFT: u8 = 2;
59const WIDTH_BITS: u8 = 0b1100;
60
61const SHAPE_WIDTH_BITS: u64 = 0b0011;
62const SHAPE_HAS_GAP: u64 = 0b0100;
63const SHAPE_VARIABLE_ARITY: u64 = 0b1000;
64const SHAPE_MIN_ARITY_SHIFT: u32 = 4;
65
66pub const NULL: u64 = 0;
68pub const ONE: u64 = 1;
70pub const NUMBER: u64 = 2;
72pub const STRING: u64 = 3;
74pub const LIST: u64 = 4;
76pub const IDENTIFIED: u64 = 5;
78pub const FIRST_LINK_ADDRESS: u64 = 6;
80
81const COMPACT_GAP: u64 = FIRST_LINK_ADDRESS - 1;
83
84pub const WIDTHS: [u8; 4] = [1, 2, 4, 8];
86
87#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
89pub enum Reference {
90 Internal(u64),
92 External(u64),
94}
95
96impl Reference {
97 pub const NULL: Reference = Reference::Internal(NULL);
99}
100
101#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
104pub struct ArityRange {
105 pub min: u64,
107 pub max: Option<u64>,
109}
110
111impl ArityRange {
112 pub const DOUBLETS: ArityRange = ArityRange::exactly(2);
114
115 pub const fn exactly(arity: u64) -> Self {
117 Self {
118 min: arity,
119 max: Some(arity),
120 }
121 }
122
123 pub const fn at_least(min: u64) -> Self {
125 Self { min, max: None }
126 }
127
128 pub const fn between(min: u64, max: u64) -> Self {
130 Self {
131 min,
132 max: Some(max),
133 }
134 }
135
136 pub fn contains(&self, length: u64) -> bool {
138 length >= self.min && self.max.is_none_or(|max| length <= max)
139 }
140
141 pub fn is_fixed(&self) -> bool {
144 self.max == Some(self.min)
145 }
146
147 pub(crate) fn validate(&self) -> Result<(), String> {
148 if self.min == 0 {
149 return Err("arity must be at least 1".into());
150 }
151 if self.min > u64::MAX >> SHAPE_MIN_ARITY_SHIFT {
152 return Err(format!("arity {} is too large", self.min));
153 }
154 if self.max.is_some_and(|max| max < self.min) {
155 return Err(format!("arity range {self} is empty"));
156 }
157 Ok(())
158 }
159
160 fn extra(&self) -> u64 {
162 self.max.map_or(0, |max| max - self.min)
163 }
164
165 fn from_shape(min: u64, extra: Option<u64>) -> BinaryResult<Self> {
166 let range = match extra {
167 None => Self::exactly(min),
168 Some(0) => Self::at_least(min),
169 Some(extra) => Self::between(
170 min,
171 min.checked_add(extra)
172 .ok_or_else(|| BinaryError::malformed("arity range overflows 64 bits"))?,
173 ),
174 };
175 range.validate().map_err(BinaryError::malformed)?;
176 Ok(range)
177 }
178}
179
180impl Default for ArityRange {
181 fn default() -> Self {
182 Self::DOUBLETS
183 }
184}
185
186impl fmt::Display for ArityRange {
187 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
188 match self.max {
189 Some(max) if max == self.min => write!(formatter, "{max}"),
190 Some(max) => write!(formatter, "{}..{max}", self.min),
191 None => write!(formatter, "{}..", self.min),
192 }
193 }
194}
195
196impl FromStr for ArityRange {
197 type Err = String;
198
199 fn from_str(text: &str) -> Result<Self, Self::Err> {
201 let number = |part: &str| {
202 part.parse::<u64>()
203 .map_err(|_| format!("invalid arity '{text}': expected n, min..max or min.."))
204 };
205 let range = match text.split_once("..") {
206 None => Self::exactly(number(text)?),
207 Some((min, "")) => Self::at_least(number(min)?),
208 Some((min, max)) => Self::between(number(min)?, number(max)?),
209 };
210 range.validate()?;
211 Ok(range)
212 }
213}
214
215#[derive(Clone, Copy, Debug, PartialEq, Eq)]
217pub struct DecodeLimits {
218 pub max_links: u64,
220 pub max_references: u64,
222 pub max_nodes: usize,
224 pub max_string_bytes: usize,
226 pub max_depth: usize,
228}
229
230impl Default for DecodeLimits {
231 fn default() -> Self {
232 Self {
233 max_links: 1 << 22,
234 max_references: 1 << 24,
235 max_nodes: 1 << 22,
236 max_string_bytes: 64 << 20,
237 max_depth: 64,
238 }
239 }
240}
241
242impl DecodeLimits {
243 pub fn unlimited() -> Self {
246 Self {
247 max_links: u64::MAX,
248 max_references: u64::MAX,
249 max_nodes: usize::MAX,
250 max_string_bytes: usize::MAX,
251 max_depth: usize::MAX,
252 }
253 }
254}
255
256#[derive(Clone, Debug, PartialEq, Eq)]
259pub struct Section {
260 pub gap: u64,
262 pub arity: ArityRange,
264 pub width: u8,
266 pub links: Vec<Vec<Reference>>,
268}
269
270#[derive(Clone, Debug, Default, PartialEq, Eq)]
272pub struct LinksPacket {
273 pub external_references: bool,
275 pub sections: Vec<Section>,
277}
278
279pub fn internal_capacity(width: u8, external_references: bool) -> u64 {
281 let bits = u32::from(width) * 8 - u32::from(external_references);
282 if bits >= 64 {
283 u64::MAX
284 } else {
285 (1u64 << bits) - 1
286 }
287}
288
289pub fn external_capacity(width: u8) -> u64 {
291 (1u64 << (u32::from(width) * 8 - 1)) - 1
292}
293
294pub fn address_tier(address: u64, external_references: bool) -> BinaryResult<u8> {
296 WIDTHS
297 .into_iter()
298 .find(|&width| internal_capacity(width, external_references) >= address)
299 .ok_or_else(|| {
300 BinaryError::Unencodable(format!("address {address} exceeds the internal range"))
301 })
302}
303
304fn width_mask(width: u8) -> u64 {
305 internal_capacity(width, false)
306}
307
308pub fn encode_external(value: u64, width: u8) -> u64 {
310 if value == 0 {
311 1u64 << (u32::from(width) * 8 - 1)
312 } else {
313 value.wrapping_neg() & width_mask(width)
314 }
315}
316
317pub fn decode_external(raw: u64, width: u8) -> Option<u64> {
319 let external_zero = 1u64 << (u32::from(width) * 8 - 1);
320 if raw == external_zero {
321 Some(0)
322 } else if raw > external_zero {
323 Some(raw.wrapping_neg() & width_mask(width))
324 } else {
325 None
326 }
327}
328
329fn width_code(width: u8) -> BinaryResult<u8> {
330 WIDTHS
331 .iter()
332 .position(|&candidate| candidate == width)
333 .map(|code| code as u8)
334 .ok_or_else(|| BinaryError::Unencodable(format!("invalid width {width}")))
335}
336
337fn width_from_code(code: u64) -> u8 {
339 WIDTHS[(code & 0b11) as usize]
340}
341
342pub fn reference_width(reference: Reference, external_references: bool) -> BinaryResult<u8> {
344 match reference {
345 Reference::Internal(address) => address_tier(address, external_references),
346 Reference::External(value) => {
347 if !external_references {
348 return Err(BinaryError::Unencodable(
349 "external reference in a packet without external references".into(),
350 ));
351 }
352 WIDTHS
353 .into_iter()
354 .find(|&width| external_capacity(width) >= value)
355 .ok_or_else(|| {
356 BinaryError::Unencodable(format!("external value {value} exceeds 63 bits"))
357 })
358 }
359 }
360}
361
362impl Section {
363 fn write_header(&self, out: &mut Vec<u8>) -> BinaryResult<()> {
364 let mut shape =
365 u64::from(width_code(self.width)?) | (self.arity.min << SHAPE_MIN_ARITY_SHIFT);
366 if self.gap != 0 {
367 shape |= SHAPE_HAS_GAP;
368 }
369 if !self.arity.is_fixed() {
370 shape |= SHAPE_VARIABLE_ARITY;
371 }
372 write_leb128(out, shape);
373 if self.gap != 0 {
374 write_leb128(out, self.gap);
375 }
376 if !self.arity.is_fixed() {
377 write_leb128(out, self.arity.extra());
378 }
379 write_leb128(out, self.links.len() as u64);
380 Ok(())
381 }
382
383 fn read_header(reader: &mut dyn Read) -> BinaryResult<(Self, u64)> {
386 let shape = read_leb128(reader)?;
387 let width = width_from_code(shape & SHAPE_WIDTH_BITS);
388 let gap = if shape & SHAPE_HAS_GAP != 0 {
389 read_leb128(reader)?
390 } else {
391 0
392 };
393 let extra = if shape & SHAPE_VARIABLE_ARITY != 0 {
394 Some(read_leb128(reader)?)
395 } else {
396 None
397 };
398 let arity = ArityRange::from_shape(shape >> SHAPE_MIN_ARITY_SHIFT, extra)?;
399 let count = read_leb128(reader)?;
400 let section = Section {
401 gap,
402 arity,
403 width,
404 links: Vec::new(),
405 };
406 Ok((section, count))
407 }
408
409 fn validate(&self) -> BinaryResult<()> {
410 width_code(self.width)?;
411 self.arity.validate().map_err(BinaryError::Unencodable)?;
412 for link in &self.links {
413 if !self.arity.contains(link.len() as u64) {
414 return Err(BinaryError::Unencodable(format!(
415 "a link of {} references in a section of arity {}",
416 link.len(),
417 self.arity
418 )));
419 }
420 }
421 Ok(())
422 }
423}
424
425impl LinksPacket {
426 pub fn new(external_references: bool) -> Self {
428 Self {
429 external_references,
430 sections: Vec::new(),
431 }
432 }
433
434 pub fn pack(
443 external_references: bool,
444 links: &[(u64, Vec<Reference>)],
445 packed_widths: bool,
446 ) -> BinaryResult<Self> {
447 let planner = SectionPlanner::new(external_references, links)?;
448 let uniform_layout = planner.plan(false);
449 let uniform = Self::lay_out(external_references, links, &uniform_layout);
450 if !packed_widths {
451 return Ok(uniform);
452 }
453 let packed_layout = planner.plan(true);
454 if packed_layout == uniform_layout {
455 return Ok(uniform);
456 }
457 let packed = Self::lay_out(external_references, links, &packed_layout);
458 Ok(if packed.to_bytes()?.len() < uniform.to_bytes()?.len() {
459 packed
460 } else {
461 uniform
462 })
463 }
464
465 fn lay_out(
467 external_references: bool,
468 links: &[(u64, Vec<Reference>)],
469 layout: &[(usize, u8)],
470 ) -> Self {
471 let mut sections = Vec::with_capacity(layout.len());
472 let mut next_address = 1u64;
473 let mut remaining = links;
474 for &(count, width) in layout {
475 let (members, rest) = remaining.split_at(count);
476 remaining = rest;
477 let start = members[0].0;
478 let (shortest, longest) = members
479 .iter()
480 .map(|(_, link)| link.len() as u64)
481 .fold((u64::MAX, 0), |(shortest, longest), length| {
482 (shortest.min(length), longest.max(length))
483 });
484 sections.push(Section {
485 gap: start - next_address,
486 arity: ArityRange::between(shortest, longest),
487 width,
488 links: members.iter().map(|(_, link)| link.clone()).collect(),
489 });
490 next_address = start + count as u64;
491 }
492 Self {
493 external_references,
494 sections,
495 }
496 }
497
498 pub fn links(&self) -> impl Iterator<Item = (u64, &[Reference])> + '_ {
500 let mut next_address = 1u64;
501 self.sections.iter().flat_map(move |section| {
502 let start = next_address.saturating_add(section.gap);
503 next_address = start.saturating_add(section.links.len() as u64);
504 section
505 .links
506 .iter()
507 .enumerate()
508 .map(move |(index, link)| (start + index as u64, link.as_slice()))
509 })
510 }
511
512 pub fn link_count(&self) -> u64 {
514 self.sections
515 .iter()
516 .map(|section| section.links.len() as u64)
517 .sum()
518 }
519
520 pub(crate) fn validate(&self) -> BinaryResult<()> {
521 let mut next_address = 1u64;
522 for section in &self.sections {
523 section.validate()?;
524 next_address = next_address
525 .checked_add(section.gap)
526 .and_then(|start| start.checked_add(section.links.len() as u64))
527 .ok_or_else(|| BinaryError::Unencodable("addresses overflow 64 bits".into()))?;
528 for link in §ion.links {
529 for &reference in link {
530 self.raw_reference(reference, section.width)?;
531 }
532 }
533 }
534 Ok(())
535 }
536
537 fn is_compact(&self) -> bool {
538 match self.sections.as_slice() {
539 [] => true,
540 [only] => {
541 only.gap == COMPACT_GAP
542 && only.arity == ArityRange::DOUBLETS
543 && !only.links.is_empty()
544 }
545 _ => false,
546 }
547 }
548
549 pub fn to_bytes(&self) -> BinaryResult<Vec<u8>> {
551 let mut bytes = Vec::new();
552 self.write_to(&mut bytes)?;
553 Ok(bytes)
554 }
555
556 pub fn write_to(&self, writer: &mut dyn Write) -> BinaryResult<()> {
558 let mut header = BINARY_VERSION_1;
559 if self.external_references {
560 header |= FLAG_EXTERNAL_REFERENCES;
561 }
562 let mut out = Vec::new();
563 self.validate()?;
564 if self.is_compact() {
565 let width = self.sections.first().map_or(1, |section| section.width);
566 header |= width_code(width)? << WIDTH_SHIFT;
567 out.push(header);
568 write_leb128(&mut out, self.link_count());
569 } else {
570 out.push(header | FLAG_EXPLICIT_LAYOUT);
571 write_leb128(&mut out, self.sections.len() as u64);
572 for section in &self.sections {
573 section.write_header(&mut out)?;
574 }
575 }
576 for section in &self.sections {
577 for link in §ion.links {
578 if !section.arity.is_fixed() {
579 write_leb128(&mut out, link.len() as u64 - section.arity.min);
580 }
581 for &reference in link {
582 write_raw(
583 &mut out,
584 self.raw_reference(reference, section.width)?,
585 section.width,
586 );
587 }
588 }
589 }
590 writer.write_all(&out)?;
591 Ok(())
592 }
593
594 fn raw_reference(&self, reference: Reference, width: u8) -> BinaryResult<u64> {
595 if reference_width(reference, self.external_references)? > width {
596 return Err(BinaryError::Unencodable(format!(
597 "{reference:?} does not fit {width} byte(s)"
598 )));
599 }
600 Ok(match reference {
601 Reference::Internal(address) => address,
602 Reference::External(value) => encode_external(value, width),
603 })
604 }
605
606 pub fn from_bytes(bytes: &[u8], limits: &DecodeLimits) -> BinaryResult<Self> {
608 let mut cursor = bytes;
609 let packet = Self::read_from(&mut cursor, limits)?
610 .ok_or_else(|| BinaryError::malformed("empty input"))?;
611 if !cursor.is_empty() {
612 return Err(BinaryError::malformed("trailing bytes after the packet"));
613 }
614 Ok(packet)
615 }
616
617 pub fn read_from(reader: &mut dyn Read, limits: &DecodeLimits) -> BinaryResult<Option<Self>> {
619 let Some(header) = read_byte_or_eof(reader)? else {
620 return Ok(None);
621 };
622 if header & 0xF0 != BINARY_VERSION_1 {
623 return Err(BinaryError::malformed(format!(
624 "unsupported binary header byte 0x{header:02X}"
625 )));
626 }
627 let mut packet = LinksPacket::new(header & FLAG_EXTERNAL_REFERENCES != 0);
628 let mut counts = Vec::new();
629 if header & FLAG_EXPLICIT_LAYOUT == 0 {
630 let width = width_from_code(u64::from((header & WIDTH_BITS) >> WIDTH_SHIFT));
631 let count = read_leb128(reader)?;
632 if count > u64::MAX - FIRST_LINK_ADDRESS {
633 return Err(BinaryError::malformed("addresses overflow 64 bits"));
634 }
635 if count > 0 {
636 packet.sections.push(Section {
637 gap: COMPACT_GAP,
638 arity: ArityRange::DOUBLETS,
639 width,
640 links: Vec::new(),
641 });
642 counts.push(count);
643 }
644 } else {
645 if header & WIDTH_BITS != 0 {
646 return Err(BinaryError::malformed(
647 "the explicit layout keeps the header width bits clear",
648 ));
649 }
650 let section_count = read_leb128(reader)?;
651 if section_count > limits.max_links {
652 return Err(Self::too_many_links(limits));
653 }
654 let mut next_address = 1u64;
655 for _ in 0..section_count {
656 let (section, count) = Section::read_header(reader)?;
657 next_address = next_address
658 .checked_add(section.gap)
659 .and_then(|start| start.checked_add(count))
660 .ok_or_else(|| BinaryError::malformed("addresses overflow 64 bits"))?;
661 packet.sections.push(section);
662 counts.push(count);
663 }
664 }
665 counts
666 .iter()
667 .try_fold(0u64, |total, &count| total.checked_add(count))
668 .filter(|&total| total <= limits.max_links)
669 .ok_or_else(|| Self::too_many_links(limits))?;
670 let mut references_left = limits.max_references;
671 let external_references = packet.external_references;
672 for (section, count) in packet.sections.iter_mut().zip(counts) {
673 section.links.reserve(count.min(4096) as usize);
674 for _ in 0..count {
675 let length = if section.arity.is_fixed() {
676 section.arity.min
677 } else {
678 let length = read_leb128(reader)?
679 .checked_add(section.arity.min)
680 .filter(|&length| section.arity.contains(length))
681 .ok_or_else(|| {
682 BinaryError::malformed(format!(
683 "link length outside the section arity {}",
684 section.arity
685 ))
686 })?;
687 length
688 };
689 references_left = references_left.checked_sub(length).ok_or_else(|| {
690 BinaryError::LimitExceeded(format!(
691 "references exceed the limit of {}",
692 limits.max_references
693 ))
694 })?;
695 let mut link = Vec::with_capacity(length.min(4096) as usize);
696 for _ in 0..length {
697 let raw = read_raw(reader, section.width)?;
698 link.push(
699 match decode_external(raw, section.width).filter(|_| external_references) {
700 Some(value) => Reference::External(value),
701 None => Reference::Internal(raw),
702 },
703 );
704 }
705 section.links.push(link);
706 }
707 }
708 Ok(Some(packet))
709 }
710
711 fn too_many_links(limits: &DecodeLimits) -> BinaryError {
712 BinaryError::LimitExceeded(format!(
713 "packet declares more than {} links",
714 limits.max_links
715 ))
716 }
717}
718
719const SECTION_HEADER_ESTIMATE: u64 = 2;
721const VARIABLE_ARITY_ESTIMATE: u64 = 1;
724const UNREACHABLE: u64 = u64::MAX / 4;
725const STATES: usize = WIDTHS.len() * 2;
727
728struct SectionPlanner<'a> {
736 links: &'a [(u64, Vec<Reference>)],
737 needs: Vec<u8>,
738}
739
740impl<'a> SectionPlanner<'a> {
741 fn new(external_references: bool, links: &'a [(u64, Vec<Reference>)]) -> BinaryResult<Self> {
742 let mut needs = Vec::with_capacity(links.len());
743 let mut previous_address = 0u64;
744 for (address, link) in links {
745 if *address <= previous_address {
746 return Err(BinaryError::Unencodable(format!(
747 "link addresses must ascend from 1, got {address} after {previous_address}"
748 )));
749 }
750 if *address == u64::MAX {
751 return Err(BinaryError::Unencodable(
752 "addresses overflow 64 bits".into(),
753 ));
754 }
755 if link.is_empty() {
756 return Err(BinaryError::Unencodable(format!(
757 "link {address} has no references"
758 )));
759 }
760 previous_address = *address;
761 let mut need = 1u8;
762 for &reference in link {
763 need = need.max(reference_width(reference, external_references)?);
764 }
765 needs.push(need);
766 }
767 Ok(Self { links, needs })
768 }
769
770 fn first_cheapest(costs: &[u64; STATES]) -> usize {
771 let mut best = 0;
772 for state in 1..STATES {
773 if costs[state] < costs[best] {
774 best = state;
775 }
776 }
777 best
778 }
779
780 fn plan(&self, packed_widths: bool) -> Vec<(usize, u8)> {
783 if self.links.is_empty() {
784 return Vec::new();
785 }
786 let widest = self.needs.iter().copied().max().unwrap_or(1);
787 let allowed_widths = WIDTHS.map(|width| packed_widths || width == widest);
788 let mut opens_section = vec![0u8; self.links.len()];
789 let mut previous_best = vec![0u8; self.links.len()];
790 let mut costs = [UNREACHABLE; STATES];
791 for (index, (address, link)) in self.links.iter().enumerate() {
792 let best = Self::first_cheapest(&costs);
793 previous_best[index] = best as u8;
794 let cheapest_before = if index == 0 { 0 } else { costs[best] };
795 let continues = index > 0 && self.links[index - 1].0 + 1 == *address;
796 let same_length = index > 0 && self.links[index - 1].1.len() == link.len();
797 let mut next = [UNREACHABLE; STATES];
798 for state in 0..STATES {
799 let width_index = state / 2;
800 let variable = state % 2 == 1;
801 let width = WIDTHS[width_index];
802 if !allowed_widths[width_index] || width < self.needs[index] {
803 continue;
804 }
805 let variable_estimate = if variable { VARIABLE_ARITY_ESTIMATE } else { 0 };
806 let body = link.len() as u64 * u64::from(width) + variable_estimate;
807 let opening_cost = cheapest_before + SECTION_HEADER_ESTIMATE + variable_estimate;
808 let continuing_cost = if continues && (variable || same_length) {
809 costs[state]
810 } else {
811 UNREACHABLE
812 };
813 if continuing_cost <= opening_cost {
814 next[state] = continuing_cost + body;
815 } else {
816 next[state] = opening_cost + body;
817 opens_section[index] |= 1 << state;
818 }
819 }
820 costs = next;
821 }
822 let mut sections = Vec::new();
823 let mut state = Self::first_cheapest(&costs);
824 let mut end = self.links.len();
825 for index in (0..self.links.len()).rev() {
826 if opens_section[index] & (1 << state) != 0 {
827 sections.push((end - index, WIDTHS[state / 2]));
828 end = index;
829 state = usize::from(previous_best[index]);
830 }
831 }
832 sections.reverse();
833 sections
834 }
835}
836
837fn write_raw(out: &mut Vec<u8>, value: u64, width: u8) {
838 out.extend_from_slice(&value.to_le_bytes()[..usize::from(width)]);
839}
840
841fn read_raw(reader: &mut dyn Read, width: u8) -> BinaryResult<u64> {
842 let mut bytes = [0u8; 8];
843 read_exact(reader, &mut bytes[..usize::from(width)])?;
844 Ok(u64::from_le_bytes(bytes))
845}
846
847pub fn write_leb128(out: &mut Vec<u8>, mut value: u64) {
849 loop {
850 let byte = (value & 0x7F) as u8;
851 value >>= 7;
852 if value == 0 {
853 out.push(byte);
854 return;
855 }
856 out.push(byte | 0x80);
857 }
858}
859
860pub fn read_leb128(reader: &mut dyn Read) -> BinaryResult<u64> {
862 let mut value = 0u64;
863 for shift in (0..64).step_by(7) {
864 let mut byte = [0u8; 1];
865 read_exact(reader, &mut byte)?;
866 let payload = u64::from(byte[0] & 0x7F);
867 if shift == 63 && payload > 1 {
868 return Err(BinaryError::malformed("LEB128 value overflows 64 bits"));
869 }
870 value |= payload << shift;
871 if byte[0] & 0x80 == 0 {
872 return Ok(value);
873 }
874 }
875 Err(BinaryError::malformed("LEB128 value overflows 64 bits"))
876}
877
878fn read_exact(reader: &mut dyn Read, buffer: &mut [u8]) -> BinaryResult<()> {
879 reader.read_exact(buffer).map_err(|error| {
880 if error.kind() == io::ErrorKind::UnexpectedEof {
881 BinaryError::malformed("unexpected end of packet")
882 } else {
883 BinaryError::Io(error)
884 }
885 })
886}
887
888fn read_byte_or_eof(reader: &mut dyn Read) -> BinaryResult<Option<u8>> {
890 let mut byte = [0u8; 1];
891 loop {
892 match reader.read(&mut byte) {
893 Ok(0) => return Ok(None),
894 Ok(_) => return Ok(Some(byte[0])),
895 Err(error) if error.kind() == io::ErrorKind::Interrupted => {}
896 Err(error) => return Err(error.into()),
897 }
898 }
899}