Skip to content

Commit

Permalink
syncify data-model
Browse files Browse the repository at this point in the history
  • Loading branch information
sgwilym committed Jul 31, 2024
1 parent 8ad44bb commit 5d64d37
Show file tree
Hide file tree
Showing 8 changed files with 1,393 additions and 1,298 deletions.
37 changes: 23 additions & 14 deletions data-model/src/encoding/bytes.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
use either::Either;
use ufotofu::local_nb::BulkProducer;
use syncify::syncify;

use crate::encoding::error::DecodeError;
#[syncify(encoding_sync)]
pub(super) mod encoding {

/// Have `Producer` produce a single byte, or return an error if the final value was produced or the producer experienced an error.
pub async fn produce_byte<Producer>(
producer: &mut Producer,
) -> Result<u8, DecodeError<Producer::Error>>
where
Producer: BulkProducer<Item = u8>,
{
match producer.produce().await {
Ok(Either::Left(item)) => Ok(item),
Ok(Either::Right(_)) => Err(DecodeError::InvalidInput),
Err(err) => Err(DecodeError::Producer(err)),
use crate::encoding::error::DecodeError;

use either::Either;
use syncify::syncify_replace;

#[syncify_replace(use ufotofu::sync::{ BulkProducer};)]
use ufotofu::local_nb::BulkProducer;

/// Have `Producer` produce a single byte, or return an error if the final value was produced or the producer experienced an error.
pub async fn produce_byte<Producer>(
producer: &mut Producer,
) -> Result<u8, DecodeError<Producer::Error>>
where
Producer: BulkProducer<Item = u8>,
{
match producer.produce().await {
Ok(Either::Left(item)) => Ok(item),
Ok(Either::Right(_)) => Err(DecodeError::InvalidInput),
Err(err) => Err(DecodeError::Producer(err)),
}
}
}

Expand Down
103 changes: 57 additions & 46 deletions data-model/src/encoding/compact_width.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::encoding::error::DecodeError;
use crate::encoding::parameters::Decodable;
use crate::encoding::unsigned_int::{U16BE, U32BE, U64BE, U8BE};
use ufotofu::local_nb::{BulkConsumer, BulkProducer};

/// A minimum width of bytes needed to represent a unsigned integer.
#[derive(PartialEq, Eq, Debug)]
Expand Down Expand Up @@ -108,44 +105,61 @@ impl CompactWidth {
}
}

/// Encode a `u64` integer as a `compact_width(value)`-byte big-endian integer, and consume that with a [`BulkConsumer`].
pub async fn encode_compact_width_be<Consumer: BulkConsumer<Item = u8>>(
value: u64,
consumer: &mut Consumer,
) -> Result<(), Consumer::Error> {
let width = CompactWidth::from_u64(value).width();
use syncify::syncify;
use syncify::syncify_replace;

consumer
.bulk_consume_full_slice(&value.to_be_bytes()[8 - width..])
.await
.map_err(|f| f.reason)?;
#[syncify(encoding_sync)]
pub(super) mod encoding {
use super::*;

Ok(())
}
#[syncify_replace(use ufotofu::sync::{BulkConsumer, BulkProducer};)]
use ufotofu::local_nb::{BulkConsumer, BulkProducer};

use crate::encoding::unsigned_int::{U16BE, U32BE, U64BE, U8BE};

#[syncify_replace(use crate::encoding::parameters_sync::{Decodable, };)]
use crate::encoding::parameters::Decodable;

/// Encode a `u64` integer as a `compact_width(value)`-byte big-endian integer, and consume that with a [`BulkConsumer`].
pub async fn encode_compact_width_be<Consumer: BulkConsumer<Item = u8>>(
value: u64,
consumer: &mut Consumer,
) -> Result<(), Consumer::Error> {
let width = CompactWidth::from_u64(value).width();

/// Decode the bytes representing a [`compact-width`]-bytes integer into a `usize`.
pub async fn decode_compact_width_be<Producer: BulkProducer<Item = u8>>(
compact_width: CompactWidth,
producer: &mut Producer,
) -> Result<u64, DecodeError<Producer::Error>> {
let decoded = match compact_width {
CompactWidth::One => U8BE::decode(producer).await.map(u64::from),
CompactWidth::Two => U16BE::decode(producer).await.map(u64::from),
CompactWidth::Four => U32BE::decode(producer).await.map(u64::from),
CompactWidth::Eight => U64BE::decode(producer).await.map(u64::from),
}?;

let real_width = CompactWidth::from_u64(decoded);

if real_width != compact_width {
return Err(DecodeError::InvalidInput);
consumer
.bulk_consume_full_slice(&value.to_be_bytes()[8 - width..])
.await
.map_err(|f| f.reason)?;

Ok(())
}

Ok(decoded)
/// Decode the bytes representing a [`compact-width`]-bytes integer into a `usize`.
pub async fn decode_compact_width_be<Producer: BulkProducer<Item = u8>>(
compact_width: CompactWidth,
producer: &mut Producer,
) -> Result<u64, DecodeError<Producer::Error>> {
let decoded = match compact_width {
CompactWidth::One => U8BE::decode(producer).await.map(u64::from),
CompactWidth::Two => U16BE::decode(producer).await.map(u64::from),
CompactWidth::Four => U32BE::decode(producer).await.map(u64::from),
CompactWidth::Eight => U64BE::decode(producer).await.map(u64::from),
}?;

let real_width = CompactWidth::from_u64(decoded);

if real_width != compact_width {
return Err(DecodeError::InvalidInput);
}

Ok(decoded)
}
}

#[cfg(test)]
mod tests {
use encoding_sync::{decode_compact_width_be, encode_compact_width_be};
use ufotofu::local_nb::consumer::IntoVec;
use ufotofu::local_nb::producer::FromBoxedSlice;

Expand Down Expand Up @@ -219,26 +233,23 @@ mod tests {
(CompactWidth::Eight, u64::MAX),
];

smol::block_on(async {
for (compact_width, value) in values {
let mut consumer = IntoVec::<u8>::new();
for (compact_width, value) in values {
let mut consumer = IntoVec::<u8>::new();

encode_compact_width_be(value, &mut consumer).await.unwrap();
encode_compact_width_be(value, &mut consumer).unwrap();

let encode_result = consumer.into_vec();
let encode_result = consumer.into_vec();

let decoded_compact_width = CompactWidth::new(encode_result.len() as u8).unwrap();
let decoded_compact_width = CompactWidth::new(encode_result.len() as u8).unwrap();

assert_eq!(decoded_compact_width, compact_width);
assert_eq!(decoded_compact_width, compact_width);

let mut producer = FromBoxedSlice::from_vec(encode_result);
let mut producer = FromBoxedSlice::from_vec(encode_result);

let decode_result = decode_compact_width_be(decoded_compact_width, &mut producer)
.await
.unwrap();
let decode_result =
decode_compact_width_be(decoded_compact_width, &mut producer).unwrap();

assert_eq!(decode_result, value);
}
});
assert_eq!(decode_result, value);
}
}
}
26 changes: 26 additions & 0 deletions data-model/src/encoding/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,29 @@ pub trait Decodable {
Producer: BulkProducer<Item = u8>,
Self: Sized;
}

/// A type that can be used to encode `T` to a bytestring *encoded relative to `R`*.
/// This can be used to create more compact encodings from which `T` can be derived by anyone with `R`.
pub trait RelativeEncodable<R> {
/// A function from the set `Self` to the set of bytestrings *encoded relative to `reference`*.
fn relative_encode<Consumer>(
&self,
reference: &R,
consumer: &mut Consumer,
) -> impl Future<Output = Result<(), Consumer::Error>>
where
Consumer: BulkConsumer<Item = u8>;
}

/// A type that can be used to decode `T` from a bytestring *encoded relative to `Self`*.
/// This can be used to decode a compact encoding frow which `T` can be derived by anyone with `R`.
pub trait RelativeDecodable<R> {
/// A function from the set of bytestrings *encoded relative to `Self`* to the set of `T` in relation to `Self`.
fn relative_decode<Producer>(
reference: &R,
producer: &mut Producer,
) -> impl Future<Output = Result<Self, DecodeError<Producer::Error>>>
where
Producer: BulkProducer<Item = u8>,
Self: Sized;
}
33 changes: 26 additions & 7 deletions data-model/src/encoding/parameters_sync.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::future::Future;

use crate::encoding::error::DecodeError;
use ufotofu::sync::{BulkConsumer, BulkProducer};

Expand All @@ -10,10 +8,7 @@ pub trait Encodable {
/// A function from the set `Self` to the set of bytestrings.
///
/// [Definition](https://willowprotocol.org/specs/encodings/index.html#encode_s)
fn encode<Consumer>(
&self,
consumer: &mut Consumer,
) -> Result<(), Consumer::Error>
fn encode<Consumer>(&self, consumer: &mut Consumer) -> Result<(), Consumer::Error>
where
Consumer: BulkConsumer<Item = u8>;
}
Expand All @@ -25,7 +20,31 @@ pub trait Decodable {
/// A function from the set of bytestrings to the set of `T`.
///
/// [Definition](https://willowprotocol.org/specs/encodings/index.html#decode_s)
fn decode<Producer>(
fn decode<Producer>(producer: &mut Producer) -> Result<Self, DecodeError<Producer::Error>>
where
Producer: BulkProducer<Item = u8>,
Self: Sized;
}

/// A type that can be used to encode `T` to a bytestring *encoded relative to `R`*.
/// This can be used to create more compact encodings from which `T` can be derived by anyone with `R`.
pub trait RelativeEncodable<R> {
/// A function from the set `Self` to the set of bytestrings *encoded relative to `reference`*.
fn relative_encode<Consumer>(
&self,
reference: &R,
consumer: &mut Consumer,
) -> Result<(), Consumer::Error>
where
Consumer: BulkConsumer<Item = u8>;
}

/// A type that can be used to decode `T` from a bytestring *encoded relative to `Self`*.
/// This can be used to decode a compact encoding frow which `T` can be derived by anyone with `R`.
pub trait RelativeDecodable<R> {
/// A function from the set of bytestrings *encoded relative to `Self`* to the set of `T` in relation to `Self`.
fn relative_decode<Producer>(
reference: &R,
producer: &mut Producer,
) -> Result<Self, DecodeError<Producer::Error>>
where
Expand Down
Loading

0 comments on commit 5d64d37

Please sign in to comment.