use super::Error;
use commonware_runtime::{Handle, ReadOptions};
use futures::{Stream, stream};
use std::{future::Future, num::NonZeroUsize, ops::Range};
mod blobs;
mod checkpoint;
pub mod fixed;
mod metrics;
pub mod variable;
#[cfg(test)]
pub(crate) mod tests;
fn batch_count_to_blob_boundary(position: u64, remaining: usize, items_per_blob: u64) -> usize {
let pos_in_blob = position % items_per_blob;
let remaining_space = items_per_blob - pos_in_blob;
remaining_space.min(remaining as u64) as usize
}
const fn position_to_blob(position: u64, items_per_blob: u64) -> u64 {
position / items_per_blob
}
fn blob_first_position(blob: u64, items_per_blob: u64) -> Result<u64, Error> {
blob.checked_mul(items_per_blob)
.ok_or(Error::OffsetOverflow)
}
const fn blob_end_position(blob: u64, items_per_blob: u64, end: u64) -> u64 {
if end == 0 {
return 0;
}
let end_blob = (end - 1) / items_per_blob;
if blob >= end_blob {
return end;
}
(blob + 1) * items_per_blob
}
struct Decoded<T> {
batch: Batch<T>,
error: Option<Error>,
}
impl<T> Decoded<T> {
const fn failed(start: u64, items: Vec<T>, error: Error) -> Self {
Self {
batch: Batch { start, items },
error: Some(error),
}
}
}
trait BatchDecoder: Sized {
type Item;
fn next(self) -> impl Future<Output = Option<(Decoded<Self::Item>, Self)>> + Send;
}
struct ReplayStreamState<S: BatchDecoder> {
states: std::vec::IntoIter<S>,
current: Option<S>,
pending: Option<Error>,
}
impl<S: BatchDecoder + Send> ReplayStreamState<S>
where
S::Item: Send,
{
async fn next(mut self) -> Option<(Result<Batch<S::Item>, Error>, Self)> {
loop {
if let Some(err) = self.pending.take() {
return Some((Err(err), self));
}
let state = match self.current.take().or_else(|| self.states.next()) {
Some(state) => state,
None => return None,
};
match state.next().await {
Some((decoded, state)) => {
match decoded.error {
Some(err) => {
self.pending = Some(err);
self.states = Vec::new().into_iter();
}
None => self.current = Some(state),
}
if !decoded.batch.items.is_empty() {
return Some((Ok(decoded.batch), self));
}
}
None => {
self.current = None;
}
}
}
}
}
fn replay_stream_from_states<S>(
states: Vec<S>,
) -> impl Stream<Item = Result<Batch<S::Item>, Error>> + Send
where
S: BatchDecoder + Send,
S::Item: Send,
{
stream::unfold(
ReplayStreamState {
states: states.into_iter(),
current: None,
pending: None,
},
ReplayStreamState::next,
)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Batch<T> {
pub start: u64,
pub items: Vec<T>,
}
impl<T> IntoIterator for Batch<T> {
type Item = (u64, T);
type IntoIter = std::iter::Zip<Range<u64>, std::vec::IntoIter<T>>;
fn into_iter(self) -> Self::IntoIter {
let end = self.start + self.items.len() as u64;
(self.start..end).zip(self.items)
}
}
pub trait Contiguous: Send + Sync {
type Item: Send + Sync;
fn bounds(&self) -> Range<u64>;
fn read(&self, position: u64) -> impl Future<Output = Result<Self::Item, Error>> + Send;
fn read_many(
&self,
positions: &[u64],
) -> impl Future<Output = Result<Vec<Self::Item>, Error>> + Send;
fn try_read_sync(&self, position: u64) -> Option<Self::Item>;
fn try_read_many_sync(&self, positions: &[u64]) -> Vec<Option<Self::Item>>;
fn replay(
&self,
range: Range<u64>,
buffer: NonZeroUsize,
read_options: ReadOptions,
) -> impl Future<
Output = Result<impl Stream<Item = Result<Batch<Self::Item>, Error>> + Send, Error>,
> + Send;
}
pub enum Many<'a, T> {
Flat(&'a [T]),
Nested(&'a [&'a [T]]),
}
impl<T> Many<'_, T> {
pub fn len(&self) -> usize {
match self {
Self::Flat(items) => items.len(),
Self::Nested(nested_items) => nested_items.iter().map(|items| items.len()).sum(),
}
}
pub fn is_empty(&self) -> bool {
match self {
Self::Flat(items) => items.is_empty(),
Self::Nested(nested_items) => nested_items.iter().all(|items| items.is_empty()),
}
}
}
pub trait Mutable: Contiguous + Sized {
fn append(
self,
item: &Self::Item,
) -> impl std::future::Future<Output = Result<(Self, u64), Error>> + Send;
fn append_many(
self,
items: Many<'_, Self::Item>,
) -> impl std::future::Future<Output = Result<(Self, u64), Error>> + Send;
fn prune(
self,
min_position: u64,
) -> impl std::future::Future<Output = Result<(Self, bool), Error>> + Send;
fn start_sync(
self,
) -> impl std::future::Future<Output = Result<(Self, Handle<()>), Error>> + Send;
fn commit(self) -> impl std::future::Future<Output = Result<Self, Error>> + Send;
fn sync(self) -> impl std::future::Future<Output = Result<Self, Error>> + Send;
fn destroy(self) -> impl std::future::Future<Output = Result<(), Error>> + Send;
}