{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash #-}
module Haskus.Binary.Enum
( EnumField
, CEnum (..)
, fromEnumField
, toEnumField
, makeEnum
, makeEnumMaybe
, makeEnumWithCustom
, dataToTag
)
where
import Haskus.Binary.Storable
import Foreign.Ptr
import Data.Data
import GHC.Prim
import GHC.Int
newtype EnumField b a
= EnumField b
deriving (Show,Eq,Storable)
instance
( Integral b
, StaticStorable b
, CEnum a
) => StaticStorable (EnumField b a)
where
type SizeOf (EnumField b a) = SizeOf b
type Alignment (EnumField b a) = Alignment b
staticPeekIO p = EnumField <$> staticPeek (castPtr p :: Ptr b)
staticPokeIO p (EnumField v) = staticPoke (castPtr p :: Ptr b) v
fromEnumField :: (CEnum a, Integral b) => EnumField b a -> a
{-# INLINABLE fromEnumField #-}
fromEnumField (EnumField b) = toCEnum b
toEnumField :: (CEnum a, Integral b) => a -> EnumField b a
{-# INLINABLE toEnumField #-}
toEnumField = EnumField . fromCEnum
class CEnum a where
fromCEnum :: Integral b => a -> b
fromCEnum = fromIntegral . dataToTag
toCEnum :: Integral b => b -> a
default toCEnum :: (Enum a, Integral b) => b -> a
toCEnum = toEnum . fromIntegral
makeEnumWithCustom :: forall a i. (Data a,Integral i) => i -> a
{-# INLINABLE makeEnumWithCustom #-}
makeEnumWithCustom x =
if x' < maxConstrIndex t
then fromConstr (indexConstr t x')
else fromConstrB (fromConstr (toConstr (x' - m)))
(indexConstr t m)
where
m = maxConstrIndex t
x' = fromIntegral x + 1
t = dataTypeOf (undefined :: a)
makeEnumMaybe :: forall a i. (Data a,Integral i) => i -> Maybe a
{-# INLINABLE makeEnumMaybe #-}
makeEnumMaybe x =
if x' < maxConstrIndex t
then Just (fromConstr (indexConstr t x'))
else Nothing
where
x' = fromIntegral x + 1
t = dataTypeOf (undefined :: a)
makeEnum :: forall a i. (Data a,Integral i) => i -> a
{-# INLINABLE makeEnum #-}
makeEnum x =fromConstr (indexConstr t x')
where
x' = fromIntegral x + 1
t = dataTypeOf (undefined :: a)
dataToTag :: a -> Int
dataToTag a = I# (dataToTag# a)