module Data.Enum.Storable (
   T,
   fromPlain, toPlain,
   ) where

import Foreign.Storable (Storable, poke, peek, sizeOf, alignment)
import Foreign.Ptr (Ptr, castPtr)

import Data.Functor ((<$>))

import Prelude2010
import Prelude ()


newtype T w e = Cons e
   deriving (Eq, Ord)


instance (Show e) => Show (T w e) where
   showsPrec p (Cons e) =
      showParen (p>=10) $ showString "Enum.fromPlain " . showsPrec 11 e

instance (Bounded e) => Bounded (T w e) where
   minBound = Cons minBound
   maxBound = Cons maxBound

instance (Enum e) => Enum (T w e) where
   fromEnum (Cons e) = fromEnum e
   toEnum = Cons . toEnum
   succ (Cons e) = Cons $ succ e
   pred (Cons e) = Cons $ pred e
   enumFrom (Cons e) = map Cons $ enumFrom e
   enumFromThen (Cons e0) (Cons e1) = map Cons $ enumFromThen e0 e1
   enumFromTo (Cons e0) (Cons e1) = map Cons $ enumFromTo e0 e1
   enumFromThenTo (Cons e0) (Cons e1) (Cons e2) =
      map Cons $ enumFromThenTo e0 e1 e2

enumPtr :: Ptr (T w e) -> Ptr w
enumPtr = castPtr

zero :: (Num w) => T w e -> w
zero _ = 0

instance (Storable w, Integral w, Enum e) => Storable (T w e) where
   sizeOf = sizeOf . zero
   alignment = alignment . zero
   peek ptr = Cons . toEnum . fromIntegral <$> peek (enumPtr ptr)
   poke ptr (Cons e) = poke (enumPtr ptr) (fromIntegral $ fromEnum e)

fromPlain :: a -> T w a
fromPlain = Cons

toPlain :: T w a -> a
toPlain (Cons a) = a