willow-data-model 0.7.0

The core datatypes of Willow, an eventually consistent data store with improved distributed deletion.
Documentation
use arbitrary::Arbitrary;

use order_theory::*;

use signature::{Keypair, Signer, Verifier};
use ufotofu::codec_prelude::*;

/// A namespace id for testing.
///
/// Serves as a "public key" corresopnding to a [`TestNamespaceSecret`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Arbitrary)]
#[allow(missing_docs)]
pub enum TestNamespace {
    Family,
    Wiki,
    Project,
}

pub use TestNamespace::*;

impl Encodable for TestNamespace {
    async fn encode<C>(&self, consumer: &mut C) -> Result<(), C::Error>
    where
        C: BulkConsumer<Item = u8> + ?Sized,
    {
        match self {
            Family => consumer.consume_item(0).await,
            Wiki => consumer.consume_item(1).await,
            Project => consumer.consume_item(2).await,
        }
    }
}

impl EncodableKnownLength for TestNamespace {
    fn len_of_encoding(&self) -> usize {
        1
    }
}

impl Decodable for TestNamespace {
    type ErrorReason = Blame;

    async fn decode<P>(
        producer: &mut P,
    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
    where
        P: BulkProducer<Item = u8> + ?Sized,
        Self: Sized,
    {
        let byte = producer.produce_item().await?;

        match byte {
            0 => Ok(Family),
            1 => Ok(Wiki),
            2 => Ok(Project),
            _ => Err(DecodeError::Other(Blame::TheirFault)),
        }
    }
}

impl DecodableCanonic for TestNamespace {
    type ErrorCanonic = Blame;

    async fn decode_canonic<P>(
        producer: &mut P,
    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorCanonic>>
    where
        P: BulkProducer<Item = u8> + ?Sized,
        Self: Sized,
    {
        Self::decode(producer).await
    }
}

impl Verifier<TestNamespaceSignature> for TestNamespace {
    fn verify(
        &self,
        _msg: &[u8],
        signature: &TestNamespaceSignature,
    ) -> Result<(), signature::Error> {
        match (self, signature) {
            (Family, FamilySignature) => Ok(()),
            (Wiki, WikiSignature) => Ok(()),
            (Project, ProjectSignature) => Ok(()),
            _ => Err(signature::Error::new()),
        }
    }
}

impl GreatestElement for TestNamespace {
    fn greatest() -> Self {
        Project
    }
}

impl TrySuccessor for TestNamespace {
    fn try_successor(&self) -> Option<Self> {
        match self {
            Family => Some(Wiki),
            Wiki => Some(Project),
            Project => None,
        }
    }
}

impl SuccessorExceptForGreatest for TestNamespace {}

impl LeastElement for TestNamespace {
    fn least() -> Self {
        Family
    }
}

impl TryPredecessor for TestNamespace {
    fn try_predecessor(&self) -> Option<Self> {
        match self {
            Family => None,
            Wiki => Some(Family),
            Project => Some(Wiki),
        }
    }
}

impl PredecessorExceptForLeast for TestNamespace {}

/// A "private key" corresponding to a namespace, used for issuing [`TestNamespaceSignature`]s.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Arbitrary)]
#[allow(missing_docs)]
pub enum TestNamespaceSecret {
    FamilySecret,
    WikiSecret,
    ProjectSecret,
}

pub use TestNamespaceSecret::*;

impl Signer<TestNamespaceSignature> for TestNamespaceSecret {
    fn try_sign(&self, _msg: &[u8]) -> Result<TestNamespaceSignature, signature::Error> {
        Ok(match self {
            FamilySecret => FamilySignature,
            WikiSecret => WikiSignature,
            ProjectSecret => ProjectSignature,
        })
    }
}

impl Keypair for TestNamespaceSecret {
    type VerifyingKey = TestNamespace;

    fn verifying_key(&self) -> Self::VerifyingKey {
        match self {
            FamilySecret => Family,
            WikiSecret => Wiki,
            ProjectSecret => Project,
        }
    }
}

/// A "signature" issued by a [`TestNamespaceSecret`].
///
/// The signing process ignores the actual details of the payload.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Arbitrary)]
#[allow(missing_docs)]
pub enum TestNamespaceSignature {
    FamilySignature,
    WikiSignature,
    ProjectSignature,
}

pub use TestNamespaceSignature::*;

impl Encodable for TestNamespaceSignature {
    async fn encode<C>(&self, consumer: &mut C) -> Result<(), C::Error>
    where
        C: BulkConsumer<Item = u8> + ?Sized,
    {
        match self {
            FamilySignature => consumer.consume_item(0).await,
            WikiSignature => consumer.consume_item(1).await,
            ProjectSignature => consumer.consume_item(2).await,
        }
    }
}

impl EncodableKnownLength for TestNamespaceSignature {
    fn len_of_encoding(&self) -> usize {
        1
    }
}

impl Decodable for TestNamespaceSignature {
    type ErrorReason = Blame;

    async fn decode<P>(
        producer: &mut P,
    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
    where
        P: BulkProducer<Item = u8> + ?Sized,
        Self: Sized,
    {
        let byte = producer.produce_item().await?;

        match byte {
            0 => Ok(FamilySignature),
            1 => Ok(WikiSignature),
            2 => Ok(ProjectSignature),
            _ => Err(DecodeError::Other(Blame::TheirFault)),
        }
    }
}

impl DecodableCanonic for TestNamespaceSignature {
    type ErrorCanonic = Blame;

    async fn decode_canonic<P>(
        producer: &mut P,
    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorCanonic>>
    where
        P: BulkProducer<Item = u8> + ?Sized,
        Self: Sized,
    {
        Self::decode(producer).await
    }
}