{- | Top-level binrep module, exporting all classes, generics & runners.

binrep helps you precisely model binary schemas by combining simple "building
blocks" (e.g. @'Binrep.Type.NullTerminated.NullTerminated' a@) in regular
Haskell types. You can then receive high-performance serializers and parsers for
free via generics.

binrep is /not/ a general-purpose parsing/serializing library. For that, see

  * mason, for fast and flexible serializing
  * flatparse, for extremely performant parsing
  * bytezap, for overly-fast serializing and parsing (but very limited)
-}

module Binrep
  (
  -- * Class and instance design
  -- $class-and-instance-design

  -- * Struct parsing & serializing
  -- $struct-handlers
    module Binrep.BLen
  , module Binrep.CBLen
  , module Binrep.Put
  , module Binrep.Put.Struct
  , module Binrep.Get
  , module Binrep.Get.Struct
  ) where

import Binrep.BLen
import Binrep.CBLen
import Binrep.Put
import Binrep.Put.Struct
import Binrep.Get
import Binrep.Get.Struct

{- $class-and-instance-design
At the core of binrep are a set of classes defining parsers, serializers, and
serialized length checkers on supported types. binrep is its own ecosystem where
explicitness and correctness win over all:

  * there are no binrep instances for 'Data.Void.Void' or 'GHC.Generics.V1'
    because we can't use them; rather than providing an absurd, possibly
    convenient instance, we emit a type error for their attempted use.
  * you can't put/get 'Data.Word.Word32's etc by themselves; you must provide
    endianness information via the 'Binrep.Util.ByteOrder.ByteOrdered' newtype
  * @'Get' 'Data.ByteString.ByteString'@ just consumes the whole input. seem
    weird? it works with the combinators (it's actually rather important)

Here are some important design decisions:

  * Fields in product types are concatenated left-to-right. e.g. @'Put' (l, r)@
    first puts @l@, then @r@. Nothing is placed between them.
  * Sum types must define how to handle the constructor sum.
    Generics are split into sum handlers and non-sum handlers.
    binrep instances are not provided for types such as @'Either' a b@, where we
    can't state how to choose between the 'Left' and 'Right' constructors.
  * @'Refined.Refined' (pl `Refined.And` pr) a@ is re-associated to
    @'Refined.Refined' pr ('Refined.Refined' pl a)@. The single layer of
    refinements is ergonomic, but the way binrep instances work means we need
    the latter. So 'Refined.And' instances essentially rewrite themselves to
    work as if it were a stack of refinements. (See
    'Binrep.Type.Derived.NullTermPadded' for an example.)
-}

{- $struct-handlers

There are experimental "struct" handlers, which only work on data types that
look like C structs. That is,

  * every field must be constant length, and
  * no sums allowed.

The underlying runners for these are even faster-- they shouldn't do much more
work than the code a C compiler would generate for a similar @struct@. But they
are very inflexible (few binrep instances, hard to write by hand) and poorly
tested. Please be warned when using them. (And do consider sending bug reports
to the author!)
-}