willow_encoding/
max_power.rs

1use syncify::syncify;
2use syncify::syncify_replace;
3
4/// Return the least natural number such that 256^`n` is greater than or equal to `n`.
5///
6/// Used for determining the minimal number of bytes needed to represent a given unsigned integer, and more specifically [`path_length_power`](https://willowprotocol.org/specs/encodings/index.html#path_length_power) and [`path_count_power`](https://willowprotocol.org/specs/encodings/index.html#path_count_power).
7pub const fn max_power(max_size: usize) -> u8 {
8    if max_size < 256 {
9        1
10    } else if max_size < 65536 {
11        2
12    } else if max_size < 16777216 {
13        3
14    } else if max_size < 4294967296 {
15        4
16    } else if max_size < (256_usize).pow(5) {
17        5
18    } else if max_size < (256_usize).pow(6) {
19        6
20    } else if max_size < (256_usize).pow(7) {
21        7
22    } else {
23        8
24    }
25}
26
27#[syncify(encoding_sync)]
28pub(super) mod encoding {
29    use super::*;
30
31    use core::mem::size_of;
32
33    use crate::error::DecodeError;
34
35    #[syncify_replace(use ufotofu::sync::{BulkConsumer, BulkProducer};)]
36    use ufotofu::local_nb::{BulkConsumer, BulkProducer};
37
38    /// Encode a `usize` to a `n`-width unsigned integer, where `n` is the least number of bytes needed to represent `max_size`.
39    pub async fn encode_max_power<C>(
40        value: usize,
41        max_size: usize,
42        consumer: &mut C,
43    ) -> Result<(), C::Error>
44    where
45        C: BulkConsumer<Item = u8>,
46    {
47        if value > max_size {
48            panic!("Can't encode a value larger than its maximum possible value!")
49        }
50
51        let power = max_power(max_size);
52        let value_encoded_raw: [u8; size_of::<u64>()] = value.to_be_bytes();
53
54        consumer
55            .bulk_consume_full_slice(&value_encoded_raw[size_of::<u64>() - (power as usize)..])
56            .await
57            .map_err(|f| f.reason)?;
58
59        Ok(())
60    }
61
62    /// Decode a `u64` from `n`-width bytestring, where `n` is the least number of bytes needed to represent `max_size`.
63    pub async fn decode_max_power<P>(
64        max_size: usize,
65        producer: &mut P,
66    ) -> Result<u64, DecodeError<P::Error>>
67    where
68        P: BulkProducer<Item = u8>,
69    {
70        let power = max_power(max_size);
71        let mut slice = [0u8; size_of::<u64>()];
72
73        producer
74            .bulk_overwrite_full_slice(&mut slice[size_of::<u64>() - (power as usize)..])
75            .await?;
76
77        Ok(u64::from_be_bytes(slice))
78    }
79}
80
81pub use encoding::{decode_max_power, encode_max_power};