Skip to main content

monero_io/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3#![deny(missing_docs)]
4#![cfg_attr(not(feature = "std"), no_std)]
5
6use core::fmt::Debug;
7#[allow(unused_imports)]
8use std_shims::prelude::*;
9use std_shims::io::{self, Read, Write};
10
11mod varint;
12pub use varint::*;
13
14/// Write a byte.
15///
16/// This is used as a building block within generic functions.
17pub fn write_byte<W: Write>(byte: &u8, w: &mut W) -> io::Result<()> {
18  w.write_all(&[*byte])
19}
20
21/// Write a list of elements, without length-prefixing.
22pub fn write_raw_vec<T, W: Write, F: FnMut(&T, &mut W) -> io::Result<()>>(
23  mut f: F,
24  values: &[T],
25  w: &mut W,
26) -> io::Result<()> {
27  for value in values {
28    f(value, w)?;
29  }
30  Ok(())
31}
32
33/// Write a list of elements, with length-prefixing.
34pub fn write_vec<T, W: Write, F: FnMut(&T, &mut W) -> io::Result<()>>(
35  f: F,
36  values: &[T],
37  w: &mut W,
38) -> io::Result<()> {
39  VarInt::write(&values.len(), w)?;
40  write_raw_vec(f, values, w)
41}
42
43/// Read a constant amount of bytes.
44pub fn read_bytes<R: Read, const N: usize>(r: &mut R) -> io::Result<[u8; N]> {
45  let mut res = [0; N];
46  r.read_exact(&mut res)?;
47  Ok(res)
48}
49
50/// Read a single byte.
51pub fn read_byte<R: Read>(r: &mut R) -> io::Result<u8> {
52  Ok(read_bytes::<_, 1>(r)?[0])
53}
54
55/// Read a u16, little-endian encoded.
56pub fn read_u16<R: Read>(r: &mut R) -> io::Result<u16> {
57  read_bytes(r).map(u16::from_le_bytes)
58}
59
60/// Read a u32, little-endian encoded.
61pub fn read_u32<R: Read>(r: &mut R) -> io::Result<u32> {
62  read_bytes(r).map(u32::from_le_bytes)
63}
64
65/// Read a u64, little-endian encoded.
66pub fn read_u64<R: Read>(r: &mut R) -> io::Result<u64> {
67  read_bytes(r).map(u64::from_le_bytes)
68}
69
70/// Read a variable-length list of elements, without length-prefixing.
71pub fn read_raw_vec<R: Read, T, F: FnMut(&mut R) -> io::Result<T>>(
72  mut f: F,
73  len: usize,
74  r: &mut R,
75) -> io::Result<Vec<T>> {
76  let mut res = vec![];
77  for _ in 0 .. len {
78    res.push(f(r)?);
79  }
80  Ok(res)
81}
82
83/// Read a constant-length list of elements.
84pub fn read_array<R: Read, T: Debug, F: FnMut(&mut R) -> io::Result<T>, const N: usize>(
85  f: F,
86  r: &mut R,
87) -> io::Result<[T; N]> {
88  read_raw_vec(f, N, r).map(|vec| {
89    vec.try_into().expect(
90      "read vector of specific length yet couldn't transform to an array of the same length",
91    )
92  })
93}
94
95/// Read a length-prefixed variable-length list of elements.
96///
97/// An optional bound on the length of the result may be provided. If `None`, the returned `Vec`
98/// will be of the length read off the reader, if successfully read. If `Some(_)`, an error will be
99/// raised if the length read off the read is greater than the bound.
100pub fn read_vec<R: Read, T, F: FnMut(&mut R) -> io::Result<T>>(
101  f: F,
102  length_bound: Option<usize>,
103  r: &mut R,
104) -> io::Result<Vec<T>> {
105  let declared_length: usize = VarInt::read(r)?;
106  if let Some(length_bound) = length_bound {
107    if declared_length > length_bound {
108      Err(io::Error::other("vector exceeds bound on length"))?;
109    }
110  }
111  read_raw_vec(f, declared_length, r)
112}