endr 0.9.0

endr: append-only replicated objects
Documentation
use std::{pin::Pin, fmt::Debug};

use futures::{Future, Stream};
use thiserror::Error;
use tracing::debug;

use crate::{StorageBackend, ObjectID};

pub(crate) trait Telepathic {
    type ID: Clone + PartialEq + Eq + std::hash::Hash;
    type WriteAccess;
    type StateInfo: PartialEq + Eq;
    type Diff: TelepathicDiff<ID = Self::ID>;
    type Error;

    fn id(&self) -> Self::ID;

    fn try_apply_diff(
        &mut self,
        diff: Self::Diff,
    ) -> ApplyDiffResult<Self::StateInfo, Self::ID, Self::Diff, Self::Error>;

    fn state_info(&self) -> Option<Self::StateInfo>;

    fn diff_since(&self, state_info: Option<&Self::StateInfo>) -> Option<Self::Diff>;

    fn state_as_initial_diff(&self) -> Option<Self::Diff> {
        let since_initial_diff = self.diff_since(None);
        since_initial_diff
    }

    fn load(
        id: Self::ID,
        storage: Box<dyn StorageBackend>,
    ) -> Pin<Box<dyn Stream<Item = Self::Diff>>>;
    fn store(
        effective_diff: Self::Diff,
        storage: Box<dyn StorageBackend>,
    ) -> Pin<Box<dyn Future<Output = ()>>>;
}

#[derive(Debug)]
pub struct ApplyDiffSuccess<
    S: PartialEq + Eq,
    ID: Clone + PartialEq + Eq + std::hash::Hash,
    D: TelepathicDiff<ID = ID>,
> {
    pub new_state_info: S,
    pub effective_diff: D,
}

pub type ApplyDiffResult<S, ID, D, E> = Result<Option<ApplyDiffSuccess<S, ID, D>>, ApplyDiffErrorFor<E>>;

pub trait TelepathicDiff: Debug {
    type ID: Clone + PartialEq + Eq + std::hash::Hash;
    fn id(&self) -> Self::ID;
}

#[derive(Debug, Error)]
pub enum ApplyDiffErrorFor<E> {
    #[error("Invalid known state assumed {0:?} {1}")]
    InvalidKnownStateAssumption(ObjectID, String),
    #[error(transparent)]
    Other(#[from] E),
}