{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

{- | Description: Garbage collected event folding CRDT. -}
module Data.CRDT.EventFold (
  -- * Overview
  {- |
    This module provides a CRDT data structure that collects and applies
    operations (called "events") that mutate an underlying data structure.

    It is "Garbage Collected" in the sense that the number of operations
    accumulated in the structure will not grow unbounded, assuming that
    participants manage to sync their data once in a while. The size of
    the data (as measured by the number of operations we have to store)
    is allowed to shrink.

    In addition to mutating the underlying data, each operation can
    also produce an output that can be obtained by the client. The
    output can be either totally consistent across all replicas (which
    is slower), or it can be returned immediately and possibly reflect
    an inconsistent state.
  -}

  -- ** Garbage Collection
  {- |
    Unlike many traditional CRDTs which always grow and never shrink,
    'EventFold' has a mechanism for determining what consensus
    has been reached by all of the participants, which allows us to
    "garbage collect" events that achieved total consensus. Perhaps more
    importantly, this allows us to produce the totally consistent output
    for events for which total consensus has been achieved.

    But there are trade offs. The big downside is that participation in the
    distributed replication of the 'EventFold' must be strictly managed.

    - The process of participating itself involves registering with an
      existing participant, using 'participate'. You can't just send the
      data off to some other computer and expect that now that computer
      is participating in the CRDT. It isn't.
    - Participants can not "restore from backup". Once they have
      incorporated data received from other participants or generated
      new data themselves, and that data has been transmitted to any
      other participant, they are committed to using that result going
      forward. Doing anything that looks like "restoring from an older
      version" would destroy the idea that participants have reached
      consensus on anything, and the results would be undefined and
      almost certainly completely wrong. This library is written with
      some limited capability to detect this situation, but it is not
      always possible to detect it all cases. Many times you will just
      end up with undefined behavior.
  -}

  -- ** A Belabored Analogy
  {- |
    The 'EventFold' name derives from a loose analogy to folding over
    a list of events using plain old 'foldl'. The component parts of
    'foldl' are:

    - A binary operator, analogous to 'apply'.

    - An accumulator value, analogous to 'infimumValue'.

    - A list of values to fold over, loosely analogous to "the list of
      all future calls to 'event'".

    - A return value.  There is no real analogy for the "return value".
      Similarly to how you never actually obtain a return value if you
      try to 'foldl' over an infinite list, 'EventFold's are meant to be
      long-lived objects that accommodate an infinite number of calls
      to 'event'. What you can do is inspect the current value of the
      accumulator using 'infimumValue', or the "projected" value of
      the accumulator using 'projectedValue' (where "projected" means
      "taking into account all of the currently known calls to 'event'
      that have not yet been folded into the accumulator, and which may
      yet turn out to to have other events inserted into the middle or
      beginning of the list").

    The 'EventFold' value itself can be thought of as an intermediate,
    replicated, current state of the fold of an infinite list of events
    that has not yet been fully generated.  So you can, for instance,
    check the current accumulator value.

    In a little more detail, consider the type signature of 'foldl'
    (for lists).

    > foldl
    >   :: (b -> a -> b) -- Analogous to 'apply', where 'a' is your 'Event'
    >                    -- instance, and 'b' is 'State a'.
    >
    >   -> b             -- Loosely analogous to 'infimumValue' where
    >                    -- progressive applications are accumulated.
    >
    >   -> [a]           -- Analogous to all outstanding or future calls to
    >                    -- 'event'.
    >
    >   -> b
  -}
  -- * Basic API
  -- ** Creating new CRDTs
  new,

  -- ** Adding new events
  event,

  -- ** Coordinating replica updates
  {- |
    Functions in this section are used to help merge foreign copies of
    the CRDT, and transmit our own copy. (This library does not provide
    any kind of transport support, except that all the relevant types
    have 'Binary' instances. Actually arranging for these things to get
    shipped across a wire is left to the user.)

    In principal, the only function you need is 'fullMerge'. Everything
    else in this section is an optimization.  You can ship the full
    'EventFold' value to a remote participant and it can incorporate
    any changes using 'fullMerge', and vice versa. You can receive an
    'EventFold' value from another participant and incorporate its
    changes locally using 'fullMerge'.

    However, if your underlying data structure is large, it may be more
    efficient to just ship a sort of diff containing the information
    that the local participant thinks the remote participant might be
    missing. That is what 'events' and 'diffMerge' are for.
  -}
  fullMerge,
  fullMerge_,
  UpdateResult(..),
  events,
  diffMerge,
  diffMerge_,
  MergeError(..),
  acknowledge,

  -- ** Participation
  participate,
  disassociate,

  -- ** Defining your state and events
  Event(..),
  EventResult(..),

  -- * Inspecting the 'EventFold'
  isBlockedOnError,
  projectedValue,
  infimumValue,
  infimumId,
  infimumParticipants,
  allParticipants,
  projParticipants,
  origin,
  divergent,
  source,

  -- * Underlying Types
  EventFold,
  EventId,
  bottomEid,
  Diff,

) where

import Control.Exception (Exception)
import Data.Aeson (FromJSON(parseJSON), ToJSON(toEncoding, toJSON),
  FromJSONKey, ToJSONKey)
import Data.Bifunctor (Bifunctor(first))
import Data.Binary (Binary(get, put))
import Data.Default.Class (Default(def))
import Data.Map (Map, toAscList, toDescList, unionWith)
import Data.Set ((\\), Set, member, union)
import GHC.Generics (Generic)
import Prelude (Applicative(pure), Bool(False, True), Either(Left, Right),
  Enum(succ), Eq((/=), (==)), Foldable(foldr, maximum), Functor(fmap),
  Maybe(Just, Nothing), Monoid(mempty), Ord((<), (<=), compare, max),
  Semigroup((<>)), ($), (.), (<$>), (||), Num, Show, const, fst, id,
  not, otherwise, snd)
import Type.Reflection (Typeable)
import qualified Data.DoubleWord as DW
import qualified Data.Map as Map
import qualified Data.Map.Merge.Lazy as Map.Merge
import qualified Data.Set as Set

{-# ANN module "HLint: ignore Redundant if" #-}
{-# ANN module "HLint: ignore Use catMaybes" #-}

{- |
  This type is a
  <https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type CRDT>
  into which participants can add 'Event's that are folded into a
  base 'State'. You can also think of the "events" as operations that
  mutate the base state, and the point of this CRDT is to coordinate
  the application of the operations across all participants so that
  they are applied consistently even if the operations themselves are
  not commutative, idempotent, or monotonic.

  Variables are:

  - @o@ - Origin
  - @p@ - Participant
  - @e@ - Event

  The "Origin" is a value that is more or less meant to identify the
  "thing" being replicated, and in particular identify the historical
  lineage of the 'EventFold'. The idea is that it is meaningless to
  try and merge two 'EventFold's that do not share a common history
  (identified by the origin value) and doing so is a programming error. It
  is only used to try and check for this type of programming error and
  throw an exception if it happens instead of producing undefined (and
  difficult to detect) behavior.
-}
data EventFold o p e = EventFold {
     forall o p e. EventFold o p e -> o
psOrigin :: o,
    forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum :: Infimum (State e) p,
     forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p),
    forall o p e. EventFold o p e -> Set (EventId p)
psUnjoins :: Set (EventId p)
                 {- ^
                   The set of events that perform an unjoin with
                   unjoins that have not reached the infimum. This is
                   an optimization so that 'reduce' doesn't have to
                   recompute this every time.
                 -}
  }
  deriving stock ((forall x. EventFold o p e -> Rep (EventFold o p e) x)
-> (forall x. Rep (EventFold o p e) x -> EventFold o p e)
-> Generic (EventFold o p e)
forall x. Rep (EventFold o p e) x -> EventFold o p e
forall x. EventFold o p e -> Rep (EventFold o p e) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall o p e x. Rep (EventFold o p e) x -> EventFold o p e
forall o p e x. EventFold o p e -> Rep (EventFold o p e) x
$cfrom :: forall o p e x. EventFold o p e -> Rep (EventFold o p e) x
from :: forall x. EventFold o p e -> Rep (EventFold o p e) x
$cto :: forall o p e x. Rep (EventFold o p e) x -> EventFold o p e
to :: forall x. Rep (EventFold o p e) x -> EventFold o p e
Generic)
deriving anyclass instance (ToJSON o, ToJSON p, ToJSON e, ToJSON (State e), ToJSON (Output e)) => ToJSON (EventFold o p e)
deriving anyclass instance (Ord p, FromJSON o, FromJSON p, FromJSON e, FromJSON (Output e), FromJSON (State e)) => FromJSON (EventFold o p e)
deriving stock instance
    ( Eq (Output e)
    , Eq o
    , Eq p
    , Eq e
    )
  =>
    Eq (EventFold o p e)
instance
    (
      Binary o,
      Binary p,
      Binary e,
      Binary (State e),
      Binary (Output e)
    )
  =>
    Binary (EventFold o p e)
deriving stock instance
    ( Show (Output e)
    , Show o
    , Show p
    , Show e
    , Show (State e)
    )
  => Show (EventFold o p e)


{- |
  `Infimum` is the infimum, or greatest lower bound, of the possible
  values of @s@.
-}
data Infimum s p = Infimum
  {      forall s p. Infimum s p -> EventId p
eventId :: EventId p
  , forall s p. Infimum s p -> Set p
participants :: Set p
  ,   forall s p. Infimum s p -> s
stateValue :: s
  }
  deriving stock ((forall x. Infimum s p -> Rep (Infimum s p) x)
-> (forall x. Rep (Infimum s p) x -> Infimum s p)
-> Generic (Infimum s p)
forall x. Rep (Infimum s p) x -> Infimum s p
forall x. Infimum s p -> Rep (Infimum s p) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall s p x. Rep (Infimum s p) x -> Infimum s p
forall s p x. Infimum s p -> Rep (Infimum s p) x
$cfrom :: forall s p x. Infimum s p -> Rep (Infimum s p) x
from :: forall x. Infimum s p -> Rep (Infimum s p) x
$cto :: forall s p x. Rep (Infimum s p) x -> Infimum s p
to :: forall x. Rep (Infimum s p) x -> Infimum s p
Generic, Int -> Infimum s p -> ShowS
[Infimum s p] -> ShowS
Infimum s p -> String
(Int -> Infimum s p -> ShowS)
-> (Infimum s p -> String)
-> ([Infimum s p] -> ShowS)
-> Show (Infimum s p)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall s p. (Show p, Show s) => Int -> Infimum s p -> ShowS
forall s p. (Show p, Show s) => [Infimum s p] -> ShowS
forall s p. (Show p, Show s) => Infimum s p -> String
$cshowsPrec :: forall s p. (Show p, Show s) => Int -> Infimum s p -> ShowS
showsPrec :: Int -> Infimum s p -> ShowS
$cshow :: forall s p. (Show p, Show s) => Infimum s p -> String
show :: Infimum s p -> String
$cshowList :: forall s p. (Show p, Show s) => [Infimum s p] -> ShowS
showList :: [Infimum s p] -> ShowS
Show)
  deriving anyclass ([Infimum s p] -> Value
[Infimum s p] -> Encoding
Infimum s p -> Bool
Infimum s p -> Value
Infimum s p -> Encoding
(Infimum s p -> Value)
-> (Infimum s p -> Encoding)
-> ([Infimum s p] -> Value)
-> ([Infimum s p] -> Encoding)
-> (Infimum s p -> Bool)
-> ToJSON (Infimum s p)
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
forall s p. (ToJSON s, ToJSON p) => [Infimum s p] -> Value
forall s p. (ToJSON s, ToJSON p) => [Infimum s p] -> Encoding
forall s p. (ToJSON s, ToJSON p) => Infimum s p -> Bool
forall s p. (ToJSON s, ToJSON p) => Infimum s p -> Value
forall s p. (ToJSON s, ToJSON p) => Infimum s p -> Encoding
$ctoJSON :: forall s p. (ToJSON s, ToJSON p) => Infimum s p -> Value
toJSON :: Infimum s p -> Value
$ctoEncoding :: forall s p. (ToJSON s, ToJSON p) => Infimum s p -> Encoding
toEncoding :: Infimum s p -> Encoding
$ctoJSONList :: forall s p. (ToJSON s, ToJSON p) => [Infimum s p] -> Value
toJSONList :: [Infimum s p] -> Value
$ctoEncodingList :: forall s p. (ToJSON s, ToJSON p) => [Infimum s p] -> Encoding
toEncodingList :: [Infimum s p] -> Encoding
$comitField :: forall s p. (ToJSON s, ToJSON p) => Infimum s p -> Bool
omitField :: Infimum s p -> Bool
ToJSON, Maybe (Infimum s p)
Value -> Parser [Infimum s p]
Value -> Parser (Infimum s p)
(Value -> Parser (Infimum s p))
-> (Value -> Parser [Infimum s p])
-> Maybe (Infimum s p)
-> FromJSON (Infimum s p)
forall a.
(Value -> Parser a)
-> (Value -> Parser [a]) -> Maybe a -> FromJSON a
forall s p. (Ord p, FromJSON p, FromJSON s) => Maybe (Infimum s p)
forall s p.
(Ord p, FromJSON p, FromJSON s) =>
Value -> Parser [Infimum s p]
forall s p.
(Ord p, FromJSON p, FromJSON s) =>
Value -> Parser (Infimum s p)
$cparseJSON :: forall s p.
(Ord p, FromJSON p, FromJSON s) =>
Value -> Parser (Infimum s p)
parseJSON :: Value -> Parser (Infimum s p)
$cparseJSONList :: forall s p.
(Ord p, FromJSON p, FromJSON s) =>
Value -> Parser [Infimum s p]
parseJSONList :: Value -> Parser [Infimum s p]
$comittedField :: forall s p. (Ord p, FromJSON p, FromJSON s) => Maybe (Infimum s p)
omittedField :: Maybe (Infimum s p)
FromJSON)
instance (Binary s, Binary p) => Binary (Infimum s p)
instance (Eq p) => Eq (Infimum s p) where
  Infimum EventId p
s1 Set p
_ s
_ == :: Infimum s p -> Infimum s p -> Bool
== Infimum EventId p
s2 Set p
_ s
_ = EventId p
s1 EventId p -> EventId p -> Bool
forall a. Eq a => a -> a -> Bool
== EventId p
s2
instance (Ord p) => Ord (Infimum s p) where
  compare :: Infimum s p -> Infimum s p -> Ordering
compare (Infimum EventId p
s1 Set p
_ s
_) (Infimum EventId p
s2 Set p
_ s
_) = EventId p -> EventId p -> Ordering
forall a. Ord a => a -> a -> Ordering
compare EventId p
s1 EventId p
s2


{- |
  `EventId` is a monotonically increasing, totally ordered identification
  value which allows us to lend the attribute of monotonicity to event
  application operations which would not naturally be monotonic.
-}
data EventId p
  = BottomEid
  | Eid Word256 p
  deriving stock ((forall x. EventId p -> Rep (EventId p) x)
-> (forall x. Rep (EventId p) x -> EventId p)
-> Generic (EventId p)
forall x. Rep (EventId p) x -> EventId p
forall x. EventId p -> Rep (EventId p) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall p x. Rep (EventId p) x -> EventId p
forall p x. EventId p -> Rep (EventId p) x
$cfrom :: forall p x. EventId p -> Rep (EventId p) x
from :: forall x. EventId p -> Rep (EventId p) x
$cto :: forall p x. Rep (EventId p) x -> EventId p
to :: forall x. Rep (EventId p) x -> EventId p
Generic, EventId p -> EventId p -> Bool
(EventId p -> EventId p -> Bool)
-> (EventId p -> EventId p -> Bool) -> Eq (EventId p)
forall p. Eq p => EventId p -> EventId p -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall p. Eq p => EventId p -> EventId p -> Bool
== :: EventId p -> EventId p -> Bool
$c/= :: forall p. Eq p => EventId p -> EventId p -> Bool
/= :: EventId p -> EventId p -> Bool
Eq, Eq (EventId p)
Eq (EventId p) =>
(EventId p -> EventId p -> Ordering)
-> (EventId p -> EventId p -> Bool)
-> (EventId p -> EventId p -> Bool)
-> (EventId p -> EventId p -> Bool)
-> (EventId p -> EventId p -> Bool)
-> (EventId p -> EventId p -> EventId p)
-> (EventId p -> EventId p -> EventId p)
-> Ord (EventId p)
EventId p -> EventId p -> Bool
EventId p -> EventId p -> Ordering
EventId p -> EventId p -> EventId p
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall p. Ord p => Eq (EventId p)
forall p. Ord p => EventId p -> EventId p -> Bool
forall p. Ord p => EventId p -> EventId p -> Ordering
forall p. Ord p => EventId p -> EventId p -> EventId p
$ccompare :: forall p. Ord p => EventId p -> EventId p -> Ordering
compare :: EventId p -> EventId p -> Ordering
$c< :: forall p. Ord p => EventId p -> EventId p -> Bool
< :: EventId p -> EventId p -> Bool
$c<= :: forall p. Ord p => EventId p -> EventId p -> Bool
<= :: EventId p -> EventId p -> Bool
$c> :: forall p. Ord p => EventId p -> EventId p -> Bool
> :: EventId p -> EventId p -> Bool
$c>= :: forall p. Ord p => EventId p -> EventId p -> Bool
>= :: EventId p -> EventId p -> Bool
$cmax :: forall p. Ord p => EventId p -> EventId p -> EventId p
max :: EventId p -> EventId p -> EventId p
$cmin :: forall p. Ord p => EventId p -> EventId p -> EventId p
min :: EventId p -> EventId p -> EventId p
Ord, Int -> EventId p -> ShowS
[EventId p] -> ShowS
EventId p -> String
(Int -> EventId p -> ShowS)
-> (EventId p -> String)
-> ([EventId p] -> ShowS)
-> Show (EventId p)
forall p. Show p => Int -> EventId p -> ShowS
forall p. Show p => [EventId p] -> ShowS
forall p. Show p => EventId p -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall p. Show p => Int -> EventId p -> ShowS
showsPrec :: Int -> EventId p -> ShowS
$cshow :: forall p. Show p => EventId p -> String
show :: EventId p -> String
$cshowList :: forall p. Show p => [EventId p] -> ShowS
showList :: [EventId p] -> ShowS
Show)
  deriving anyclass ([EventId p] -> Value
[EventId p] -> Encoding
EventId p -> Bool
EventId p -> Value
EventId p -> Encoding
(EventId p -> Value)
-> (EventId p -> Encoding)
-> ([EventId p] -> Value)
-> ([EventId p] -> Encoding)
-> (EventId p -> Bool)
-> ToJSON (EventId p)
forall p. ToJSON p => [EventId p] -> Value
forall p. ToJSON p => [EventId p] -> Encoding
forall p. ToJSON p => EventId p -> Bool
forall p. ToJSON p => EventId p -> Value
forall p. ToJSON p => EventId p -> Encoding
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: forall p. ToJSON p => EventId p -> Value
toJSON :: EventId p -> Value
$ctoEncoding :: forall p. ToJSON p => EventId p -> Encoding
toEncoding :: EventId p -> Encoding
$ctoJSONList :: forall p. ToJSON p => [EventId p] -> Value
toJSONList :: [EventId p] -> Value
$ctoEncodingList :: forall p. ToJSON p => [EventId p] -> Encoding
toEncodingList :: [EventId p] -> Encoding
$comitField :: forall p. ToJSON p => EventId p -> Bool
omitField :: EventId p -> Bool
ToJSON, Maybe (EventId p)
Value -> Parser [EventId p]
Value -> Parser (EventId p)
(Value -> Parser (EventId p))
-> (Value -> Parser [EventId p])
-> Maybe (EventId p)
-> FromJSON (EventId p)
forall p. FromJSON p => Maybe (EventId p)
forall p. FromJSON p => Value -> Parser [EventId p]
forall p. FromJSON p => Value -> Parser (EventId p)
forall a.
(Value -> Parser a)
-> (Value -> Parser [a]) -> Maybe a -> FromJSON a
$cparseJSON :: forall p. FromJSON p => Value -> Parser (EventId p)
parseJSON :: Value -> Parser (EventId p)
$cparseJSONList :: forall p. FromJSON p => Value -> Parser [EventId p]
parseJSONList :: Value -> Parser [EventId p]
$comittedField :: forall p. FromJSON p => Maybe (EventId p)
omittedField :: Maybe (EventId p)
FromJSON, ToJSONKeyFunction [EventId p]
ToJSONKeyFunction (EventId p)
ToJSONKeyFunction (EventId p)
-> ToJSONKeyFunction [EventId p] -> ToJSONKey (EventId p)
forall a.
ToJSONKeyFunction a -> ToJSONKeyFunction [a] -> ToJSONKey a
forall p. ToJSON p => ToJSONKeyFunction [EventId p]
forall p. ToJSON p => ToJSONKeyFunction (EventId p)
$ctoJSONKey :: forall p. ToJSON p => ToJSONKeyFunction (EventId p)
toJSONKey :: ToJSONKeyFunction (EventId p)
$ctoJSONKeyList :: forall p. ToJSON p => ToJSONKeyFunction [EventId p]
toJSONKeyList :: ToJSONKeyFunction [EventId p]
ToJSONKey, FromJSONKeyFunction [EventId p]
FromJSONKeyFunction (EventId p)
FromJSONKeyFunction (EventId p)
-> FromJSONKeyFunction [EventId p] -> FromJSONKey (EventId p)
forall a.
FromJSONKeyFunction a -> FromJSONKeyFunction [a] -> FromJSONKey a
forall p. FromJSON p => FromJSONKeyFunction [EventId p]
forall p. FromJSON p => FromJSONKeyFunction (EventId p)
$cfromJSONKey :: forall p. FromJSON p => FromJSONKeyFunction (EventId p)
fromJSONKey :: FromJSONKeyFunction (EventId p)
$cfromJSONKeyList :: forall p. FromJSON p => FromJSONKeyFunction [EventId p]
fromJSONKeyList :: FromJSONKeyFunction [EventId p]
FromJSONKey, Get (EventId p)
[EventId p] -> Put
EventId p -> Put
(EventId p -> Put)
-> Get (EventId p) -> ([EventId p] -> Put) -> Binary (EventId p)
forall p. Binary p => Get (EventId p)
forall p. Binary p => [EventId p] -> Put
forall p. Binary p => EventId p -> Put
forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
$cput :: forall p. Binary p => EventId p -> Put
put :: EventId p -> Put
$cget :: forall p. Binary p => Get (EventId p)
get :: Get (EventId p)
$cputList :: forall p. Binary p => [EventId p] -> Put
putList :: [EventId p] -> Put
Binary)
instance Default (EventId p) where
  def :: EventId p
def = EventId p
forall p. EventId p
BottomEid


{- |
  The participant the created an event, if there is one (which there
  isn't for 'bottomEid').
-}
source :: EventId p -> Maybe p
source :: forall p. EventId p -> Maybe p
source = \case
  EventId p
BottomEid -> Maybe p
forall a. Maybe a
Nothing
  Eid Word256
_ p
p -> p -> Maybe p
forall a. a -> Maybe a
Just p
p


{- | Newtype around 'DW.Word256' to supply typeclass instances. -}
newtype Word256 = Word256 {
    Word256 -> Word256
unWord256 :: DW.Word256
  }
  deriving stock ((forall x. Word256 -> Rep Word256 x)
-> (forall x. Rep Word256 x -> Word256) -> Generic Word256
forall x. Rep Word256 x -> Word256
forall x. Word256 -> Rep Word256 x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Word256 -> Rep Word256 x
from :: forall x. Word256 -> Rep Word256 x
$cto :: forall x. Rep Word256 x -> Word256
to :: forall x. Rep Word256 x -> Word256
Generic)
  deriving newtype (Word256 -> Word256 -> Bool
(Word256 -> Word256 -> Bool)
-> (Word256 -> Word256 -> Bool) -> Eq Word256
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Word256 -> Word256 -> Bool
== :: Word256 -> Word256 -> Bool
$c/= :: Word256 -> Word256 -> Bool
/= :: Word256 -> Word256 -> Bool
Eq, Eq Word256
Eq Word256 =>
(Word256 -> Word256 -> Ordering)
-> (Word256 -> Word256 -> Bool)
-> (Word256 -> Word256 -> Bool)
-> (Word256 -> Word256 -> Bool)
-> (Word256 -> Word256 -> Bool)
-> (Word256 -> Word256 -> Word256)
-> (Word256 -> Word256 -> Word256)
-> Ord Word256
Word256 -> Word256 -> Bool
Word256 -> Word256 -> Ordering
Word256 -> Word256 -> Word256
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Word256 -> Word256 -> Ordering
compare :: Word256 -> Word256 -> Ordering
$c< :: Word256 -> Word256 -> Bool
< :: Word256 -> Word256 -> Bool
$c<= :: Word256 -> Word256 -> Bool
<= :: Word256 -> Word256 -> Bool
$c> :: Word256 -> Word256 -> Bool
> :: Word256 -> Word256 -> Bool
$c>= :: Word256 -> Word256 -> Bool
>= :: Word256 -> Word256 -> Bool
$cmax :: Word256 -> Word256 -> Word256
max :: Word256 -> Word256 -> Word256
$cmin :: Word256 -> Word256 -> Word256
min :: Word256 -> Word256 -> Word256
Ord, Int -> Word256 -> ShowS
[Word256] -> ShowS
Word256 -> String
(Int -> Word256 -> ShowS)
-> (Word256 -> String) -> ([Word256] -> ShowS) -> Show Word256
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Word256 -> ShowS
showsPrec :: Int -> Word256 -> ShowS
$cshow :: Word256 -> String
show :: Word256 -> String
$cshowList :: [Word256] -> ShowS
showList :: [Word256] -> ShowS
Show, Int -> Word256
Word256 -> Int
Word256 -> [Word256]
Word256 -> Word256
Word256 -> Word256 -> [Word256]
Word256 -> Word256 -> Word256 -> [Word256]
(Word256 -> Word256)
-> (Word256 -> Word256)
-> (Int -> Word256)
-> (Word256 -> Int)
-> (Word256 -> [Word256])
-> (Word256 -> Word256 -> [Word256])
-> (Word256 -> Word256 -> [Word256])
-> (Word256 -> Word256 -> Word256 -> [Word256])
-> Enum Word256
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: Word256 -> Word256
succ :: Word256 -> Word256
$cpred :: Word256 -> Word256
pred :: Word256 -> Word256
$ctoEnum :: Int -> Word256
toEnum :: Int -> Word256
$cfromEnum :: Word256 -> Int
fromEnum :: Word256 -> Int
$cenumFrom :: Word256 -> [Word256]
enumFrom :: Word256 -> [Word256]
$cenumFromThen :: Word256 -> Word256 -> [Word256]
enumFromThen :: Word256 -> Word256 -> [Word256]
$cenumFromTo :: Word256 -> Word256 -> [Word256]
enumFromTo :: Word256 -> Word256 -> [Word256]
$cenumFromThenTo :: Word256 -> Word256 -> Word256 -> [Word256]
enumFromThenTo :: Word256 -> Word256 -> Word256 -> [Word256]
Enum, Integer -> Word256
Word256 -> Word256
Word256 -> Word256 -> Word256
(Word256 -> Word256 -> Word256)
-> (Word256 -> Word256 -> Word256)
-> (Word256 -> Word256 -> Word256)
-> (Word256 -> Word256)
-> (Word256 -> Word256)
-> (Word256 -> Word256)
-> (Integer -> Word256)
-> Num Word256
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
$c+ :: Word256 -> Word256 -> Word256
+ :: Word256 -> Word256 -> Word256
$c- :: Word256 -> Word256 -> Word256
- :: Word256 -> Word256 -> Word256
$c* :: Word256 -> Word256 -> Word256
* :: Word256 -> Word256 -> Word256
$cnegate :: Word256 -> Word256
negate :: Word256 -> Word256
$cabs :: Word256 -> Word256
abs :: Word256 -> Word256
$csignum :: Word256 -> Word256
signum :: Word256 -> Word256
$cfromInteger :: Integer -> Word256
fromInteger :: Integer -> Word256
Num)
instance FromJSON Word256 where
  parseJSON :: Value -> Parser Word256
parseJSON Value
v = do
    (Word64
a, Word64
b, Word64
c, Word64
d) <- Value -> Parser (Word64, Word64, Word64, Word64)
forall a. FromJSON a => Value -> Parser a
parseJSON Value
v
    Word256 -> Parser Word256
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word256 -> Word256
Word256 (Word128 -> Word128 -> Word256
DW.Word256 (Word64 -> Word64 -> Word128
DW.Word128 Word64
a Word64
b) (Word64 -> Word64 -> Word128
DW.Word128 Word64
c Word64
d)))
instance ToJSON Word256 where
  toJSON :: Word256 -> Value
toJSON (Word256 (DW.Word256 (DW.Word128 Word64
a Word64
b) (DW.Word128 Word64
c Word64
d))) =
    (Word64, Word64, Word64, Word64) -> Value
forall a. ToJSON a => a -> Value
toJSON (Word64
a, Word64
b, Word64
c, Word64
d)
  toEncoding :: Word256 -> Encoding
toEncoding (Word256 (DW.Word256 (DW.Word128 Word64
a Word64
b) (DW.Word128 Word64
c Word64
d))) =
    (Word64, Word64, Word64, Word64) -> Encoding
forall a. ToJSON a => a -> Encoding
toEncoding (Word64
a, Word64
b, Word64
c, Word64
d)
instance Binary Word256 where
  put :: Word256 -> Put
put (Word256 (DW.Word256 (DW.Word128 Word64
a Word64
b) (DW.Word128 Word64
c Word64
d))) =
    (Word64, Word64, Word64, Word64) -> Put
forall t. Binary t => t -> Put
put (Word64
a, Word64
b, Word64
c, Word64
d)
  get :: Get Word256
get = do
    (Word64
a, Word64
b, Word64
c, Word64
d) <- Get (Word64, Word64, Word64, Word64)
forall t. Binary t => Get t
get
    Word256 -> Get Word256
forall a. a -> Get a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word256 -> Word256
Word256 (Word128 -> Word128 -> Word256
DW.Word256 (Word64 -> Word64 -> Word128
DW.Word128 Word64
a Word64
b) (Word64 -> Word64 -> Word128
DW.Word128 Word64
c Word64
d)))


{- |
  This is the exception type for illegal merges. These errors indicate
  serious programming bugs.
-}
data MergeError o p e
  = DifferentOrigins o o
    {- ^
      The 'EventFold's do not have the same origin. It makes no sense
      to merge 'EventFold's that have different origins because they
      do not share a common history.
    -}
  | DiffTooNew (EventFold o p e) (Diff o p e)
    {- ^
      The `Diff`'s infimum is greater than any event known to 'EventFold'
      into which it is being merged. This should be impossible and
      indicates that either the local 'EventFold' has rolled back an
      event that it had previously acknowledged, or else the source of
      the 'Diff' moved the infimum forward without a full acknowledgement
      from all participants. Both of these conditions should be regarded
      as serious bugs.
    -}
  | DiffTooSparse (EventFold o p e) (Diff o p e)
    {- ^
      The 'Diff' assumes we know about events that we do not in fact know
      about. This is only possible if we rolled back our copy of the state
      somehow and "forgot" about state that we had previous acknowledged,
      or else some other participant erroneously acknowledged some events
      on our behalf.
    -}
  deriving stock ((forall x. MergeError o p e -> Rep (MergeError o p e) x)
-> (forall x. Rep (MergeError o p e) x -> MergeError o p e)
-> Generic (MergeError o p e)
forall x. Rep (MergeError o p e) x -> MergeError o p e
forall x. MergeError o p e -> Rep (MergeError o p e) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall o p e x. Rep (MergeError o p e) x -> MergeError o p e
forall o p e x. MergeError o p e -> Rep (MergeError o p e) x
$cfrom :: forall o p e x. MergeError o p e -> Rep (MergeError o p e) x
from :: forall x. MergeError o p e -> Rep (MergeError o p e) x
$cto :: forall o p e x. Rep (MergeError o p e) x -> MergeError o p e
to :: forall x. Rep (MergeError o p e) x -> MergeError o p e
Generic)
deriving anyclass instance (Ord p, FromJSON o, FromJSON p, FromJSON e, FromJSON (State e), FromJSON (Output e)) => FromJSON (MergeError o p e)
deriving anyclass instance (ToJSON o, ToJSON p, ToJSON e, ToJSON (Output e), ToJSON (State e)) => ToJSON (MergeError o p e)
deriving stock instance
    ( Show (Output e)
    , Show o
    , Show p
    , Show e
    , Show (State e)
    )
  =>
    Show (MergeError o p e)
instance (Typeable o, Typeable p, Typeable e, Show (Output e), Show o, Show p, Show e, Show (State e)) => Exception (MergeError o p e)


{- | `Delta` is how we represent mutations to the event fold state. -}
data Delta p e
  = Join p
  | UnJoin p
  | EventD e
  | Error (Output e) (Set p)
  deriving stock ((forall x. Delta p e -> Rep (Delta p e) x)
-> (forall x. Rep (Delta p e) x -> Delta p e)
-> Generic (Delta p e)
forall x. Rep (Delta p e) x -> Delta p e
forall x. Delta p e -> Rep (Delta p e) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall p e x. Rep (Delta p e) x -> Delta p e
forall p e x. Delta p e -> Rep (Delta p e) x
$cfrom :: forall p e x. Delta p e -> Rep (Delta p e) x
from :: forall x. Delta p e -> Rep (Delta p e) x
$cto :: forall p e x. Rep (Delta p e) x -> Delta p e
to :: forall x. Rep (Delta p e) x -> Delta p e
Generic)
deriving anyclass instance (ToJSON p, ToJSON e, ToJSON (Output e)) => ToJSON (Delta p e)
deriving anyclass instance (Ord p, FromJSON p, FromJSON e, FromJSON (Output e)) => (FromJSON (Delta p e))
deriving stock instance (Eq p, Eq e, Eq (Output e)) => Eq (Delta p e)
deriving stock instance (Show p, Show e, Show (Output e)) => Show (Delta p e)
instance (Binary p, Binary e, Binary (Output e)) => Binary (Delta p e)


{- |
  Instances of this class define the particular "events" being "folded"
  over in a distributed fashion. In addition to the event type itself,
  there are a couple of type families which define the 'State' into which
  folded events are accumulated, and the 'Output' which application of
  a particular event can generate.

  TL;DR: This is how users define their own custom operations.
-}
class Event p e where
  type Output e
  type State e
  {- | Apply an event to a state value. **This function MUST be total!!!** -}
  apply :: e -> State e -> EventResult e

  join :: p -> State e -> State e
  join p
_ State e
s = State e
s

  unjoin :: p -> State e -> State e
  unjoin p
_ State e
s = State e
s
{- | The most trivial event type. -}
instance Event p () where
  type Output () = ()
  type State () = ()
  apply :: () -> State () -> EventResult ()
apply () () = Output () -> State () -> EventResult ()
forall e. Output e -> State e -> EventResult e
Pure () ()
{- | The union of two event types. -}
instance (Event p a, Event p b) => Event p (Either a b) where
  type Output (Either a b) = Either (Output a) (Output b)
  type State (Either a b) = (State a, State b)

  apply :: Either a b -> State (Either a b) -> EventResult (Either a b)
apply (Left a
e) (State a
a, State b
b) =
    case forall p e. Event p e => e -> State e -> EventResult e
apply @p a
e State a
a of
      SystemError Output a
o -> Output (Either a b) -> EventResult (Either a b)
forall e. Output e -> EventResult e
SystemError (Output a -> Either (Output a) (Output b)
forall a b. a -> Either a b
Left Output a
o)
      Pure Output a
o State a
s -> Output (Either a b)
-> State (Either a b) -> EventResult (Either a b)
forall e. Output e -> State e -> EventResult e
Pure (Output a -> Either (Output a) (Output b)
forall a b. a -> Either a b
Left Output a
o) (State a
s, State b
b)
  apply (Right b
e) (State a
a, State b
b) =
    case forall p e. Event p e => e -> State e -> EventResult e
apply @p b
e State b
b of
      SystemError Output b
o -> Output (Either a b) -> EventResult (Either a b)
forall e. Output e -> EventResult e
SystemError (Output b -> Either (Output a) (Output b)
forall a b. b -> Either a b
Right Output b
o)
      Pure Output b
o State b
s -> Output (Either a b)
-> State (Either a b) -> EventResult (Either a b)
forall e. Output e -> State e -> EventResult e
Pure (Output b -> Either (Output a) (Output b)
forall a b. b -> Either a b
Right Output b
o) (State a
a, State b
s)

  join :: p -> State (Either a b) -> State (Either a b)
join p
p (State a
a, State b
b) =
    (forall p e. Event p e => p -> State e -> State e
join @p @a p
p State a
a, forall p e. Event p e => p -> State e -> State e
join @p @b p
p State b
b)

  unjoin :: p -> State (Either a b) -> State (Either a b)
unjoin p
p (State a
a, State b
b) =
    (forall p e. Event p e => p -> State e -> State e
unjoin @p @a p
p State a
a, forall p e. Event p e => p -> State e -> State e
unjoin @p @b p
p State b
b)


{- |
  The result of applying an event.

  Morally speaking, events are always pure functions. However, mundane
  issues like finite memory constraints and finite execution time can
  cause referentially opaque behavior. In a normal Haskell program, this
  usually leads to a crash or an exception, and the crash or exception
  can itself, in a way, be thought of as being referentially transparent,
  because there is no way for it to both happen and, simultaneously,
  not happen.

  However, in our case we are replicating computations across many
  different pieces of hardware, so there most definitely is a way
  for these aberrant system failures to both happen and not happen
  simultaneously. What happens if the computation of the event runs out
  of memory on one machine, but not on another?

  There exists a strategy for dealing with these problems: if the
  computation of an event experiences a failure on every participant, then
  the event is pushed into the infimum as a failure (i.e. a no-op), but if
  any single participant successfully computes the event then all other
  participants can (somehow) request a "Full Merge" from the successful
  participant. The Full Merge will include the infimum __value__ computed
  by the successful participant, which will include the successful
  application of the problematic event. The error participants can thus
  bypass computation of the problem event altogether, and can simply
  overwrite their infimum with the infimum provided by the Full Merge.

  Doing a full merge can be much more expensive than doing a simple
  'Diff' merge, because it requires transmitting the full value of the
  'EventFold' instead of just the outstanding operations.

  This type represents how computation of the event finished; with either a
  pure result, or some kind of system error.

  TL;DR:

  In general 'SystemError' is probably only ever useful for when your
  event type somehow executes untrusted code (for instance when your event
  type is a Turing-complete DSL that allows users to submit their own
  custom-programmed "events") and you want to limit the resources that
  can be consumed by such untrusted code.  It is much less useful when
  you are encoding some well defined business logic directly in Haskell.
-}
data EventResult e
  = SystemError (Output e)
  | Pure (Output e) (State e)


{- |
  Construct a new 'EventFold' with the given origin and initial
  participant.
-}
new
  :: forall o p e.
     ( Default (State e)
     , Event p e
     , Ord p
     )
  => o {- ^ The "origin", identifying the historical lineage of this CRDT. -}
  -> p {- ^ The initial participant. -}
  -> EventFold o p e
new :: forall o p e.
(Default (State e), Event p e, Ord p) =>
o -> p -> EventFold o p e
new o
o p
participant =
  EventFold {
    psOrigin :: o
psOrigin = o
o,
    psInfimum :: Infimum (State e) p
psInfimum = Infimum {
        eventId :: EventId p
eventId = EventId p
forall a. Default a => a
def,
        participants :: Set p
participants = p -> Set p
forall a. a -> Set a
Set.singleton p
participant,
        stateValue :: State e
stateValue = forall p e. Event p e => p -> State e -> State e
join @p @e p
participant State e
forall a. Default a => a
def
      },
    psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents = Map (EventId p) (Delta p e, Set p)
forall a. Monoid a => a
mempty,
    psUnjoins :: Set (EventId p)
psUnjoins = Set (EventId p)
forall a. Monoid a => a
mempty
  }


{- |
  Get the outstanding events that need to be propagated to a particular
  participant.

  It isn't always the case that a less expensive 'diffMerge' is sufficient
  to maintain consistency. For instance, if the initial 'participate'
  for a participant hasn't reached the infimum yet then there is no way
  to guarantee that the target will receive /every/ new event from every
  participant (because an old participant might not even know about the
  new participant, because being part of the infimum is the /definition/
  of all participants knowing a thing).

  If the new participant doesn't receive every event, then it obviously
  can't 'apply' the missing events. Therefore, until it's 'participate'
  event is part of the infimum, it must receive infimum values that have
  the missing events pre-applied by some other participant.
-}
events
  :: forall o p e. (Ord p)
  => p {- ^ The participant to which we are sending the 'Diff'. -}
  -> EventFold o p e {- ^ The EventFold being propagated. -}
  -> Maybe (Diff o p e)
     {- ^
       'Nothing' if the participant must perform a 'fullMerge' in order
       to maintain consistency. 'Just' if a less expensive 'diffMerge'
       will suffice.
     -}
events :: forall o p e. Ord p => p -> EventFold o p e -> Maybe (Diff o p e)
events p
peer EventFold o p e
ef =
    if
      Set p -> [(Delta p e, Set p)] -> Bool
diffOk
        (Infimum (State e) p -> Set p
forall s p. Infimum s p -> Set p
participants (EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum EventFold o p e
ef))
        ((EventId p, (Delta p e, Set p)) -> (Delta p e, Set p)
forall a b. (a, b) -> b
snd ((EventId p, (Delta p e, Set p)) -> (Delta p e, Set p))
-> [(EventId p, (Delta p e, Set p))] -> [(Delta p e, Set p)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Map (EventId p) (Delta p e, Set p)
-> [(EventId p, (Delta p e, Set p))]
forall k a. Map k a -> [(k, a)]
Map.toAscList (EventFold o p e -> Map (EventId p) (Delta p e, Set p)
forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents EventFold o p e
ef))
    then
      Diff o p e -> Maybe (Diff o p e)
forall a. a -> Maybe a
Just
        Diff {
          diffEvents :: Map (EventId p) (Maybe (Delta p e), Set p)
diffEvents = (Delta p e, Set p) -> (Maybe (Delta p e), Set p)
omitAcknowledged ((Delta p e, Set p) -> (Maybe (Delta p e), Set p))
-> Map (EventId p) (Delta p e, Set p)
-> Map (EventId p) (Maybe (Delta p e), Set p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> EventFold o p e -> Map (EventId p) (Delta p e, Set p)
forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents EventFold o p e
ef,
          diffOrigin :: o
diffOrigin = EventFold o p e -> o
forall o p e. EventFold o p e -> o
psOrigin EventFold o p e
ef,
          diffInfimum :: EventId p
diffInfimum = Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId (EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum EventFold o p e
ef),
          diffUnjoins :: Set (EventId p)
diffUnjoins = EventFold o p e -> Set (EventId p)
forall o p e. EventFold o p e -> Set (EventId p)
psUnjoins EventFold o p e
ef
        }
    else
      Maybe (Diff o p e)
forall a. Maybe a
Nothing
  where
    {- |
      Return 'True' if it is ok to send a diff. 'False' if a full merge
      must be performed.
    -}
    diffOk :: Set p -> [(Delta p e, Set p)] -> Bool
    diffOk :: Set p -> [(Delta p e, Set p)] -> Bool
diffOk Set p
accPeers [(Delta p e, Set p)]
someEvents =
        if p
peer p -> Set p -> Bool
forall a. Ord a => a -> Set a -> Bool
`member` Set p
accPeers then
          {-
            Even if the target is part of the infimum, we still have
            to make sure the target doesn't have an upcoming 'UnJoin'
            (regardless if it is followed by another 'Join', otherwise
            we would just use 'projParticipants').
          -}
          case [(Delta p e, Set p)]
someEvents of
            (Delta p e
e, Set p
_):[(Delta p e, Set p)]
more ->
              Set p -> [(Delta p e, Set p)] -> Bool
diffOk (Delta p e -> Set p
accumulatePeers Delta p e
e) [(Delta p e, Set p)]
more
            [] -> Bool
True
        else
          Bool
False
      where
        accumulatePeers :: Delta p e -> Set p
        accumulatePeers :: Delta p e -> Set p
accumulatePeers = \case
          UnJoin p
p -> p -> Set p -> Set p
forall a. Ord a => a -> Set a -> Set a
Set.delete p
p Set p
accPeers
          Delta p e
_ -> Set p
accPeers

    {- |
      Don't send the event data to participants which have already
      acknowledged it, saving network and cpu resources.
    -}
    omitAcknowledged :: (Delta p e, Set p) -> (Maybe (Delta p e), Set p)
omitAcknowledged (Delta p e
d, Set p
acks) =
      (
        case (Delta p e
d, p
peer p -> Set p -> Bool
forall a. Ord a => a -> Set a -> Bool
`member` Set p
acks) of
          (Error {}, Bool
_) -> Delta p e -> Maybe (Delta p e)
forall a. a -> Maybe a
Just Delta p e
d
          (Delta p e
_, Bool
False) -> Delta p e -> Maybe (Delta p e)
forall a. a -> Maybe a
Just Delta p e
d
          (Delta p e, Bool)
_ -> Maybe (Delta p e)
forall a. Maybe a
Nothing,
        Set p
acks
      )


{- | A package containing events that can be merged into an event fold. -}
data Diff o p e = Diff {
     forall o p e.
Diff o p e -> Map (EventId p) (Maybe (Delta p e), Set p)
diffEvents :: Map (EventId p) (Maybe (Delta p e), Set p),
     forall o p e. Diff o p e -> o
diffOrigin :: o,
    forall o p e. Diff o p e -> EventId p
diffInfimum :: EventId p,
    forall o p e. Diff o p e -> Set (EventId p)
diffUnjoins :: Set (EventId p)
  }
  deriving stock ((forall x. Diff o p e -> Rep (Diff o p e) x)
-> (forall x. Rep (Diff o p e) x -> Diff o p e)
-> Generic (Diff o p e)
forall x. Rep (Diff o p e) x -> Diff o p e
forall x. Diff o p e -> Rep (Diff o p e) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall o p e x. Rep (Diff o p e) x -> Diff o p e
forall o p e x. Diff o p e -> Rep (Diff o p e) x
$cfrom :: forall o p e x. Diff o p e -> Rep (Diff o p e) x
from :: forall x. Diff o p e -> Rep (Diff o p e) x
$cto :: forall o p e x. Rep (Diff o p e) x -> Diff o p e
to :: forall x. Rep (Diff o p e) x -> Diff o p e
Generic)
deriving stock instance (Eq o, Eq p, Eq e, Eq (Output e)) => Eq (Diff o p e)
deriving anyclass instance (ToJSON o, ToJSON p, ToJSON e, ToJSON (Output e)) => ToJSON (Diff o p e)
deriving anyclass instance (Ord p, FromJSON o, FromJSON p, FromJSON e, FromJSON (Output e)) => FromJSON (Diff o p e)
deriving stock instance (
    Show o, Show p, Show e, Show (Output e)
  ) =>
    Show (Diff o p e)
instance (
    Binary o, Binary p, Binary e, Binary (Output e)
  ) =>
    Binary (Diff o p e)


{- |
  Like 'fullMerge', but merge a remote 'Diff' instead of a full remote
  'EventFold'.
-}
diffMerge
  :: ( Eq (Output e)
     , Eq e
     , Eq o
     , Event p e
     , Ord p
     )
  => p {- ^ The "local" participant doing the merge. -}
  -> EventFold o p e {- ^ The local copy of the 'EventFold'. -}
  -> Diff o p e {- ^ The 'Diff' provided by the remote participant. -}
  -> Either
       (MergeError o p e)
       (UpdateResult o p e)

diffMerge :: forall e o p.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
p
-> EventFold o p e
-> Diff o p e
-> Either (MergeError o p e) (UpdateResult o p e)
diffMerge p
participant EventFold o p e
orig Diff o p e
ep =
  case EventFold o p e
-> Diff o p e -> Either (MergeError o p e) (UpdateResult o p e)
forall o p e.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
EventFold o p e
-> Diff o p e -> Either (MergeError o p e) (UpdateResult o p e)
diffMerge_ EventFold o p e
orig Diff o p e
ep of
    Left MergeError o p e
err -> MergeError o p e -> Either (MergeError o p e) (UpdateResult o p e)
forall a b. a -> Either a b
Left MergeError o p e
err
    Right (UpdateResult EventFold o p e
ef1 Map (EventId p) (Output e)
outputs1 Bool
prop1) ->
      let UpdateResult EventFold o p e
ef2 Map (EventId p) (Output e)
outputs2 Bool
prop2 = p -> EventFold o p e -> UpdateResult o p e
forall e o p.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
p -> EventFold o p e -> UpdateResult o p e
acknowledge p
participant EventFold o p e
ef1
      in
        UpdateResult o p e
-> Either (MergeError o p e) (UpdateResult o p e)
forall a b. b -> Either a b
Right (
          EventFold o p e
-> Map (EventId p) (Output e) -> Bool -> UpdateResult o p e
forall o p e.
EventFold o p e
-> Map (EventId p) (Output e) -> Bool -> UpdateResult o p e
UpdateResult
            EventFold o p e
ef2
            (Map (EventId p) (Output e)
-> Map (EventId p) (Output e) -> Map (EventId p) (Output e)
forall k a. Ord k => Map k a -> Map k a -> Map k a
Map.union Map (EventId p) (Output e)
outputs1 Map (EventId p) (Output e)
outputs2)
            (Bool
prop1 Bool -> Bool -> Bool
|| Bool
prop2)
        )


{- | Like 'diffMerge', but without automatic acknowledgement. -}
diffMerge_
  :: forall o p e.
     ( Eq (Output e)
     , Eq e
     , Eq o
     , Event p e
     , Ord p
     )
  => EventFold o p e {- ^ The local copy of the 'EventFold'. -}
  -> Diff o p e {- ^ The 'Diff' provided by the remote participant. -}
  -> Either
       (MergeError o p e)
       (UpdateResult o p e)

diffMerge_ :: forall o p e.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
EventFold o p e
-> Diff o p e -> Either (MergeError o p e) (UpdateResult o p e)
diffMerge_
    (EventFold {psOrigin :: forall o p e. EventFold o p e -> o
psOrigin = o
o1})
    Diff {diffOrigin :: forall o p e. Diff o p e -> o
diffOrigin = o
o2}
  | o
o1 o -> o -> Bool
forall a. Eq a => a -> a -> Bool
/= o
o2 =
    MergeError o p e -> Either (MergeError o p e) (UpdateResult o p e)
forall a b. a -> Either a b
Left (o -> o -> MergeError o p e
forall o p e. o -> o -> MergeError o p e
DifferentOrigins o
o1 o
o2)

diffMerge_ EventFold o p e
ef Diff o p e
pak | Bool
tooNew =
    MergeError o p e -> Either (MergeError o p e) (UpdateResult o p e)
forall a b. a -> Either a b
Left (EventFold o p e -> Diff o p e -> MergeError o p e
forall o p e. EventFold o p e -> Diff o p e -> MergeError o p e
DiffTooNew EventFold o p e
ef Diff o p e
pak)
  where
    maxState :: EventId p
maxState =
      Set (EventId p) -> EventId p
forall a. Ord a => Set a -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum
      (Set (EventId p) -> EventId p)
-> (EventFold o p e -> Set (EventId p))
-> EventFold o p e
-> EventId p
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EventId p -> Set (EventId p) -> Set (EventId p)
forall a. Ord a => a -> Set a -> Set a
Set.insert (Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId (Infimum (State e) p -> EventId p)
-> (EventFold o p e -> Infimum (State e) p)
-> EventFold o p e
-> EventId p
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum (EventFold o p e -> EventId p) -> EventFold o p e -> EventId p
forall a b. (a -> b) -> a -> b
$ EventFold o p e
ef)
      (Set (EventId p) -> Set (EventId p))
-> (EventFold o p e -> Set (EventId p))
-> EventFold o p e
-> Set (EventId p)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map (EventId p) (Delta p e, Set p) -> Set (EventId p)
forall k a. Map k a -> Set k
Map.keysSet
      (Map (EventId p) (Delta p e, Set p) -> Set (EventId p))
-> (EventFold o p e -> Map (EventId p) (Delta p e, Set p))
-> EventFold o p e
-> Set (EventId p)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents
      (EventFold o p e -> EventId p) -> EventFold o p e -> EventId p
forall a b. (a -> b) -> a -> b
$ EventFold o p e
ef

    tooNew :: Bool
    tooNew :: Bool
tooNew = EventId p
maxState EventId p -> EventId p -> Bool
forall a. Ord a => a -> a -> Bool
< Diff o p e -> EventId p
forall o p e. Diff o p e -> EventId p
diffInfimum Diff o p e
pak

diffMerge_
    orig :: EventFold o p e
orig@(EventFold o
o Infimum (State e) p
infimum Map (EventId p) (Delta p e, Set p)
d1 Set (EventId p)
unjoins)
    diff :: Diff o p e
diff@(Diff Map (EventId p) (Maybe (Delta p e), Set p)
d2 o
_ EventId p
i2 Set (EventId p)
diffUnjoins)
  =
    let
      mergedEvents :: Maybe (Map (EventId p) (Delta p e, Set p))
      mergedEvents :: Maybe (Map (EventId p) (Delta p e, Set p))
mergedEvents =
        WhenMissing Maybe (EventId p) (Delta p e, Set p) (Delta p e, Set p)
-> WhenMissing
     Maybe (EventId p) (Maybe (Delta p e), Set p) (Delta p e, Set p)
-> WhenMatched
     Maybe
     (EventId p)
     (Delta p e, Set p)
     (Maybe (Delta p e), Set p)
     (Delta p e, Set p)
-> Map (EventId p) (Delta p e, Set p)
-> Map (EventId p) (Maybe (Delta p e), Set p)
-> Maybe (Map (EventId p) (Delta p e, Set p))
forall (f :: * -> *) k a c b.
(Applicative f, Ord k) =>
WhenMissing f k a c
-> WhenMissing f k b c
-> WhenMatched f k a b c
-> Map k a
-> Map k b
-> f (Map k c)
Map.Merge.mergeA
          WhenMissing Maybe (EventId p) (Delta p e, Set p) (Delta p e, Set p)
forall (f :: * -> *) k x. Applicative f => WhenMissing f k x x
Map.Merge.preserveMissing
          ((EventId p
 -> (Maybe (Delta p e), Set p) -> Maybe (Maybe (Delta p e, Set p)))
-> WhenMissing
     Maybe (EventId p) (Maybe (Delta p e), Set p) (Delta p e, Set p)
forall (f :: * -> *) k x y.
Applicative f =>
(k -> x -> f (Maybe y)) -> WhenMissing f k x y
Map.Merge.traverseMaybeMissing EventId p
-> (Maybe (Delta p e), Set p) -> Maybe (Maybe (Delta p e, Set p))
forall a b. EventId p -> (Maybe a, b) -> Maybe (Maybe (a, b))
includeDiffEvents)
          ((EventId p
 -> (Delta p e, Set p)
 -> (Maybe (Delta p e), Set p)
 -> (Delta p e, Set p))
-> WhenMatched
     Maybe
     (EventId p)
     (Delta p e, Set p)
     (Maybe (Delta p e), Set p)
     (Delta p e, Set p)
forall (f :: * -> *) k x y z.
Applicative f =>
(k -> x -> y -> z) -> WhenMatched f k x y z
Map.Merge.zipWithMatched (((Delta p e, Set p)
 -> (Maybe (Delta p e), Set p) -> (Delta p e, Set p))
-> EventId p
-> (Delta p e, Set p)
-> (Maybe (Delta p e), Set p)
-> (Delta p e, Set p)
forall a b. a -> b -> a
const (Delta p e, Set p)
-> (Maybe (Delta p e), Set p) -> (Delta p e, Set p)
mergeAcks))
          Map (EventId p) (Delta p e, Set p)
d1
          Map (EventId p) (Maybe (Delta p e), Set p)
d2
    in
      case Maybe (Map (EventId p) (Delta p e, Set p))
mergedEvents of
        Maybe (Map (EventId p) (Delta p e, Set p))
Nothing -> MergeError o p e -> Either (MergeError o p e) (UpdateResult o p e)
forall a b. a -> Either a b
Left (EventFold o p e -> Diff o p e -> MergeError o p e
forall o p e. EventFold o p e -> Diff o p e -> MergeError o p e
DiffTooSparse EventFold o p e
orig Diff o p e
diff)
        Just Map (EventId p) (Delta p e, Set p)
events_ ->
          let
            (EventFold o p e
ef, Map (EventId p) (Output e)
outputs) =
              EventId p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
forall o p e.
(Event p e, Ord p) =>
EventId p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
reduce
                EventId p
i2
                EventFold {
                  psOrigin :: o
psOrigin = o
o,
                  psInfimum :: Infimum (State e) p
psInfimum = Infimum (State e) p
infimum,
                  psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents = Map (EventId p) (Delta p e, Set p)
events_,
                  psUnjoins :: Set (EventId p)
psUnjoins = Set (EventId p)
unjoins Set (EventId p) -> Set (EventId p) -> Set (EventId p)
forall a. Ord a => Set a -> Set a -> Set a
`Set.union` Set (EventId p)
diffUnjoins
                }
          in
            UpdateResult o p e
-> Either (MergeError o p e) (UpdateResult o p e)
forall a b. b -> Either a b
Right (
              EventFold o p e
-> Map (EventId p) (Output e) -> Bool -> UpdateResult o p e
forall o p e.
EventFold o p e
-> Map (EventId p) (Output e) -> Bool -> UpdateResult o p e
UpdateResult
                EventFold o p e
ef
                Map (EventId p) (Output e)
outputs
                (
                  EventId p
i2 EventId p -> EventId p -> Bool
forall a. Eq a => a -> a -> Bool
/= Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId Infimum (State e) p
infimum
                  Bool -> Bool -> Bool
|| Bool -> Bool
not (Map (EventId p) (Maybe (Delta p e), Set p) -> Bool
forall k a. Map k a -> Bool
Map.null Map (EventId p) (Maybe (Delta p e), Set p)
d2)
                  Bool -> Bool -> Bool
|| EventFold o p e
ef EventFold o p e -> EventFold o p e -> Bool
forall a. Eq a => a -> a -> Bool
/= EventFold o p e
orig
                )
            )
  where
    includeDiffEvents :: EventId p -> (Maybe a, b) -> Maybe (Maybe (a, b))
    includeDiffEvents :: forall a b. EventId p -> (Maybe a, b) -> Maybe (Maybe (a, b))
includeDiffEvents EventId p
eid (Maybe a
md, b
acks) =
      {-
        Don't consider diff events that are behind the infimum of the
        EventFold being updated.
      -}
      if EventId p
eid EventId p -> EventId p -> Bool
forall a. Ord a => a -> a -> Bool
<= Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId Infimum (State e) p
infimum
        then
          {- Don't incude the key, but also don't fail the merge. -}
          Maybe (a, b) -> Maybe (Maybe (a, b))
forall a. a -> Maybe a
Just Maybe (a, b)
forall a. Maybe a
Nothing
        else
          case Maybe a
md of
            Maybe a
Nothing ->
              {-
                The diff assumes this replica has knowledge of the event,
                but it does not. Fail the merge.
              -}
              Maybe (Maybe (a, b))
forall a. Maybe a
Nothing
            Just a
d ->
              Maybe (a, b) -> Maybe (Maybe (a, b))
forall a. a -> Maybe a
Just (Maybe (a, b) -> Maybe (Maybe (a, b)))
-> Maybe (a, b) -> Maybe (Maybe (a, b))
forall a b. (a -> b) -> a -> b
$ (a, b) -> Maybe (a, b)
forall a. a -> Maybe a
Just (a
d, b
acks)

    mergeAcks
      :: (Delta p e, Set p)
      -> (Maybe (Delta p e), Set p)
      -> (Delta p e, Set p)
    mergeAcks :: (Delta p e, Set p)
-> (Maybe (Delta p e), Set p) -> (Delta p e, Set p)
mergeAcks
        (Error Output e
output Set p
eacks1, Set p
acks1)
        (Just (Error Output e
_ Set p
eacks2), Set p
acks2)
      =
        (Output e -> Set p -> Delta p e
forall p e. Output e -> Set p -> Delta p e
Error Output e
output (Set p
eacks1 Set p -> Set p -> Set p
forall a. Ord a => Set a -> Set a -> Set a
`union` Set p
eacks2), Set p
acks1 Set p -> Set p -> Set p
forall a. Ord a => Set a -> Set a -> Set a
`union` Set p
acks2)
    mergeAcks
        left :: (Delta p e, Set p)
left@(Error {}, Set p
acks1)
        (Maybe (Delta p e)
md, Set p
acks2)
      =
        case Maybe (Delta p e)
md of
          Maybe (Delta p e)
Nothing -> (Delta p e, Set p)
left
          Just Delta p e
d ->
            (Delta p e
d, Set p
acks1 Set p -> Set p -> Set p
forall a. Ord a => Set a -> Set a -> Set a
`union` Set p
acks2)
    mergeAcks
        (Delta p e
d, Set p
acks1)
        (Just Delta p e
_, Set p
acks2)
      =
        (Delta p e
d, Set p
acks1 Set p -> Set p -> Set p
forall a. Ord a => Set a -> Set a -> Set a
`union` Set p
acks2)
    mergeAcks
        (Delta p e
d, Set p
acks1)
        (Maybe (Delta p e)
Nothing, Set p
acks2)
      =
        (Delta p e
d, Set p
acks1 Set p -> Set p -> Set p
forall a. Ord a => Set a -> Set a -> Set a
`union` Set p
acks2)


{- |
  Monotonically merge the information in two 'EventFold's.  The resulting
  'EventFold' may have a higher infimum value, but it will never have a
  lower one (where "higher" and "lower" are measured by 'infimumId' value,
  not the value of the underlying data structure). Only 'EventFold's
  that originated from the same 'new' call can be merged. If the origins
  are mismatched, or if there is some other programming error detected,
  then an error will be returned.

  Returns the new 'EventFold' value, along with the output for all of
  the events that can now be considered "fully consistent".
-}
fullMerge
  :: ( Eq (Output e)
     , Eq e
     , Eq o
     , Event p e
     , Ord p
     )
  => p {- ^ The "local" participant doing the merge. -}
  -> EventFold o p e {- ^ The local copy of the 'EventFold'. -}
  -> EventFold o p e {- ^ The remote copy of the 'Eventfold'. -}
  -> Either (MergeError o p e) (UpdateResult o p e)
fullMerge :: forall e o p.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
p
-> EventFold o p e
-> EventFold o p e
-> Either (MergeError o p e) (UpdateResult o p e)
fullMerge p
participant EventFold o p e
left EventFold o p e
right =
  case EventFold o p e
-> EventFold o p e
-> Either (MergeError o p e) (UpdateResult o p e)
forall e o p.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
EventFold o p e
-> EventFold o p e
-> Either (MergeError o p e) (UpdateResult o p e)
fullMerge_ EventFold o p e
left EventFold o p e
right of
    Left MergeError o p e
err -> MergeError o p e -> Either (MergeError o p e) (UpdateResult o p e)
forall a b. a -> Either a b
Left MergeError o p e
err
    Right (UpdateResult EventFold o p e
ef1 Map (EventId p) (Output e)
outputs1 Bool
_) ->
      let UpdateResult EventFold o p e
ef2 Map (EventId p) (Output e)
outputs2 Bool
_ = p -> EventFold o p e -> UpdateResult o p e
forall e o p.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
p -> EventFold o p e -> UpdateResult o p e
acknowledge p
participant EventFold o p e
ef1
      in
        UpdateResult o p e
-> Either (MergeError o p e) (UpdateResult o p e)
forall a b. b -> Either a b
Right (
          EventFold o p e
-> Map (EventId p) (Output e) -> Bool -> UpdateResult o p e
forall o p e.
EventFold o p e
-> Map (EventId p) (Output e) -> Bool -> UpdateResult o p e
UpdateResult
            EventFold o p e
ef2
            (Map (EventId p) (Output e)
-> Map (EventId p) (Output e) -> Map (EventId p) (Output e)
forall k a. Ord k => Map k a -> Map k a -> Map k a
Map.union Map (EventId p) (Output e)
outputs1 Map (EventId p) (Output e)
outputs2)
            (EventFold o p e
ef2 EventFold o p e -> EventFold o p e -> Bool
forall a. Eq a => a -> a -> Bool
/= EventFold o p e
left Bool -> Bool -> Bool
|| EventFold o p e
ef2 EventFold o p e -> EventFold o p e -> Bool
forall a. Eq a => a -> a -> Bool
/= EventFold o p e
right)
        )


{- | Like 'fullMerge', but without the automatic acknowlegement.  -}
fullMerge_
  :: ( Eq (Output e)
     , Eq e
     , Eq o
     , Event p e
     , Ord p
     )
  => EventFold o p e {- ^ The local copy of the 'EventFold'. -}
  -> EventFold o p e {- ^ The remote copy of the 'Eventfold'. -}
  -> Either (MergeError o p e) (UpdateResult o p e)
fullMerge_ :: forall e o p.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
EventFold o p e
-> EventFold o p e
-> Either (MergeError o p e) (UpdateResult o p e)
fullMerge_ EventFold o p e
left right :: EventFold o p e
right@(EventFold o
o2 Infimum (State e) p
i2 Map (EventId p) (Delta p e, Set p)
d2 Set (EventId p)
unjoins) =
  case
    EventFold o p e
-> Diff o p e -> Either (MergeError o p e) (UpdateResult o p e)
forall o p e.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
EventFold o p e
-> Diff o p e -> Either (MergeError o p e) (UpdateResult o p e)
diffMerge_
      EventFold o p e
left {
        psInfimum = max (psInfimum left) i2
      }
      Diff {
        diffOrigin :: o
diffOrigin = o
o2,
        diffEvents :: Map (EventId p) (Maybe (Delta p e), Set p)
diffEvents = (Delta p e -> Maybe (Delta p e))
-> (Delta p e, Set p) -> (Maybe (Delta p e), Set p)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Delta p e -> Maybe (Delta p e)
forall a. a -> Maybe a
Just ((Delta p e, Set p) -> (Maybe (Delta p e), Set p))
-> Map (EventId p) (Delta p e, Set p)
-> Map (EventId p) (Maybe (Delta p e), Set p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Map (EventId p) (Delta p e, Set p)
d2,
        diffInfimum :: EventId p
diffInfimum = Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId Infimum (State e) p
i2,
        diffUnjoins :: Set (EventId p)
diffUnjoins = Set (EventId p)
unjoins
      }
  of
    Left MergeError o p e
err -> MergeError o p e -> Either (MergeError o p e) (UpdateResult o p e)
forall a b. a -> Either a b
Left MergeError o p e
err
    Right (UpdateResult EventFold o p e
ef Map (EventId p) (Output e)
outputs Bool
_prop) ->
      UpdateResult o p e
-> Either (MergeError o p e) (UpdateResult o p e)
forall a b. b -> Either a b
Right (
        EventFold o p e
-> Map (EventId p) (Output e) -> Bool -> UpdateResult o p e
forall o p e.
EventFold o p e
-> Map (EventId p) (Output e) -> Bool -> UpdateResult o p e
UpdateResult
          EventFold o p e
ef
          Map (EventId p) (Output e)
outputs
          (EventFold o p e
ef EventFold o p e -> EventFold o p e -> Bool
forall a. Eq a => a -> a -> Bool
/= EventFold o p e
left Bool -> Bool -> Bool
|| EventFold o p e
ef EventFold o p e -> EventFold o p e -> Bool
forall a. Eq a => a -> a -> Bool
/= EventFold o p e
right)
      )


{- |
  The result updating the 'EventFold', which contains:

  - The new 'EventFold' value,
  - The outputs of events that have reached the infimum as a result of
    the update (i.e. "totally consistent outputs"),
  - And a flag indicating whether the other participants need to hear
    about the changes.
-}
data UpdateResult o p e = UpdateResult
  {        forall o p e. UpdateResult o p e -> EventFold o p e
urEventFold :: EventFold o p e
                          {- ^ The new 'EventFold' value -}
  ,          forall o p e. UpdateResult o p e -> Map (EventId p) (Output e)
urOutputs :: Map (EventId p) (Output e)
                          {- ^
                            Any consistent outputs resulting from
                            the update.
                          -}
  , forall o p e. UpdateResult o p e -> Bool
urNeedsPropagation :: Bool
                          {- ^
                            'True' if any new information was added to
                            the 'EventFold' which might need propagating
                            to other participants.
                          -}
  }
deriving stock instance
  ( Show (Output e)
  , Show (State e)
  , Show e
  , Show o
  , Show p
  )
  => Show (UpdateResult o p e)


{- |
  Record the fact that the participant acknowledges the information
  contained in the 'EventFold'. The implication is that the participant
  __must__ base all future operations on the result of this function.

  Returns the new 'EventFold' value, along with the output for all of
  the events that can now be considered "fully consistent".
-}
acknowledge
  :: ( Eq (Output e)
     , Eq e
     , Eq o
     , Event p e
     , Ord p
     )
  => p
  -> EventFold o p e
  -> UpdateResult o p e
acknowledge :: forall e o p.
(Eq (Output e), Eq e, Eq o, Event p e, Ord p) =>
p -> EventFold o p e -> UpdateResult o p e
acknowledge p
p EventFold o p e
ef =
  let (EventFold o p e
ef2, Map (EventId p) (Output e)
outputs) = p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
forall p e o.
(Event p e, Ord p) =>
p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
acknowledge_ p
p EventFold o p e
ef
  in
    UpdateResult {
      urEventFold :: EventFold o p e
urEventFold = EventFold o p e
ef2,
      urOutputs :: Map (EventId p) (Output e)
urOutputs = Map (EventId p) (Output e)
outputs,
      urNeedsPropagation :: Bool
urNeedsPropagation = EventFold o p e
ef EventFold o p e -> EventFold o p e -> Bool
forall a. Eq a => a -> a -> Bool
/= EventFold o p e
ef2
    }


{- | Internal version of 'acknowledge'. -}
acknowledge_
  :: ( Event p e
     , Ord p
     )
  => p
  -> EventFold o p e
  -> (EventFold o p e, Map (EventId p) (Output e))
acknowledge_ :: forall p e o.
(Event p e, Ord p) =>
p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
acknowledge_ p
p EventFold o p e
ef =
    {-
      First do a normal reduction, then do a special acknowledgement of the
      reduction error, if any.
    -}
    let
      (EventFold o p e
ps2, Map (EventId p) (Output e)
outputs) =
        EventId p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
forall o p e.
(Event p e, Ord p) =>
EventId p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
reduce
          (Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId (EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum EventFold o p e
ef))
          EventFold o p e
ef {psEvents = fmap ackOne (psEvents ef)}
      (EventFold o p e
ps3, Map (EventId p) (Output e)
outputs2) = p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
forall p e o.
(Event p e, Ord p) =>
p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
ackErr p
p EventFold o p e
ps2
    in
      (EventFold o p e
ps3, Map (EventId p) (Output e)
outputs Map (EventId p) (Output e)
-> Map (EventId p) (Output e) -> Map (EventId p) (Output e)
forall a. Semigroup a => a -> a -> a
<> Map (EventId p) (Output e)
outputs2)
  where
    ackOne :: (Delta p e, Set p) -> (Delta p e, Set p)
ackOne (Delta p e
e, Set p
acks) = (Delta p e
e, p -> Set p -> Set p
forall a. Ord a => a -> Set a -> Set a
Set.insert p
p Set p
acks)


{- | Acknowledge the reduction error, if one exists. -}
ackErr
  :: ( Event p e
     , Ord p
     )
  => p
  -> EventFold o p e
  -> (EventFold o p e, Map (EventId p) (Output e))
ackErr :: forall p e o.
(Event p e, Ord p) =>
p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
ackErr p
p EventFold o p e
ef =
  case Map (EventId p) (Delta p e, Set p)
-> Maybe
     ((EventId p, (Delta p e, Set p)),
      Map (EventId p) (Delta p e, Set p))
forall k a. Map k a -> Maybe ((k, a), Map k a)
Map.minViewWithKey (EventFold o p e -> Map (EventId p) (Delta p e, Set p)
forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents EventFold o p e
ef) of
    Just ((EventId p
eid, (Error Output e
o Set p
eacks, Set p
acks)), Map (EventId p) (Delta p e, Set p)
deltas) ->
      EventId p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
forall o p e.
(Event p e, Ord p) =>
EventId p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
reduce
        (Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId (EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum EventFold o p e
ef))
        EventFold o p e
ef {
          psEvents =
            Map.insert
              eid
              (Error o (Set.insert p eacks), acks)
              deltas
        }
    Maybe
  ((EventId p, (Delta p e, Set p)),
   Map (EventId p) (Delta p e, Set p))
_ -> (EventFold o p e
ef, Map (EventId p) (Output e)
forall a. Monoid a => a
mempty)


{- |
  Allow a participant to join in the distributed nature of the
  'EventFold'. Return the 'EventId' at which the participation is
  recorded, and the resulting 'EventFold'. The purpose of returning the
  'EventId' is so that you can use it to tell when the participation
  event has reached the infimum. See also: 'infimumId'
-}
participate
  :: forall o p e.
     ( Event p e
     , Ord p
     )
  => p {- ^ The local participant. -}
  -> p {- ^ The participant being added. -}
  -> EventFold o p e
  -> (EventId p, UpdateResult o p e)
participate :: forall o p e.
(Event p e, Ord p) =>
p -> p -> EventFold o p e -> (EventId p, UpdateResult o p e)
participate p
self p
peer EventFold o p e
ef =
    (
      EventId p
eid,
      let
        (EventFold o p e
ef2, Map (EventId p) (Output e)
outputs) =
          p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
forall p e o.
(Event p e, Ord p) =>
p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
acknowledge_
            p
self
            EventFold o p e
ef {
              psEvents =
                Map.insert
                  eid
                  (Join peer, mempty)
                  (psEvents ef)
            }
      in
        UpdateResult {
          urEventFold :: EventFold o p e
urEventFold = EventFold o p e
ef2,
          urOutputs :: Map (EventId p) (Output e)
urOutputs = Map (EventId p) (Output e)
outputs,
          {-
            By definition, we have added some new information that
            needs propagating.
          -}
          urNeedsPropagation :: Bool
urNeedsPropagation = Bool
True
        }
    )
  where
    eid :: EventId p
    eid :: EventId p
eid = p -> EventFold o p e -> EventId p
forall o p e. p -> EventFold o p e -> EventId p
nextId p
self EventFold o p e
ef


{- |
  Indicate that a participant is removing itself from participating in
  the distributed 'EventFold'.
-}
disassociate
  :: forall o p e.
     ( Event p e
     , Ord p
     )
  => p {- ^ The peer removing itself from participation. -}
  -> EventFold o p e
  -> (EventId p, UpdateResult o p e)
disassociate :: forall o p e.
(Event p e, Ord p) =>
p -> EventFold o p e -> (EventId p, UpdateResult o p e)
disassociate p
peer EventFold o p e
ef =
    let
      (EventFold o p e
ef2, Map (EventId p) (Output e)
outputs) =
        p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
forall p e o.
(Event p e, Ord p) =>
p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
acknowledge_
          p
peer
          EventFold o p e
ef {
            psEvents =
              Map.insert
                eid
                (UnJoin peer, mempty)
                (psEvents ef),
            psUnjoins = Set.insert eid (psUnjoins ef)
          }
    in
      (
        EventId p
eid,
        UpdateResult {
          urEventFold :: EventFold o p e
urEventFold = EventFold o p e
ef2,
          urOutputs :: Map (EventId p) (Output e)
urOutputs = Map (EventId p) (Output e)
outputs,
          {-
            By definition, we have added some new information that
            needs propagating.
          -}
          urNeedsPropagation :: Bool
urNeedsPropagation = Bool
True
        }
      )
  where
    eid :: EventId p
    eid :: EventId p
eid = p -> EventFold o p e -> EventId p
forall o p e. p -> EventFold o p e -> EventId p
nextId p
peer EventFold o p e
ef


{- |
  Introduce a change to the EventFold on behalf of the participant.
  Return the new 'EventFold', along with the projected output of the
  event, along with an 'EventId' which can be used to get the fully
  consistent event output at a later time.
-}
event
  :: forall o p e.
     ( Event p e
     , Ord p
     )
  => p
  -> e
  -> EventFold o p e
  -> (Output e, EventId p, UpdateResult o p e)
event :: forall o p e.
(Event p e, Ord p) =>
p
-> e
-> EventFold o p e
-> (Output e, EventId p, UpdateResult o p e)
event p
p e
e EventFold o p e
ef =
  let
    eid :: EventId p
eid = p -> EventFold o p e -> EventId p
forall o p e. p -> EventFold o p e -> EventId p
nextId p
p EventFold o p e
ef
  in
    (
      case forall p e. Event p e => e -> State e -> EventResult e
apply @p e
e (EventFold o p e -> State e
forall o p e. Event p e => EventFold o p e -> State e
projectedValue EventFold o p e
ef) of
        Pure Output e
output State e
_ -> Output e
output
        SystemError Output e
output -> Output e
output,
      EventId p
eid,
      let
        (EventFold o p e
ef2, Map (EventId p) (Output e)
outputs) =
          EventId p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
forall o p e.
(Event p e, Ord p) =>
EventId p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
reduce
            (Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId (EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum EventFold o p e
ef))
            (
              EventFold o p e
ef {
                psEvents =
                  Map.insert
                    eid
                    (EventD e, Set.singleton p)
                    (psEvents ef)
              }
            )
      in
        UpdateResult {
          urEventFold :: EventFold o p e
urEventFold = EventFold o p e
ef2,
          urOutputs :: Map (EventId p) (Output e)
urOutputs = Map (EventId p) (Output e)
outputs,
          urNeedsPropagation :: Bool
urNeedsPropagation =
            {-
              An event is, by definition, adding information to the 'EventFold',
              and the only time we might not need to propagate this this
              information is if the local participant is the only participant.
            -}
            EventFold o p e -> Set p
forall p o e. Ord p => EventFold o p e -> Set p
allParticipants EventFold o p e
ef2 Set p -> Set p -> Bool
forall a. Eq a => a -> a -> Bool
/= p -> Set p
forall a. a -> Set a
Set.singleton p
p
        }
    )


{- | Return the current projected value of the 'EventFold'. -}
projectedValue :: forall o p e. (Event p e) => EventFold o p e -> State e
projectedValue :: forall o p e. Event p e => EventFold o p e -> State e
projectedValue
    EventFold {
      psInfimum :: forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum = Infimum {State e
stateValue :: forall s p. Infimum s p -> s
stateValue :: State e
stateValue},
      Map (EventId p) (Delta p e, Set p)
psEvents :: forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents
    }
  =
    (Delta p e -> State e -> State e)
-> State e -> [Delta p e] -> State e
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr
      Delta p e -> State e -> State e
applyDelta
      State e
stateValue
      [Delta p e]
changes
  where
    applyDelta :: Delta p e -> State e -> State e
    applyDelta :: Delta p e -> State e -> State e
applyDelta Delta p e
d State e
s =
      case Delta p e
d of
        Join p
p -> forall p e. Event p e => p -> State e -> State e
join @p @e p
p State e
s
        UnJoin p
p -> forall p e. Event p e => p -> State e -> State e
unjoin @p @e p
p State e
s
        EventD e
e ->
          case forall p e. Event p e => e -> State e -> EventResult e
apply @p e
e State e
s of
            Pure Output e
_ State e
newState -> State e
newState
            SystemError Output e
_ -> State e
s
        Error{} -> State e
s

    changes :: [Delta p e]
    changes :: [Delta p e]
changes = (Delta p e, Set p) -> Delta p e
forall a b. (a, b) -> a
fst ((Delta p e, Set p) -> Delta p e)
-> ((EventId p, (Delta p e, Set p)) -> (Delta p e, Set p))
-> (EventId p, (Delta p e, Set p))
-> Delta p e
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (EventId p, (Delta p e, Set p)) -> (Delta p e, Set p)
forall a b. (a, b) -> b
snd ((EventId p, (Delta p e, Set p)) -> Delta p e)
-> [(EventId p, (Delta p e, Set p))] -> [Delta p e]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Map (EventId p) (Delta p e, Set p)
-> [(EventId p, (Delta p e, Set p))]
forall k a. Map k a -> [(k, a)]
toDescList Map (EventId p) (Delta p e, Set p)
psEvents


{- | Return the current infimum value of the 'EventFold'. -}
infimumValue :: EventFold o p e -> State e
infimumValue :: forall o p e. EventFold o p e -> State e
infimumValue EventFold {psInfimum :: forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum = Infimum {State e
stateValue :: forall s p. Infimum s p -> s
stateValue :: State e
stateValue}} =
  State e
stateValue


{- | Return the 'EventId' of the infimum value. -}
infimumId :: EventFold o p e -> EventId p
infimumId :: forall o p e. EventFold o p e -> EventId p
infimumId = Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId (Infimum (State e) p -> EventId p)
-> (EventFold o p e -> Infimum (State e) p)
-> EventFold o p e
-> EventId p
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum


{- | Gets the known participants at the infimum. -}
infimumParticipants :: EventFold o p e -> Set p
infimumParticipants :: forall o p e. EventFold o p e -> Set p
infimumParticipants
    EventFold {
      psInfimum :: forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum = Infimum {Set p
participants :: forall s p. Infimum s p -> Set p
participants :: Set p
participants}
    }
  =
    Set p
participants


{- |
  Get all known participants. This includes participants that are
  projected for removal.
-}
allParticipants :: (Ord p) => EventFold o p e -> Set p
allParticipants :: forall p o e. Ord p => EventFold o p e -> Set p
allParticipants
    EventFold {
      psInfimum :: forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum = Infimum {Set p
participants :: forall s p. Infimum s p -> Set p
participants :: Set p
participants},
      Map (EventId p) (Delta p e, Set p)
psEvents :: forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents
    }
  =
    ((EventId p, (Delta p e, Set p)) -> Set p -> Set p)
-> Set p -> [(EventId p, (Delta p e, Set p))] -> Set p
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (EventId p, (Delta p e, Set p)) -> Set p -> Set p
forall p e.
Ord p =>
(EventId p, (Delta p e, Set p)) -> Set p -> Set p
updateParticipants Set p
participants (Map (EventId p) (Delta p e, Set p)
-> [(EventId p, (Delta p e, Set p))]
forall k a. Map k a -> [(k, a)]
toDescList Map (EventId p) (Delta p e, Set p)
psEvents)
  where
    updateParticipants :: (Ord p)
      => (EventId p, (Delta p e, Set p))
      -> Set p
      -> Set p
    updateParticipants :: forall p e.
Ord p =>
(EventId p, (Delta p e, Set p)) -> Set p -> Set p
updateParticipants (EventId p
_, (Join p
p, Set p
_)) = p -> Set p -> Set p
forall a. Ord a => a -> Set a -> Set a
Set.insert p
p
    updateParticipants (EventId p, (Delta p e, Set p))
_ = Set p -> Set p
forall a. a -> a
id


{- |
  Get all the projected participants. This does not include participants that
  are projected for removal.
-}
projParticipants :: (Ord p) => EventFold o p e -> Set p
projParticipants :: forall p o e. Ord p => EventFold o p e -> Set p
projParticipants
    EventFold {
      psInfimum :: forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum = Infimum {Set p
participants :: forall s p. Infimum s p -> Set p
participants :: Set p
participants},
      Map (EventId p) (Delta p e, Set p)
psEvents :: forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents
    }
  =
    ((EventId p, (Delta p e, Set p)) -> Set p -> Set p)
-> Set p -> [(EventId p, (Delta p e, Set p))] -> Set p
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (EventId p, (Delta p e, Set p)) -> Set p -> Set p
forall p e.
Ord p =>
(EventId p, (Delta p e, Set p)) -> Set p -> Set p
updateParticipants Set p
participants (Map (EventId p) (Delta p e, Set p)
-> [(EventId p, (Delta p e, Set p))]
forall k a. Map k a -> [(k, a)]
toDescList Map (EventId p) (Delta p e, Set p)
psEvents)
  where
    updateParticipants :: (Ord p)
      => (EventId p, (Delta p e, Set p))
      -> Set p
      -> Set p
    updateParticipants :: forall p e.
Ord p =>
(EventId p, (Delta p e, Set p)) -> Set p -> Set p
updateParticipants (EventId p
_, (Join p
p, Set p
_)) = p -> Set p -> Set p
forall a. Ord a => a -> Set a -> Set a
Set.insert p
p
    updateParticipants (EventId p
_, (UnJoin p
p, Set p
_)) = p -> Set p -> Set p
forall a. Ord a => a -> Set a -> Set a
Set.delete p
p
    updateParticipants (EventId p, (Delta p e, Set p))
_ = Set p -> Set p
forall a. a -> a
id


{- |
  Returns the participants that we think might be diverging. In
  this context, a participant is "diverging" if there is an event
  that the participant has not acknowledged but we are expecting it
  to acknowledge. Along with the participant, return the last known
  `EventId` which that participant has acknowledged, or 'BottomEid'
  if the participant has a acknowledged no events, as may be the case
  immediately after the participant joined replication.
-}
divergent :: forall o p e. (Ord p) => EventFold o p e -> Map p (EventId p)
divergent :: forall o p e. Ord p => EventFold o p e -> Map p (EventId p)
divergent
    EventFold {
      psInfimum :: forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum = Infimum {Set p
participants :: forall s p. Infimum s p -> Set p
participants :: Set p
participants, EventId p
eventId :: forall s p. Infimum s p -> EventId p
eventId :: EventId p
eventId},
      Map (EventId p) (Delta p e, Set p)
psEvents :: forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents
    }
  =
    let (Map p (EventId p)
byParticipant, EventId p
maxEid) = (Map p (EventId p), EventId p)
eidByParticipant
    in (EventId p -> Bool) -> Map p (EventId p) -> Map p (EventId p)
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter (EventId p -> EventId p -> Bool
forall a. Ord a => a -> a -> Bool
< EventId p
maxEid) Map p (EventId p)
byParticipant

  where
    eidByParticipant :: (Map p (EventId p), EventId p)
    eidByParticipant :: (Map p (EventId p), EventId p)
eidByParticipant =
      ((EventId p, Delta p e, Set p)
 -> (Map p (EventId p), EventId p)
 -> (Map p (EventId p), EventId p))
-> (Map p (EventId p), EventId p)
-> [(EventId p, Delta p e, Set p)]
-> (Map p (EventId p), EventId p)
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr
        (EventId p, Delta p e, Set p)
-> (Map p (EventId p), EventId p) -> (Map p (EventId p), EventId p)
accum
        (
          [(p, EventId p)] -> Map p (EventId p)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(p
p, EventId p
eventId) | p
p <- Set p -> [p]
forall a. Set a -> [a]
Set.toList Set p
participants],
          EventId p
eventId
        )
        (
          let flatten :: (a, (b, c)) -> (a, b, c)
flatten (a
a, (b
b, c
c)) = (a
a, b
b, c
c)
          in ((EventId p, (Delta p e, Set p)) -> (EventId p, Delta p e, Set p)
forall {a} {b} {c}. (a, (b, c)) -> (a, b, c)
flatten ((EventId p, (Delta p e, Set p)) -> (EventId p, Delta p e, Set p))
-> [(EventId p, (Delta p e, Set p))]
-> [(EventId p, Delta p e, Set p)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Map (EventId p) (Delta p e, Set p)
-> [(EventId p, (Delta p e, Set p))]
forall k a. Map k a -> [(k, a)]
toAscList Map (EventId p) (Delta p e, Set p)
psEvents)
        )

    accum
      :: (EventId p, Delta p e, Set p)
      -> (Map p (EventId p), EventId p)
      -> (Map p (EventId p), EventId p)

    accum :: (EventId p, Delta p e, Set p)
-> (Map p (EventId p), EventId p) -> (Map p (EventId p), EventId p)
accum (EventId p
eid, Join p
p, Set p
acks) (Map p (EventId p)
acc, EventId p
maxEid) =
      (
        (EventId p -> EventId p -> EventId p)
-> Map p (EventId p) -> Map p (EventId p) -> Map p (EventId p)
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
unionWith
          EventId p -> EventId p -> EventId p
forall a. Ord a => a -> a -> a
max
          (p -> EventId p -> Map p (EventId p) -> Map p (EventId p)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert p
p EventId p
forall p. EventId p
BottomEid Map p (EventId p)
acc)
          ([(p, EventId p)] -> Map p (EventId p)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(p
a, EventId p
eid) | p
a <- Set p -> [p]
forall a. Set a -> [a]
Set.toList Set p
acks]),
        EventId p -> EventId p -> EventId p
forall a. Ord a => a -> a -> a
max EventId p
maxEid EventId p
eid
      )

    accum (EventId p
eid, Delta p e
_, Set p
acks) (Map p (EventId p)
acc, EventId p
maxEid) =
      (
        (EventId p -> EventId p -> EventId p)
-> Map p (EventId p) -> Map p (EventId p) -> Map p (EventId p)
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
unionWith
          EventId p -> EventId p -> EventId p
forall a. Ord a => a -> a -> a
max
          Map p (EventId p)
acc
          ([(p, EventId p)] -> Map p (EventId p)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(p
a, EventId p
eid) | p
a <- Set p -> [p]
forall a. Set a -> [a]
Set.toList Set p
acks]),
        EventId p -> EventId p -> EventId p
forall a. Ord a => a -> a -> a
max EventId p
maxEid EventId p
eid
      )


{- | Return the origin value of the 'EventFold'. -}
origin :: EventFold o p e -> o
origin :: forall o p e. EventFold o p e -> o
origin = EventFold o p e -> o
forall o p e. EventFold o p e -> o
psOrigin


{- |
  This helper function is responsible for figuring out if the 'EventFold'
  has enough information to derive a new infimum value. In other words,
  this is where garbage collection happens.
-}
reduce
  :: forall o p e.
     ( Event p e
     , Ord p
     )
  => EventId p
     {- ^
       The infimum 'EventId' as known by some node in the cluster. "Some
       node" can be different than "this node" in the case where another
       node advanced the infimum before we did (because it knew about our
       acknowledgement, but we didn't know about its acknowledgement)
       and sent us an 'Diff' with this value of the infimum. In this
       case, this infimum value acts as a universal acknowledgement of
       all events coming before it.
     -}
  -> EventFold o p e
  -> (EventFold o p e, Map (EventId p) (Output e))
reduce :: forall o p e.
(Event p e, Ord p) =>
EventId p
-> EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
reduce
    EventId p
infState
  =
    EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
go
  where
    go
      :: EventFold o p e
      -> (EventFold o p e, Map (EventId p) (Output e))
    go :: EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
go
        ef :: EventFold o p e
ef@EventFold
          { psInfimum :: forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum = infimum :: Infimum (State e) p
infimum@Infimum {Set p
participants :: forall s p. Infimum s p -> Set p
participants :: Set p
participants, State e
stateValue :: forall s p. Infimum s p -> s
stateValue :: State e
stateValue}
          , Map (EventId p) (Delta p e, Set p)
psEvents :: forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents
          , Set (EventId p)
psUnjoins :: forall o p e. EventFold o p e -> Set (EventId p)
psUnjoins :: Set (EventId p)
psUnjoins
          }
      =
        case Map (EventId p) (Delta p e, Set p)
-> Maybe
     ((EventId p, (Delta p e, Set p)),
      Map (EventId p) (Delta p e, Set p))
forall k a. Map k a -> Maybe ((k, a), Map k a)
Map.minViewWithKey Map (EventId p) (Delta p e, Set p)
psEvents of
          Maybe
  ((EventId p, (Delta p e, Set p)),
   Map (EventId p) (Delta p e, Set p))
Nothing ->
            (
              EventFold {
                psOrigin :: o
psOrigin = EventFold o p e -> o
forall o p e. EventFold o p e -> o
psOrigin EventFold o p e
ef,
                psInfimum :: Infimum (State e) p
psInfimum = EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum EventFold o p e
ef,
                psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents = Map (EventId p) (Delta p e, Set p)
forall a. Monoid a => a
mempty,
                psUnjoins :: Set (EventId p)
psUnjoins = Set (EventId p)
forall a. Monoid a => a
mempty
              },
              Map (EventId p) (Output e)
forall a. Monoid a => a
mempty
            )
          Just ((EventId p
eid, (Delta p e
update, Set p
acks)), Map (EventId p) (Delta p e, Set p)
newDeltas)
            | EventId p
eid EventId p -> EventId p -> Bool
forall a. Ord a => a -> a -> Bool
<= Infimum (State e) p -> EventId p
forall s p. Infimum s p -> EventId p
eventId Infimum (State e) p
infimum -> {- The event is obsolete. Ignore it. -}
                EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
go EventFold o p e
ef {
                  psEvents = newDeltas,
                  psUnjoins = dropObsoleteUnjoins eid psUnjoins
                }
            | EventId p -> EventFold o p e -> Bool
isRenegade EventId p
eid EventFold o p e
ef -> {- This is a renegade event. Ignore it. -}
                EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
go EventFold o p e
ef {
                  psEvents = newDeltas,
                  psUnjoins = dropObsoleteUnjoins eid psUnjoins
                }
            | Bool
otherwise ->
                let
                  implicitAcks :: Set p
implicitAcks =
                    [p] -> Set p
forall a. Ord a => [a] -> Set a
Set.fromList
                      [ p
p | Just p
p <- EventId p -> Maybe p
forall p. EventId p -> Maybe p
source (EventId p -> Maybe p) -> [EventId p] -> [Maybe p]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Set (EventId p) -> [EventId p]
forall a. Set a -> [a]
Set.toList Set (EventId p)
psUnjoins ]
                  {- |
                    Join events must be acknowledged by the joining
                    participant before moving into the infimum.
                  -}
                  joining :: Set p
joining =
                    case Delta p e
update of
                      Join p
p -> p -> Set p
forall a. a -> Set a
Set.singleton p
p
                      Delta p e
_ -> Set p
forall a. Monoid a => a
mempty
                in
                  if
                      Set p -> Bool
forall a. Set a -> Bool
Set.null (((Set p
participants Set p -> Set p -> Set p
forall a. Ord a => Set a -> Set a -> Set a
`union` Set p
joining) Set p -> Set p -> Set p
forall a. Ord a => Set a -> Set a -> Set a
\\ Set p
acks) Set p -> Set p -> Set p
forall a. Ord a => Set a -> Set a -> Set a
\\ Set p
implicitAcks)
                      Bool -> Bool -> Bool
|| EventId p
eid EventId p -> EventId p -> Bool
forall a. Ord a => a -> a -> Bool
<= EventId p
infState
                    then
                      {-
                        This branch means to roll the update into the
                        infimum. The @else@ branch means we do not.
                      -}
                      case Delta p e
update of
                        Join p
p ->
                          EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
go EventFold o p e
ef {
                            psInfimum = infimum {
                                eventId = eid,
                                participants = Set.insert p participants,
                                stateValue = join @p @e p stateValue
                              },
                            psEvents = newDeltas,
                            psUnjoins = dropObsoleteUnjoins eid psUnjoins
                          }
                        UnJoin p
p ->
                          EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
go EventFold o p e
ef {
                            psInfimum = infimum {
                                eventId = eid,
                                participants = Set.delete p participants,
                                stateValue = unjoin @p @e p stateValue
                              },
                            psEvents = newDeltas,
                            psUnjoins = dropObsoleteUnjoins eid psUnjoins
                          }
                        Error Output e
output Set p
eacks
                          | Set p -> Bool
forall a. Set a -> Bool
Set.null (Set p
participants Set p -> Set p -> Set p
forall a. Ord a => Set a -> Set a -> Set a
\\ Set p
eacks) ->
                              let
                                (EventFold o p e
ps2, Map (EventId p) (Output e)
outputs) =
                                  EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
go EventFold o p e
ef {
                                    psInfimum = infimum {
                                      eventId = eid
                                    },
                                    psUnjoins = dropObsoleteUnjoins eid psUnjoins
                                  }
                              in
                                (EventFold o p e
ps2, EventId p
-> Output e
-> Map (EventId p) (Output e)
-> Map (EventId p) (Output e)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert EventId p
eid Output e
output Map (EventId p) (Output e)
outputs)
                          | Bool
otherwise ->
                              (
                                EventFold {
                                  psOrigin :: o
psOrigin = EventFold o p e -> o
forall o p e. EventFold o p e -> o
psOrigin EventFold o p e
ef,
                                  psInfimum :: Infimum (State e) p
psInfimum = EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum EventFold o p e
ef,
                                  Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents,
                                  Set (EventId p)
psUnjoins :: Set (EventId p)
psUnjoins :: Set (EventId p)
psUnjoins
                                },
                                Map (EventId p) (Output e)
forall a. Monoid a => a
mempty
                              )
                        EventD e
e ->
                          case forall p e. Event p e => e -> State e -> EventResult e
apply @p e
e State e
stateValue of
                            SystemError Output e
output ->
                              (
                                EventFold {
                                  psOrigin :: o
psOrigin = EventFold o p e -> o
forall o p e. EventFold o p e -> o
psOrigin EventFold o p e
ef,
                                  psInfimum :: Infimum (State e) p
psInfimum = Infimum (State e) p
infimum,
                                  psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents =
                                    EventId p
-> (Delta p e, Set p)
-> Map (EventId p) (Delta p e, Set p)
-> Map (EventId p) (Delta p e, Set p)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert
                                      EventId p
eid
                                      (Output e -> Set p -> Delta p e
forall p e. Output e -> Set p -> Delta p e
Error Output e
output Set p
forall a. Monoid a => a
mempty, Set p
acks)
                                      Map (EventId p) (Delta p e, Set p)
newDeltas,
                                  psUnjoins :: Set (EventId p)
psUnjoins = EventId p -> Set (EventId p) -> Set (EventId p)
dropObsoleteUnjoins EventId p
eid Set (EventId p)
psUnjoins
                                },
                                Map (EventId p) (Output e)
forall a. Monoid a => a
mempty
                              )
                            Pure Output e
output State e
newState ->
                              let
                                (EventFold o p e
ps2, Map (EventId p) (Output e)
outputs) =
                                  EventFold o p e -> (EventFold o p e, Map (EventId p) (Output e))
go EventFold o p e
ef {
                                    psInfimum = infimum {
                                        eventId = eid,
                                        stateValue = newState
                                      },
                                    psEvents = newDeltas,
                                    psUnjoins = dropObsoleteUnjoins eid psUnjoins
                                  }
                              in
                                (EventFold o p e
ps2, EventId p
-> Output e
-> Map (EventId p) (Output e)
-> Map (EventId p) (Output e)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert EventId p
eid Output e
output Map (EventId p) (Output e)
outputs)
                    else
                      (
                        EventFold {
                          psOrigin :: o
psOrigin = EventFold o p e -> o
forall o p e. EventFold o p e -> o
psOrigin EventFold o p e
ef,
                          psInfimum :: Infimum (State e) p
psInfimum = EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum EventFold o p e
ef,
                          Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents,
                          Set (EventId p)
psUnjoins :: Set (EventId p)
psUnjoins :: Set (EventId p)
psUnjoins
                        },
                        Map (EventId p) (Output e)
forall a. Monoid a => a
mempty
                      )

    dropObsoleteUnjoins :: EventId p -> Set (EventId p) -> Set (EventId p)
    dropObsoleteUnjoins :: EventId p -> Set (EventId p) -> Set (EventId p)
dropObsoleteUnjoins EventId p
newInfimumEid Set (EventId p)
unjoins =
      let (Set (EventId p)
_, Set (EventId p)
gt) = EventId p -> Set (EventId p) -> (Set (EventId p), Set (EventId p))
forall a. Ord a => a -> Set a -> (Set a, Set a)
Set.split EventId p
newInfimumEid Set (EventId p)
unjoins
      in Set (EventId p)
gt

    {- |
      Renegade events are events that originate from a non-participating
      peer.  This might happen in a network partition situation, where
      the cluster ejected a peer that later reappears on the network,
      broadcasting updates.
    -}
    isRenegade :: EventId p -> EventFold o p e -> Bool
    isRenegade :: EventId p -> EventFold o p e -> Bool
isRenegade EventId p
BottomEid EventFold o p e
_ = Bool
False
    isRenegade (Eid Word256
_ p
p) EventFold o p e
ef =
      Bool -> Bool
not (p
p p -> Set p -> Bool
forall a. Ord a => a -> Set a -> Bool
`member` Infimum (State e) p -> Set p
forall s p. Infimum s p -> Set p
participants (EventFold o p e -> Infimum (State e) p
forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum EventFold o p e
ef))


{- |
  A utility function that constructs the next `EventId` on behalf of
  a participant.
-}
nextId
  :: forall o p e.
     p
  -> EventFold o p e
  -> EventId p
nextId :: forall o p e. p -> EventFold o p e -> EventId p
nextId p
p EventFold {psInfimum :: forall o p e. EventFold o p e -> Infimum (State e) p
psInfimum = Infimum {EventId p
eventId :: forall s p. Infimum s p -> EventId p
eventId :: EventId p
eventId}, Map (EventId p) (Delta p e, Set p)
psEvents :: forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents :: Map (EventId p) (Delta p e, Set p)
psEvents} =
  let
    maxEid :: EventId p
    maxEid :: EventId p
maxEid =
      case Map (EventId p) (Delta p e, Set p)
-> Maybe
     ((EventId p, (Delta p e, Set p)),
      Map (EventId p) (Delta p e, Set p))
forall k a. Map k a -> Maybe ((k, a), Map k a)
Map.maxViewWithKey Map (EventId p) (Delta p e, Set p)
psEvents of
        Just ((EventId p
eid, (Delta p e, Set p)
_), Map (EventId p) (Delta p e, Set p)
_) -> EventId p
eid
        Maybe
  ((EventId p, (Delta p e, Set p)),
   Map (EventId p) (Delta p e, Set p))
Nothing -> EventId p
eventId
  in
    case EventId p
maxEid of
      EventId p
BottomEid -> Word256 -> p -> EventId p
forall p. Word256 -> p -> EventId p
Eid Word256
0 p
p
      Eid Word256
ord p
_ -> Word256 -> p -> EventId p
forall p. Word256 -> p -> EventId p
Eid (Word256 -> Word256
forall a. Enum a => a -> a
succ Word256
ord) p
p


{- |
  Return 'True' if progress on the 'EventFold' is blocked on a
  'SystemError'.

  The implication here is that if the local copy is blocked on a
  'SystemError', it needs to somehow arrange for remote copies to send
  full 'EventFold's, not just 'Diff's. A 'diffMerge' is not sufficient
  to get past the block. Only a 'fullMerge' will suffice.

  If your system is not using 'SystemError' or else not using 'Diff's,
  then you don't ever need to worry about this function.
-}
isBlockedOnError :: EventFold o p e -> Bool
isBlockedOnError :: forall o p e. EventFold o p e -> Bool
isBlockedOnError EventFold o p e
ef =
  case Map (EventId p) (Delta p e, Set p)
-> Maybe ((Delta p e, Set p), Map (EventId p) (Delta p e, Set p))
forall k a. Map k a -> Maybe (a, Map k a)
Map.minView (EventFold o p e -> Map (EventId p) (Delta p e, Set p)
forall o p e. EventFold o p e -> Map (EventId p) (Delta p e, Set p)
psEvents EventFold o p e
ef) of
    Just ((Error Output e
_ Set p
_, Set p
_), Map (EventId p) (Delta p e, Set p)
_) -> Bool
True
    Maybe ((Delta p e, Set p), Map (EventId p) (Delta p e, Set p))
_ -> Bool
False


{- | The bottom 'EventId', possibly useful for comparison in tests. -}
bottomEid :: EventId p
bottomEid :: forall p. EventId p
bottomEid = EventId p
forall p. EventId p
BottomEid