{-# OPTIONS_GHC -Wall #-} {-# LANGUAGE ScopedTypeVariables , TypeFamilies , FlexibleContexts #-} module BitField where import Control.Monad --import Control.Applicative import Data.Bits import Foreign.Ptr import Foreign.Storable class (Storable (CType bitField), Bits (CType bitField)) => BitField bitField where type CType bitField :: * size :: bitField -> Int startPosition :: bitField -> Int cSymbol :: bitField -> Ptr (CType bitField) valueOf :: bitField -> IO (CType bitField) valueOf = peek . cSymbol value :: bitField -> IO [Bool] value n = liftM (\v -> bits v (startPosition n) (size n)) (valueOf n) setValueBit :: bitField -> Int -> Bool -> IO (CType bitField) setValueBit n pos flag | pos >= (sizeOf (undefined::CType bitField)) = error $ "bit Position: " ++ show pos ++ " >= (size n) :" ++ show (size n) | flag = modifyValue setBit | otherwise = modifyValue clearBit where modifyValue f = valueOf n >>= (\x -> return $ f x pos) -- could use the below instead of the above --(flip f pos) <$> (valueOf n) >>= poke (cSymbol n) >> valueOf n setValue :: bitField -> [Bool] -> IO [Bool] setValue n flags | (length flags) > (sizeOf $ cSymbol n) = error $ "(length flags) " ++ show (length flags) ++ " > (size n) :" ++ show (size n) | otherwise = zipWithM (setValueBit n) [(startPosition n)..] flags >> value n bits :: Bits a => a -> Int -> Int -> [Bool] bits _ _ 0 = [] bits i pos len = (testBit i pos) : bits i (succ pos) (pred len)