| Safe Haskell | None |
|---|---|
| Language | GHC2024 |
Circuit.Agent.Framing
Description
Bus message framing.
Storage format is JSON Lines: one stamped Post per line with fields
id, ts, from, to, thread and body. The body is never mutated
for framing; JSON string encoding handles newlines in the standard way.
The file image is a stream with the same Stream ends as the pure
log: Log is oldest-first on disk, so append is snoc and read is
uncons. The pure Log is newest-first; that is the dual linearisation of
the same thread DAG, not a different algebra.
'Log a' stores 'Stamped a' values in memory — no encoding in the hot path.
File persistence uses frameStored/unframeStored via PostBody at the
storage boundary.
Backwards compatibility: parseLineAt also accepts the legacy flat triple
{"ts":..., "sender":..., "body":...} and the bracket format
[timestamp] sender: body so existing log files remain readable. Those
legacy lines are assigned the supplied line index as their id and empty
to/thread lists.
Synopsis
- type PostId = Natural
- class PostBody a where
- encodePostBody :: a -> Json
- decodePostBody :: Json -> Maybe a
- type Stamped a = Stamped (UTCTime, PostId) (Post a)
- pattern Stamped :: (UTCTime, PostId) -> Post a -> Stamped a
- stamp :: Stamped r a -> r
- stamped :: Stamped r a -> a
- newtype Log a = Log {}
- class Cons f s where
- class Snoc f s where
- class Uncons f s where
- data These a b
- frameStored :: PostBody a => Stamped a -> Text
- framePost :: PostBody a => Post a -> Text
- unframeStored :: PostBody a => Text -> Maybe (Stamped a)
- parseLineAt :: Int -> Text -> Maybe (Stamped Text)
- parsePost :: PostBody a => Text -> Maybe (Post a)
- parseMessage :: Text -> Maybe (Text, Text)
- parseMessageTs :: Text -> Maybe Text
- renderStored :: PostBody a => Stamped a -> Text
- renderMessage :: Text -> Maybe Text
- formatNow :: IO Text
- parseTimeText :: Text -> Maybe UTCTime
- readLogFile :: PostBody a => FilePath -> IO (Log a)
- encodeLog :: PostBody a => Log a -> [Text]
Types
type PostId = Natural Source #
Absolute post identity. In the stamped log this is the line id assigned
by the single writer. In pure meeting logs it is the position in the
oldest-first log, but branches and cone resolve by the id itself, not by
position in the passed-in list. Use indexToIdMap to assign ids [0..] from
a chronological list.
class PostBody a where Source #
Encodable/decodable post body. Every body type in the bus must
support JSON round-trip through 'circuits-parser''s Json type.
type Stamped a = Stamped (UTCTime, PostId) (Post a) Source #
Storage boundary: a post with its assigned id and timestamp.
This is the agent-side specialisation of Stamped from
circuits core: the occurrence token is the (UTCTime, PostId) pair and
the payload is a Post a. The core type carries the free theorem that
fmap cannot touch the stamp, so the agent shares it rather than
duplicating it.
pattern Stamped :: (UTCTime, PostId) -> Post a -> Stamped a Source #
The core Stamped constructor specialised to the agent's
occurrence token (UTCTime, PostId).
The log image: a stream of stamped posts, oldest first.
Instances
| Functor Log Source # | |
| Eq a => Eq (Log a) Source # | |
| Show a => Show (Log a) Source # | |
| Cons (Log a) (Stamped a) Source # | Prepend is the dual view: a newest-first stream over the same image. |
| Snoc (Log a) (Stamped a) Source # | Append is the natural operation: one element at the end. |
| Uncons (Log a) (Stamped a) Source # | Read peels the oldest element first. |
Stream ends (re-exported from Circuit.Stream)
Stream algebra: construct a stream by prepending one token on the left.
This is the construction dual of Uncons. Together they let code move
back and forth between tokens and streams using the same coalgebra.
Methods
Prepend one token to the left of a stream.
The empty stream.
Stream algebra: construct a stream by appending one token on the right.
This is the right-handed dual of Uncons.
Methods
Append one token to the right of a stream.
The empty stream.
Stream coalgebra with explicit boundary.
uncons [x] = This x announces the final element at extraction. The
nil value is the stream-specific empty used to continue after a This
result.
Instances
| Uncons ByteString Word8 # | |
Defined in Circuit.Parser.Stream | |
| Uncons ByteString Char # | Strict Warning: bytes |
Defined in Circuit.Parser.Stream | |
| Uncons Text Char # | |
| Uncons [a] a # | |
| Uncons (Log a) (Stamped a) Source # | Read peels the oldest element first. |
| Uncons (Array a) (Array a) # | An array is a stream of its rows. |
The These type represents values with two non-exclusive possibilities.
This can be useful to represent combinations of two values, where the
combination is defined if either input is. Algebraically, the type
represents These A B(A + B + AB), which doesn't factor easily into
sums and products--a type like is unclear and
awkward to use.Either A (B, Maybe A)
These has straightforward instances of Functor, Monad, &c., and
behaves like a hybrid error/writer monad, as would be expected.
For zipping and unzipping of structures with These values, see
Data.Align.
Instances
| Bifoldable These # | |||||
| Bifoldable1 These # | Since: these-1.2 | ||||
Defined in Data.These | |||||
| Bifunctor These # | |||||
| Bitraversable These # | |||||
Defined in Data.These Methods bitraverse :: Applicative f => (a -> f c) -> (b -> f d) -> These a b -> f (These c d) # | |||||
| Eq2 These # | Since: these-1.1.1 | ||||
| Ord2 These # | Since: these-1.1.1 | ||||
Defined in Data.These | |||||
| Read2 These # | Since: these-1.1.1 | ||||
Defined in Data.These Methods liftReadsPrec2 :: (Int -> ReadS a) -> ReadS [a] -> (Int -> ReadS b) -> ReadS [b] -> Int -> ReadS (These a b) # liftReadList2 :: (Int -> ReadS a) -> ReadS [a] -> (Int -> ReadS b) -> ReadS [b] -> ReadS [These a b] # liftReadPrec2 :: ReadPrec a -> ReadPrec [a] -> ReadPrec b -> ReadPrec [b] -> ReadPrec (These a b) # liftReadListPrec2 :: ReadPrec a -> ReadPrec [a] -> ReadPrec b -> ReadPrec [b] -> ReadPrec [These a b] # | |||||
| Show2 These # | Since: these-1.1.1 | ||||
| NFData2 These # | Since: these-1.1.1 | ||||
Defined in Data.These | |||||
| Hashable2 These # | Since: these-1.1.1 | ||||
Defined in Data.These | |||||
| Assoc These # | Since: these-0.8 | ||||
| Swap These # | Since: these-0.8 | ||||
Defined in Data.These | |||||
| Monad m => Channel These (K m :: Type -> Type -> Type) # | Inclusive monoidal structure for | ||||
| Channel These (->) # | Inclusive monoidal structure for
| ||||
| Monad m => Strength These (K m :: Type -> Type -> Type) # | Inclusive tensorial strength for | ||||
| Strength These (->) # | Inclusive tensorial strength for
| ||||
Defined in Circuit.Channel | |||||
| Monad m => Action These (K m :: Type -> Type -> Type) # | Inclusive symmetry on | ||||
| Action These (->) # | Inclusive symmetry on functions. | ||||
Defined in Circuit.Tensor | |||||
| Monad m => Tensor These (K m :: Type -> Type -> Type) # | Inclusive tensor action on | ||||
| Tensor These (->) # | Inclusive tensor action on functions. | ||||
Defined in Circuit.Tensor | |||||
| Monad m => Unital These (K m :: Type -> Type -> Type) # | Inclusive unit structure on | ||||
| Unital These (->) # | Inclusive unit structure on functions. Laws: | ||||
| Generic1 (These a :: Type -> Type) # | |||||
Defined in Data.These Associated Types
| |||||
| Eq a => Eq1 (These a) # | Since: these-1.1.1 | ||||
| Ord a => Ord1 (These a) # | Since: these-1.1.1 | ||||
Defined in Data.These | |||||
| Read a => Read1 (These a) # | Since: these-1.1.1 | ||||
Defined in Data.These Methods liftReadsPrec :: (Int -> ReadS a0) -> ReadS [a0] -> Int -> ReadS (These a a0) # liftReadList :: (Int -> ReadS a0) -> ReadS [a0] -> ReadS [These a a0] # liftReadPrec :: ReadPrec a0 -> ReadPrec [a0] -> ReadPrec (These a a0) # liftReadListPrec :: ReadPrec a0 -> ReadPrec [a0] -> ReadPrec [These a a0] # | |||||
| Show a => Show1 (These a) # | Since: these-1.1.1 | ||||
| NFData a => NFData1 (These a) # | Since: these-1.1.1 | ||||
Defined in Data.These | |||||
| Semigroup a => Applicative (These a) # | |||||
| Functor (These a) # | |||||
| Semigroup a => Monad (These a) # | |||||
| Foldable (These a) # | |||||
Defined in Data.These Methods fold :: Monoid m => These a m -> m # foldMap :: Monoid m => (a0 -> m) -> These a a0 -> m # foldMap' :: Monoid m => (a0 -> m) -> These a a0 -> m # foldr :: (a0 -> b -> b) -> b -> These a a0 -> b # foldr' :: (a0 -> b -> b) -> b -> These a a0 -> b # foldl :: (b -> a0 -> b) -> b -> These a a0 -> b # foldl' :: (b -> a0 -> b) -> b -> These a a0 -> b # foldr1 :: (a0 -> a0 -> a0) -> These a a0 -> a0 # foldl1 :: (a0 -> a0 -> a0) -> These a a0 -> a0 # toList :: These a a0 -> [a0] # elem :: Eq a0 => a0 -> These a a0 -> Bool # maximum :: Ord a0 => These a a0 -> a0 # minimum :: Ord a0 => These a a0 -> a0 # | |||||
| Traversable (These a) # | |||||
| Hashable a => Hashable1 (These a) # | Since: these-1.1.1 | ||||
Defined in Data.These | |||||
| (Binary a, Binary b) => Binary (These a b) # | Since: these-0.7.1 | ||||
| (NFData a, NFData b) => NFData (These a b) # | Since: these-0.7.1 | ||||
Defined in Data.These | |||||
| (Semigroup a, Semigroup b) => Semigroup (These a b) # | |||||
| (Eq a, Eq b) => Eq (These a b) # | |||||
| (Ord a, Ord b) => Ord (These a b) # | |||||
| (Data a, Data b) => Data (These a b) # | |||||
Defined in Data.These Methods gfoldl :: (forall d b0. Data d => c (d -> b0) -> d -> c b0) -> (forall g. g -> c g) -> These a b -> c (These a b) # gunfold :: (forall b0 r. Data b0 => c (b0 -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (These a b) # toConstr :: These a b -> Constr # dataTypeOf :: These a b -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (These a b)) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (These a b)) # gmapT :: (forall b0. Data b0 => b0 -> b0) -> These a b -> These a b # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> These a b -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> These a b -> r # gmapQ :: (forall d. Data d => d -> u) -> These a b -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> These a b -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> These a b -> m (These a b) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> These a b -> m (These a b) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> These a b -> m (These a b) # | |||||
| Generic (These a b) # | |||||
Defined in Data.These Associated Types
| |||||
| (Read a, Read b) => Read (These a b) # | |||||
| (Show a, Show b) => Show (These a b) # | |||||
| (Hashable a, Hashable b) => Hashable (These a b) # | |||||
Defined in Data.These | |||||
| type Unit These # | |||||
Defined in Circuit.Tensor | |||||
| type Rep1 (These a :: Type -> Type) # | |||||
Defined in Data.These type Rep1 (These a :: Type -> Type) = D1 ('MetaData "These" "Data.These" "ths-1.2.1-19a91f2e" 'False) (C1 ('MetaCons "This" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a)) :+: (C1 ('MetaCons "That" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) Par1) :+: C1 ('MetaCons "These" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) Par1))) | |||||
| type Rep (These a b) # | |||||
Defined in Data.These type Rep (These a b) = D1 ('MetaData "These" "Data.These" "ths-1.2.1-19a91f2e" 'False) (C1 ('MetaCons "This" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a)) :+: (C1 ('MetaCons "That" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 b)) :+: C1 ('MetaCons "These" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 b)))) | |||||
Encoding
frameStored :: PostBody a => Stamped a -> Text Source #
Encode a 'Stamped a' as a single canonical JSON Lines object.
framePost :: PostBody a => Post a -> Text Source #
Encode a bare 'Post a' as a single JSON Lines object (the protocol format sent to the stamping bus daemon).
Parsing
unframeStored :: PostBody a => Text -> Maybe (Stamped a) Source #
Unframe a canonical stamped storage line (the inverse of frameStored).
Returns Nothing if the line is not valid JSON with the expected fields.
parseLineAt :: Int -> Text -> Maybe (Stamped Text) Source #
Like unframeStored, but also accepts the legacy flat triple and bracket
formats, assigning the supplied line index as the id. Legacy-only, Text body.
parseMessage :: Text -> Maybe (Text, Text) Source #
Parse a raw log line into (from, body), accepting the stamped format
and both legacy formats.
Rendering
renderStored :: PostBody a => Stamped a -> Text Source #
Render a 'Stamped a' for human display as [idts] from: body@.
Time
parseTimeText :: Text -> Maybe UTCTime Source #
Parse an ISO-8601 string to UTCTime, accepting the format we write.