ufotofu 0.10.1

Abstractions for lazily consuming and producing sequences
Documentation
#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(feature = "alloc")]
use alloc::{boxed::Box, vec::Vec};

use crate::prelude::*;

/// A trait for types which can be encoded relative to a `RelativeTo`, into a sequence of `Symbol`s.
///
/// More precisely, this trait may be implemented by types that belong to a [relative encoding relation](super). The trait specifies (via the [`RelativeEncodable::can_be_encoded_relative_to`] method) which values can be encoded relative to which other values. For such pairs, the [`relative_encode`](RelativeEncodable::relative_encode) method then writes the encoding into a given [`BulkProducer`].
///
/// API contracts:
///
/// - If [`RelativeEncodable::can_be_encoded_relative_to`] returns `false` for some pair `(t, rel)`, then trying to encode `t` relative to `rel` with [`relative_encode`](RelativeEncodable::relative_encode) is allowed to panic.
/// - For any fixed `rel: RelativeTo`, [`relative_encode`](RelativeEncodable::relative_encode) must fulfil the same API contracts as [`encode`](crate::codec::Encodable::encode) does for [`Encodable`](crate::codec::Encodable).
///
/// <br/>Counterpart: the [`RelativeDecodable`](super::RelativeDecodable) trait.
pub trait RelativeEncodable<RelativeTo, Symbol = u8> {
    /// Writes an encoding of `&self` relative to `rel` into the given bulk consumer.
    ///
    /// This method is allowed to panic if `self.can_be_encoded_relative_to(rel)` would return `false`.
    ///
    /// <br/>Counterpart: the [`RelativeDecodable::relative_decode`](super::RelativeDecodable::relative_decode) method.
    async fn relative_encode<C>(&self, rel: &RelativeTo, consumer: &mut C) -> Result<(), C::Error>
    where
        C: BulkConsumer<Item = Symbol> + ?Sized;

    /// Returns whether `self` can be encoded relative to `rel`.
    ///
    /// Implementors of this trait are highly encouraged to use the documentation comment for this method to state explicitly the conditions under which this returns `true`.
    fn can_be_encoded_relative_to(&self, rel: &RelativeTo) -> bool;
}

impl<T, RelativeTo, Symbol> RelativeEncodable<RelativeTo, Symbol> for &T where T: RelativeEncodable<RelativeTo, Symbol> {
    async fn relative_encode<C>(&self, rel: &RelativeTo, consumer: &mut C) -> Result<(), C::Error>
    where
        C: BulkConsumer<Item = Symbol> + ?Sized {
        (*self).relative_encode(rel, consumer).await
    }

    fn can_be_encoded_relative_to(&self, rel: &RelativeTo) -> bool {
        (*self).can_be_encoded_relative_to(rel)
    }
}

/// Convenience methods for [`RelativeEncodable`] types. This trait is implemented automatically for all types that implement [`RelativeEncodable`].
pub trait RelativeEncodableExt<RelativeTo, Symbol = u8>:
    RelativeEncodable<RelativeTo, Symbol>
{
    #[cfg(feature = "alloc")]
    /// Returns a [`Vec`] storing the encoding of `self` relative to `rel`.
    async fn new_vec_storing_relative_encoding(&self, rel: &RelativeTo) -> Vec<Symbol>
    where
        Symbol: Default,
    {
        let mut c = Vec::new().into_consumer();

        match self.relative_encode(rel, &mut c).await {
            Ok(()) => c.into(),
            Err(_) => unreachable!(),
        }
    }
}

impl<T, RelativeTo, S> RelativeEncodableExt<RelativeTo, S> for T where
    T: RelativeEncodable<RelativeTo, S>
{
}

/// A [`RelativeEncodable`] type for which every value can precompute the number of symbols in its encoding relative to any other (valid) value.
///
/// API contract: a successful call to `self.encode(rel, &mut c)` must write exactly `self.len_of_relative_encoding(rel)` many symbols into `c`, if `self.can_be_encoded_relative_to(rel)` would return true.
pub trait RelativeEncodableKnownLength<RelativeTo, Symbol = u8>:
    RelativeEncodable<RelativeTo, Symbol>
{
    /// Computes the number of symbols of the encoding of `self`, relative to `rel`. A successful call to [`relative_encode`](RelativeEncodable::relative_encode) must feed exactly that many symbols into the bulk consumer.
    ///
    /// This method is allowed to panic if `self.can_be_encoded_relative_to(rel)` would return `false`.
    fn len_of_relative_encoding(&self, rel: &RelativeTo) -> usize;
}

impl<T, RelativeTo, Symbol> RelativeEncodableKnownLength<RelativeTo, Symbol> for &T where T: RelativeEncodableKnownLength<RelativeTo, Symbol> {
    fn len_of_relative_encoding(&self, rel: &RelativeTo) -> usize {
        (*self).len_of_relative_encoding(rel)
    }
}

/// Convenience methods for [`RelativeEncodable`] types. This trait is implemented automatically for all types that implement [`RelativeEncodable`].
pub trait RelativeEncodableKnownLengthExt<RelativeTo, Symbol = u8>:
    RelativeEncodableKnownLength<RelativeTo, Symbol>
{
    #[cfg(feature = "alloc")]
    /// Returns a [`Box<[Symbol]>`](alloc::boxed::Box) storing the encoding of `self` relative to `rel`.
    ///
    /// More efficient than [`RelativeEncodableExt::new_vec_storing_relative_encoding`], because the size of the required memory allocation is computed in advance via [`RelativeEncodableKnownLength::len_of_relative_encoding`].
    async fn new_boxed_slice_storing_relative_encoding(&self, rel: &RelativeTo) -> Box<[Symbol]>
    where
        Symbol: Default,
    {
        let mut c = Vec::with_capacity(self.len_of_relative_encoding(rel)).into_consumer();

        match self.relative_encode(rel, &mut c).await {
            Ok(()) => Vec::<Symbol>::from(c).into_boxed_slice(),
            Err(_) => unreachable!(),
        }
    }
}

impl<T, S> RelativeEncodableKnownLengthExt<S> for T where T: RelativeEncodableKnownLength<S> {}