packages feed

bytezap-1.4.0: src/Bytezap/Write/Internal.hs

module Bytezap.Write.Internal where

import Bytezap.Poke ( Poke )

-- | A 'Poke' buffer write operation with the associated length to be written.
--
-- The length may be either exact or a maximum.
--
-- TODO strictness?
data Write (lt :: LengthType) s = Write
  { writeLength :: Int
  -- ^ Length of the write in bytes.
  --
  -- This is not statically asserted. Any time you construct a 'Write', you must
  -- promise this.
  --
  -- For @'Write' 'ExactLength' s@, this is an exact measurement.
  -- For @'Write' 'MaxLength'   s@, this is a maximum.

  , writeOp :: Poke s
  -- ^ The 'Poke' buffer write operation.
  }

-- | What a buffer write length field means.
data LengthType
  = ExactLength -- ^ Exact length to be written.
  | MaxLength   -- ^ Maximum length to be written.

-- | Sequence the writes, sum the lengths.
instance Semigroup (Write lt s) where
    -- TODO strictness? INLINE[1]? INLINE[0]?
    (<>) = writeCombine

-- | The empty 'Write' is the empty 'Poke', which writes zero bytes.
instance Monoid (Write lt s) where
    mempty = Write 0 mempty

-- | Turn a @'Write' 'ExactLength'@ into a @'Write' 'MaxLength'@.
writeMax :: Write ExactLength s -> Write MaxLength s
writeMax (Write l p) = Write l p

-- | Sequence a @'Write' 'MaxLength'@ and a @'Write' 'ExactLength'@
--   left-to-right.
writeMaxExact :: Write MaxLength s -> Write ExactLength s -> Write MaxLength s
writeMaxExact = writeCombine

-- | Sequence a @'Write' 'MaxLength'@ and a @'Write' 'ExactLength'@
--   left-to-right.
writeExactMax :: Write ExactLength s -> Write MaxLength s -> Write MaxLength s
writeExactMax = writeCombine

-- | Sequence two 'Write's left-to-right.
--
-- Unsafe, as it ignores 'LengthType's.
--
-- TODO strictness? INLINE[1]? INLINE[0]?
writeCombine :: Write ltl s -> Write ltr s -> Write lt s
writeCombine (Write ll lp) (Write rl rp) = Write (ll + rl) (lp <> rp)