use std::marker::PhantomData;
use stageleft::properties::Property;
use crate::live_collections::boundedness::Boundedness;
use crate::live_collections::keyed_singleton::KeyedSingletonBound;
use crate::live_collections::singleton::SingletonBound;
use crate::live_collections::stream::{ExactlyOnce, Ordering, Retries, TotalOrder};
#[sealed::sealed]
pub trait CommutativeProof {
fn register_proof(&self, expr: &syn::Expr);
}
#[sealed::sealed]
pub trait IdempotentProof {
fn register_proof(&self, expr: &syn::Expr);
}
#[sealed::sealed]
pub trait MonotoneProof {
fn register_proof(&self, expr: &syn::Expr);
}
#[sealed::sealed]
pub trait OrderPreservingProof {
fn register_proof(&self, expr: &syn::Expr);
}
#[sealed::sealed]
pub trait ConsistencyProof {}
pub struct ManualProof();
#[sealed::sealed]
impl CommutativeProof for ManualProof {
fn register_proof(&self, _expr: &syn::Expr) {}
}
#[sealed::sealed]
impl IdempotentProof for ManualProof {
fn register_proof(&self, _expr: &syn::Expr) {}
}
#[sealed::sealed]
impl MonotoneProof for ManualProof {
fn register_proof(&self, _expr: &syn::Expr) {}
}
#[sealed::sealed]
impl OrderPreservingProof for ManualProof {
fn register_proof(&self, _expr: &syn::Expr) {}
}
#[sealed::sealed]
impl ConsistencyProof for ManualProof {}
#[doc(inline)]
pub use crate::__manual_proof__ as manual_proof;
#[macro_export]
macro_rules! __manual_proof__ {
($(#[doc = $doc:expr])+) => {
$crate::properties::ManualProof()
};
}
pub enum NotProved {}
pub enum Proved {}
pub struct AggFuncAlgebra<Commutative = NotProved, Idempotent = NotProved, Monotone = NotProved>(
Option<Box<dyn CommutativeProof>>,
Option<Box<dyn IdempotentProof>>,
Option<Box<dyn MonotoneProof>>,
PhantomData<(Commutative, Idempotent, Monotone)>,
);
impl<C, I, M> AggFuncAlgebra<C, I, M> {
pub fn commutative(
self,
proof: impl CommutativeProof + 'static,
) -> AggFuncAlgebra<Proved, I, M> {
AggFuncAlgebra(Some(Box::new(proof)), self.1, self.2, PhantomData)
}
pub fn idempotent(self, proof: impl IdempotentProof + 'static) -> AggFuncAlgebra<C, Proved, M> {
AggFuncAlgebra(self.0, Some(Box::new(proof)), self.2, PhantomData)
}
pub fn monotone(self, proof: impl MonotoneProof + 'static) -> AggFuncAlgebra<C, I, Proved> {
AggFuncAlgebra(self.0, self.1, Some(Box::new(proof)), PhantomData)
}
pub(crate) fn register_proof(self, expr: &syn::Expr) {
if let Some(comm_proof) = self.0 {
comm_proof.register_proof(expr);
}
if let Some(idem_proof) = self.1 {
idem_proof.register_proof(expr);
}
if let Some(monotone_proof) = self.2 {
monotone_proof.register_proof(expr);
}
}
}
impl<C, I, M> Property for AggFuncAlgebra<C, I, M> {
type Root = AggFuncAlgebra;
fn make_root(_target: &mut Option<Self>) -> Self::Root {
AggFuncAlgebra(None, None, None, PhantomData)
}
}
pub struct SingletonMapFuncAlgebra<
OrderPreserving = NotProved,
Commutative = NotProved,
Idempotent = NotProved,
>(
Option<Box<dyn OrderPreservingProof>>,
Option<Box<dyn CommutativeProof>>,
Option<Box<dyn IdempotentProof>>,
PhantomData<(OrderPreserving, Commutative, Idempotent)>,
);
impl<O, C, I> SingletonMapFuncAlgebra<O, C, I> {
pub fn order_preserving(
self,
proof: impl OrderPreservingProof + 'static,
) -> SingletonMapFuncAlgebra<Proved, C, I> {
SingletonMapFuncAlgebra(Some(Box::new(proof)), self.1, self.2, PhantomData)
}
pub fn commutative(
self,
proof: impl CommutativeProof + 'static,
) -> SingletonMapFuncAlgebra<O, Proved, I> {
SingletonMapFuncAlgebra(self.0, Some(Box::new(proof)), self.2, PhantomData)
}
pub fn idempotent(
self,
proof: impl IdempotentProof + 'static,
) -> SingletonMapFuncAlgebra<O, C, Proved> {
SingletonMapFuncAlgebra(self.0, self.1, Some(Box::new(proof)), PhantomData)
}
pub(crate) fn register_proof(self, expr: &syn::Expr) {
if let Some(proof) = self.0 {
proof.register_proof(expr);
}
}
}
impl<O, C, I> Property for SingletonMapFuncAlgebra<O, C, I> {
type Root = SingletonMapFuncAlgebra;
fn make_root(_target: &mut Option<Self>) -> Self::Root {
SingletonMapFuncAlgebra(None, None, None, PhantomData)
}
}
pub struct StreamMapFuncAlgebra<Commutative = NotProved, Idempotent = NotProved>(
Option<Box<dyn CommutativeProof>>,
Option<Box<dyn IdempotentProof>>,
PhantomData<(Commutative, Idempotent)>,
);
impl<C, I> StreamMapFuncAlgebra<C, I> {
pub fn commutative(
self,
proof: impl CommutativeProof + 'static,
) -> StreamMapFuncAlgebra<Proved, I> {
StreamMapFuncAlgebra(Some(Box::new(proof)), self.1, PhantomData)
}
pub fn idempotent(
self,
proof: impl IdempotentProof + 'static,
) -> StreamMapFuncAlgebra<C, Proved> {
StreamMapFuncAlgebra(self.0, Some(Box::new(proof)), PhantomData)
}
pub(crate) fn register_proof(self, expr: &syn::Expr) {
if let Some(proof) = self.0 {
proof.register_proof(expr);
}
if let Some(proof) = self.1 {
proof.register_proof(expr);
}
}
}
impl<C, I> Property for StreamMapFuncAlgebra<C, I> {
type Root = StreamMapFuncAlgebra;
fn make_root(_target: &mut Option<Self>) -> Self::Root {
StreamMapFuncAlgebra(None, None, PhantomData)
}
}
#[diagnostic::on_unimplemented(
message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
label = "required for this call",
note = "To intentionally process the stream by observing a non-deterministic (shuffled) order of elements, use `.assume_ordering`. This introduces non-determinism so avoid unless necessary."
)]
#[sealed::sealed]
pub trait ValidCommutativityFor<O: Ordering> {}
#[sealed::sealed]
impl ValidCommutativityFor<TotalOrder> for NotProved {}
#[sealed::sealed]
impl<O: Ordering> ValidCommutativityFor<O> for Proved {}
#[diagnostic::on_unimplemented(
message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
label = "required for this call",
note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
)]
#[sealed::sealed]
pub trait ValidIdempotenceFor<R: Retries> {}
#[sealed::sealed]
impl ValidIdempotenceFor<ExactlyOnce> for NotProved {}
#[sealed::sealed]
impl<R: Retries> ValidIdempotenceFor<R> for Proved {}
#[sealed::sealed]
#[diagnostic::on_unimplemented(
message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
label = "required for this call",
note = "To intentionally process the stream by observing a non-deterministic (shuffled) order of elements, use `.assume_ordering`. This introduces non-determinism so avoid unless necessary."
)]
pub trait ValidMutCommutativityFor<F: FnMut(In) -> Out, In, Out, O: Ordering, const WAS_MUT: bool> {}
#[sealed::sealed]
impl<In, Out, F: FnMut(In) -> Out> ValidMutCommutativityFor<F, In, Out, TotalOrder, true>
for NotProved
{
}
#[sealed::sealed]
impl<In, Out, F: Fn(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, false>
for NotProved
{
}
#[sealed::sealed]
impl<In, Out, F: FnMut(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, true>
for Proved
{
}
#[sealed::sealed]
impl<In, Out, F: Fn(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, false>
for Proved
{
}
#[diagnostic::on_unimplemented(
message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
label = "required for this call",
note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
)]
#[sealed::sealed]
pub trait ValidMutIdempotenceFor<F: FnMut(In) -> Out, In, Out, R: Retries, const WAS_MUT: bool> {}
#[sealed::sealed]
impl<In, Out, F: FnMut(In) -> Out> ValidMutIdempotenceFor<F, In, Out, ExactlyOnce, true>
for NotProved
{
}
#[sealed::sealed]
impl<In, Out, F: Fn(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, false>
for NotProved
{
}
#[sealed::sealed]
impl<In, Out, F: FnMut(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, true>
for Proved
{
}
#[sealed::sealed]
impl<In, Out, F: Fn(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, false>
for Proved
{
}
#[sealed::sealed]
#[diagnostic::on_unimplemented(
message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
label = "required for this call",
note = "To intentionally process the stream by observing a non-deterministic (shuffled) order of elements, use `.assume_ordering`. This introduces non-determinism so avoid unless necessary."
)]
pub trait ValidMutBorrowCommutativityFor<
F: FnMut(&In) -> Out,
In: ?Sized,
Out,
O: Ordering,
const WAS_MUT: bool,
>
{
}
#[sealed::sealed]
impl<In: ?Sized, Out, F: FnMut(&In) -> Out>
ValidMutBorrowCommutativityFor<F, In, Out, TotalOrder, true> for NotProved
{
}
#[sealed::sealed]
impl<In: ?Sized, Out, F: Fn(&In) -> Out, O: Ordering>
ValidMutBorrowCommutativityFor<F, In, Out, O, false> for NotProved
{
}
#[sealed::sealed]
impl<In: ?Sized, Out, F: FnMut(&In) -> Out, O: Ordering>
ValidMutBorrowCommutativityFor<F, In, Out, O, true> for Proved
{
}
#[sealed::sealed]
impl<In: ?Sized, Out, F: Fn(&In) -> Out, O: Ordering>
ValidMutBorrowCommutativityFor<F, In, Out, O, false> for Proved
{
}
#[diagnostic::on_unimplemented(
message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
label = "required for this call",
note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
)]
#[sealed::sealed]
pub trait ValidMutBorrowIdempotenceFor<
F: FnMut(&In) -> Out,
In: ?Sized,
Out,
R: Retries,
const WAS_MUT: bool,
>
{
}
#[sealed::sealed]
impl<In: ?Sized, Out, F: FnMut(&In) -> Out>
ValidMutBorrowIdempotenceFor<F, In, Out, ExactlyOnce, true> for NotProved
{
}
#[sealed::sealed]
impl<In: ?Sized, Out, F: Fn(&In) -> Out, R: Retries>
ValidMutBorrowIdempotenceFor<F, In, Out, R, false> for NotProved
{
}
#[sealed::sealed]
impl<In: ?Sized, Out, F: FnMut(&In) -> Out, R: Retries>
ValidMutBorrowIdempotenceFor<F, In, Out, R, true> for Proved
{
}
#[sealed::sealed]
impl<In: ?Sized, Out, F: Fn(&In) -> Out, R: Retries>
ValidMutBorrowIdempotenceFor<F, In, Out, R, false> for Proved
{
}
#[sealed::sealed]
pub trait ApplyMonotoneStream<P, B2: SingletonBound> {}
#[sealed::sealed]
impl<B: Boundedness> ApplyMonotoneStream<NotProved, B> for B {}
#[sealed::sealed]
impl<B: Boundedness> ApplyMonotoneStream<Proved, B::StreamToMonotone> for B {}
#[sealed::sealed]
pub trait ApplyMonotoneKeyedStream<P, B2: KeyedSingletonBound> {}
#[sealed::sealed]
impl<B: Boundedness> ApplyMonotoneKeyedStream<NotProved, B::KeyedStreamToNonMonotone> for B {}
#[sealed::sealed]
impl<B: Boundedness> ApplyMonotoneKeyedStream<Proved, B::KeyedStreamToMonotone> for B {}
#[sealed::sealed]
pub trait ApplyOrderPreservingSingleton<P, B2: SingletonBound> {}
#[sealed::sealed]
impl<B: SingletonBound> ApplyOrderPreservingSingleton<NotProved, B::UnderlyingBound> for B {}
#[sealed::sealed]
impl<B: SingletonBound> ApplyOrderPreservingSingleton<Proved, B> for B {}