{-# LANGUAGE ViewPatterns, ScopedTypeVariables, StandaloneDeriving #-} module Data.Binary.Enum where import Prelude import Data.Binary import Control.Applicative import qualified Data.List as DL -- | we can store Enum values inside values we know how to store, so let newtype BitMap t a = BitMap [a] -- ^ Map lets you encode 'flags' compressing distinct eg. packing 8 diferent flags per byte deriving instance (Show a) => Show (BitMap t a) newtype BitEnc t a = BitEnc a -- ^ t is a store type, you will need to make sure that your enum fits there -- eg. you want to store `Bool` as `Word64` field `BitEnc Word64 Bool` deriving instance (Show a) => Show (BitEnc t a) instance (Enum a, Enum t, Binary t) => Binary (BitEnc t a) where put (BitEnc a) = put (toEnum . fromEnum $ a :: t) get = BitEnc . toEnum . fromEnum <$> (get :: Get t) instance (Enum a, Eq a, Eq t, Integral t, Binary t) => Binary (BitMap t a) where put a = put ( (toEnum (fromEnum a)) :: t ) get = toEnum . fromEnum <$> (get :: Get t) instance (Enum a, Enum t, Eq a, Eq t, Num t) => Enum (BitMap t a) where fromEnum (BitMap a) = fromEnum (foldr (\(fromEnum -> x) y -> 2 ^ x + y ) 0 (DL.nub a) :: t) toEnum = BitMap . process 0 -- (fromEnum k :: t) where process _ 0 = [] process k (flip divMod 2 -> (d, m)) | m == 1 = toEnum k : process (k + 1) d | otherwise = process (k + 1) d instance (Enum a, Enum t, Binary t) => Enum (BitEnc t a) where fromEnum (BitEnc a) = fromEnum a toEnum = BitEnc . toEnum . fromEnum