Skip to main content

tuwunel_core/utils/
bytes.rs

1use bytesize::ByteSize;
2use serde::{Deserialize, Deserializer, de};
3
4use crate::{Result, at, err};
5
6/// Accepts an integer byte count or a string with SI/IEC suffix (e.g. "24 MiB")
7/// and returns a `usize`.
8pub fn deserialize_bytesize_usize<'de, D>(de: D) -> Result<usize, D::Error>
9where
10	D: Deserializer<'de>,
11{
12	ByteSize::deserialize(de)
13		.map(at!(0))
14		.map(usize::try_from)?
15		.map_err(de::Error::custom)
16}
17
18/// Accepts an integer byte count or a string with SI/IEC suffix (e.g. "32 MiB")
19/// and returns a `u64`.
20pub fn deserialize_bytesize_u64<'de, D>(de: D) -> Result<u64, D::Error>
21where
22	D: Deserializer<'de>,
23{
24	ByteSize::deserialize(de).map(at!(0))
25}
26
27/// Parse a human-writable size string w/ si-unit suffix into integer
28#[inline]
29pub fn from_str(str: &str) -> Result<usize> {
30	let bytes: ByteSize = str
31		.parse()
32		.map_err(|e| err!(Arithmetic("Failed to parse byte size: {e}")))?;
33
34	let bytes: usize = bytes
35		.as_u64()
36		.try_into()
37		.map_err(|e| err!(Arithmetic("Failed to convert u64 to usize: {e}")))?;
38
39	Ok(bytes)
40}
41
42/// Output a human-readable size string w/ iec-unit suffix
43#[inline]
44#[must_use]
45pub fn pretty(bytes: usize) -> String {
46	let bytes: u64 = bytes
47		.try_into()
48		.expect("failed to convert usize to u64");
49
50	ByteSize::b(bytes).display().iec().to_string()
51}
52
53#[inline]
54#[must_use]
55pub fn increment(old: Option<&[u8]>) -> [u8; 8] {
56	old.map_or(0_u64, |bytes| u64_from_bytes(bytes).unwrap_or(0))
57		.wrapping_add(1)
58		.to_be_bytes()
59}
60
61/// Parses 8 big-endian bytes into an u64; panic on invalid argument
62#[inline]
63#[must_use]
64pub fn u64_from_u8(bytes: &[u8]) -> u64 {
65	u64_from_bytes(bytes).expect("must slice at least 8 bytes")
66}
67
68/// Parses the big-endian bytes into an u64.
69#[inline]
70pub fn u64_from_bytes(bytes: &[u8]) -> Result<u64> { Ok(u64::from_be_bytes(bytes.try_into()?)) }