{- | Efficient type-level bytestring parsing.

One may implement this using the type-level serializing, but mirroring it for
parsing does less work and allocation.
-}

{-# LANGUAGE AllowAmbiguousTypes, UndecidableInstances #-}

module Bytezap.Parser.Struct.TypeLits.Bytes where

import Data.Type.Byte
import Bytezap.Parser.Struct ( ParserT, prim, withLit, constParse )
import Numeric.Natural ( Natural )

class ParseReifyBytesW64 (ns :: [Natural]) where
    parseReifyBytesW64 :: ParserT st e ()

-- | Enough bytes to make a 'Word64'.
instance {-# OVERLAPPING #-}
  ( ReifyW8 n1
  , ReifyW8 n2
  , ReifyW8 n3
  , ReifyW8 n4
  , ReifyW8 n5
  , ReifyW8 n6
  , ReifyW8 n7
  , ReifyW8 n8
  , ParseReifyBytesW64 ns
  ) => ParseReifyBytesW64 (n1 ': n2 ': n3 ': n4 ': n5 ': n6 ': n7 ': n8 ': ns) where
    {-# INLINE parseReifyBytesW64 #-}
    parseReifyBytesW64 :: forall (st :: ZeroBitType) e. ParserT st e ()
parseReifyBytesW64 = Int#
-> Word64
-> ParserT st e Word64
-> ParserT st e ()
-> ParserT st e ()
forall a (st :: ZeroBitType) e r.
Eq a =>
Int# -> a -> ParserT st e a -> ParserT st e r -> ParserT st e r
withLit Int#
8# (forall (n1 :: Natural) (n2 :: Natural) (n3 :: Natural)
       (n4 :: Natural) (n5 :: Natural) (n6 :: Natural) (n7 :: Natural)
       (n8 :: Natural).
(ReifyW8 n1, ReifyW8 n2, ReifyW8 n3, ReifyW8 n4, ReifyW8 n5,
 ReifyW8 n6, ReifyW8 n7, ReifyW8 n8) =>
Word64
reifyW64 @n1 @n2 @n3 @n4 @n5 @n6 @n7 @n8)
        ParserT st e Word64
forall a (st :: ZeroBitType) e. Prim' a => ParserT st e a
prim (forall (ns :: [Natural]) (st :: ZeroBitType) e.
ParseReifyBytesW64 ns =>
ParserT st e ()
parseReifyBytesW64 @ns)

-- | Try to group 'Word32's next.
instance ParseReifyBytesW32 ns => ParseReifyBytesW64 ns where
    {-# INLINE parseReifyBytesW64 #-}
    parseReifyBytesW64 :: forall (st :: ZeroBitType) e. ParserT st e ()
parseReifyBytesW64 = forall (ns :: [Natural]) (st :: ZeroBitType) e.
ParseReifyBytesW32 ns =>
ParserT st e ()
parseReifyBytesW32 @ns

-- | Serialize a type-level bytestring, largest grouping 'Word32'.
class ParseReifyBytesW32 (ns :: [Natural]) where
    parseReifyBytesW32 :: ParserT st e ()

-- | Enough bytes to make a 'Word32'.
instance {-# OVERLAPPING #-}
  ( ReifyW8 n1
  , ReifyW8 n2
  , ReifyW8 n3
  , ReifyW8 n4
  , ParseReifyBytesW32 ns
  ) => ParseReifyBytesW32 (n1 ': n2 ': n3 ': n4 ': ns) where
    {-# INLINE parseReifyBytesW32 #-}
    parseReifyBytesW32 :: forall (st :: ZeroBitType) e. ParserT st e ()
parseReifyBytesW32 = Int#
-> Word32
-> ParserT st e Word32
-> ParserT st e ()
-> ParserT st e ()
forall a (st :: ZeroBitType) e r.
Eq a =>
Int# -> a -> ParserT st e a -> ParserT st e r -> ParserT st e r
withLit Int#
4# (forall (n1 :: Natural) (n2 :: Natural) (n3 :: Natural)
       (n4 :: Natural).
(ReifyW8 n1, ReifyW8 n2, ReifyW8 n3, ReifyW8 n4) =>
Word32
reifyW32 @n1 @n2 @n3 @n4)
        ParserT st e Word32
forall a (st :: ZeroBitType) e. Prim' a => ParserT st e a
prim (forall (ns :: [Natural]) (st :: ZeroBitType) e.
ParseReifyBytesW32 ns =>
ParserT st e ()
parseReifyBytesW32 @ns)

-- | Try to group 'Word16's next.
instance ParseReifyBytesW16 ns => ParseReifyBytesW32 ns where
    {-# INLINE parseReifyBytesW32 #-}
    parseReifyBytesW32 :: forall (st :: ZeroBitType) e. ParserT st e ()
parseReifyBytesW32 = forall (ns :: [Natural]) (st :: ZeroBitType) e.
ParseReifyBytesW16 ns =>
ParserT st e ()
parseReifyBytesW16 @ns

-- | Serialize a type-level bytestring, largest grouping 'Word16'.
class ParseReifyBytesW16 (ns :: [Natural]) where
    parseReifyBytesW16 :: ParserT st e ()

-- | Enough bytes to make a 'Word16'.
instance {-# OVERLAPPING #-}
  ( ReifyW8 n1
  , ReifyW8 n2
  , ParseReifyBytesW16 ns
  ) => ParseReifyBytesW16 (n1 ': n2 ': ns) where
    {-# INLINE parseReifyBytesW16 #-}
    parseReifyBytesW16 :: forall (st :: ZeroBitType) e. ParserT st e ()
parseReifyBytesW16 = Int#
-> Word16
-> ParserT st e Word16
-> ParserT st e ()
-> ParserT st e ()
forall a (st :: ZeroBitType) e r.
Eq a =>
Int# -> a -> ParserT st e a -> ParserT st e r -> ParserT st e r
withLit Int#
2# (forall (n1 :: Natural) (n2 :: Natural).
(ReifyW8 n1, ReifyW8 n2) =>
Word16
reifyW16 @n1 @n2)
        ParserT st e Word16
forall a (st :: ZeroBitType) e. Prim' a => ParserT st e a
prim (forall (ns :: [Natural]) (st :: ZeroBitType) e.
ParseReifyBytesW16 ns =>
ParserT st e ()
parseReifyBytesW16 @ns)

-- | Reify byte-by-byte next.
instance ParseReifyBytesW8 ns => ParseReifyBytesW16 ns where
    {-# INLINE parseReifyBytesW16 #-}
    parseReifyBytesW16 :: forall (st :: ZeroBitType) e. ParserT st e ()
parseReifyBytesW16 = forall (ns :: [Natural]) (st :: ZeroBitType) e.
ParseReifyBytesW8 ns =>
ParserT st e ()
parseReifyBytesW8 @ns

-- | Serialize a type-level bytestring, byte-by-byte.
class ParseReifyBytesW8 (ns :: [Natural]) where
    parseReifyBytesW8 :: ParserT st e ()

-- | Reify the next byte.
instance
  ( ReifyW8 n1
  , ParseReifyBytesW8 ns
  ) => ParseReifyBytesW8 (n1 ': ns) where
    {-# INLINE parseReifyBytesW8 #-}
    parseReifyBytesW8 :: forall (st :: ZeroBitType) e. ParserT st e ()
parseReifyBytesW8 = Int#
-> Word8
-> ParserT st e Word8
-> ParserT st e ()
-> ParserT st e ()
forall a (st :: ZeroBitType) e r.
Eq a =>
Int# -> a -> ParserT st e a -> ParserT st e r -> ParserT st e r
withLit Int#
1# (forall (n :: Natural). ReifyW8 n => Word8
reifyW8 @n1)
        ParserT st e Word8
forall a (st :: ZeroBitType) e. Prim' a => ParserT st e a
prim (forall (ns :: [Natural]) (st :: ZeroBitType) e.
ParseReifyBytesW8 ns =>
ParserT st e ()
parseReifyBytesW8 @ns)

-- | End of the line.
instance ParseReifyBytesW8 '[] where
    {-# INLINE parseReifyBytesW8 #-}
    parseReifyBytesW8 :: forall (st :: ZeroBitType) e. ParserT st e ()
parseReifyBytesW8 = () -> ParserT st e ()
forall a (st :: ZeroBitType) e. a -> ParserT st e a
constParse ()