binrep-0.6.0: src/Binrep/Util/Prefix.hs
{-# LANGUAGE UndecidableInstances #-} -- for convenient type level arithmetic
module Binrep.Util.Prefix where
import Binrep.Util.ByteOrder ( ByteOrdered(ByteOrdered) )
import GHC.TypeNats
import Data.Word
import Data.Kind
-- | Types which may be used as prefixes.
--
-- Generally, these will be integer types.
--
-- Note that this is separate to binary representation, so endianness is
-- irrelevant.
--
-- Note that we are also limited by the host architecture's 'Int' type.
-- We don't try to work around this, because most types are indexed with 'Int's,
-- so I think other things will break before we do.
class Prefix a where
type Max a :: Natural
-- | used by put. guaranteed that it fits from refined. that is, lenToPfx <=
-- Max.
lenToPfx :: Int -> a
-- | used by get. better not lie.
pfxToLen :: a -> Int
-- | Length prefixing with the unit means a length of 0.
--
-- This is the only sensible case. 1 doesn't work because refining checks @<=@.
--
-- I think there are laws here, where using this is the same as doing nothing at
-- all.
instance Prefix () where
type Max () = 0
lenToPfx = \case
0 -> ()
_ -> error "you lied to refine and broke everything :("
pfxToLen () = 0
-- | Byte ordering doesn't change how prefixes work.
deriving via (a :: Type) instance Prefix a => Prefix (ByteOrdered end a)
instance Prefix Word8 where
type Max Word8 = 2^8 - 1
lenToPfx = fromIntegral
pfxToLen = fromIntegral
instance Prefix Word16 where
type Max Word16 = 2^16 - 1
lenToPfx = fromIntegral
pfxToLen = fromIntegral
instance Prefix Word32 where
type Max Word32 = 2^32 - 1
lenToPfx = fromIntegral
pfxToLen = fromIntegral
instance Prefix Word64 where
type Max Word64 = 2^64 - 1
lenToPfx = fromIntegral
pfxToLen = fromIntegral