monero_io/
lib.rs

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