module Data.Serialize.Describe.Combinators(
  Optional(..),
  StaticPred(..),
  LE(..),
  BE(..)
) where

import GHC.TypeNats
import Data.Proxy
import Data.Maybe
import Data.Serialize.Describe.Descriptor
import Data.Serialize.Describe.Class
import qualified Data.Serialize.Get as G

newtype LE a = LE { unwrapLE :: a }

newtype BE a = BE { unwrapBE :: a }

newtype Optional p t = Optional { unwrapOptional :: Maybe t }

class StaticPred t a where
  check :: t -> Bool

data Equals (n :: Nat)

instance (KnownNat n, Integral i) => StaticPred i (Equals n) where
  check i = i == (fromIntegral $ natVal (Proxy :: Proxy n))

instance (Describe a, StaticPred a p) => Describe (Optional p a) where
  describe f = Descriptor (g, p)
    where
      g = do
        let d = unwrapGet $ describe @a $ fromJust . unwrapOptional . f
        v <- G.lookAhead d
        Optional <$> if check @a @p v then Just <$> d else pure Nothing
      p s = case unwrapOptional $ f s of
        Just x -> Optional . Just <$> unwrapPut s (describe $ const x)
        Nothing -> pure $ Optional Nothing