{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GADTs #-}
module Control.Distributed.Process.Serializable
( Serializable
, encodeFingerprint
, decodeFingerprint
, fingerprint
, sizeOfFingerprint
, Fingerprint
, showFingerprint
, SerializableDict(SerializableDict)
, TypeableDict(TypeableDict)
) where
import Data.Binary (Binary)
import Data.Typeable (Typeable, typeRepFingerprint, typeOf)
import Numeric (showHex)
import Control.Exception (throw)
import GHC.Fingerprint.Type (Fingerprint(..))
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BSI ( unsafeCreate, toForeignPtr )
import Foreign.Storable (pokeByteOff, peekByteOff, sizeOf)
import Foreign.ForeignPtr (withForeignPtr)
import System.IO.Unsafe (unsafePerformIO)
data SerializableDict a where
SerializableDict :: Serializable a => SerializableDict a
deriving (Typeable)
data TypeableDict a where
TypeableDict :: Typeable a => TypeableDict a
deriving (Typeable)
class (Binary a, Typeable a) => Serializable a
instance (Binary a, Typeable a) => Serializable a
encodeFingerprint :: Fingerprint -> ByteString
encodeFingerprint fp =
BSI.unsafeCreate sizeOfFingerprint $ \p -> pokeByteOff p 0 fp
decodeFingerprint :: ByteString -> Fingerprint
decodeFingerprint bs
| BS.length bs /= sizeOfFingerprint =
throw $ userError "decodeFingerprint: Invalid length"
| otherwise = unsafePerformIO $ do
let (fp, offset, _) = BSI.toForeignPtr bs
withForeignPtr fp $ \p -> peekByteOff p offset
sizeOfFingerprint :: Int
sizeOfFingerprint = sizeOf (undefined :: Fingerprint)
fingerprint :: Typeable a => a -> Fingerprint
fingerprint = typeRepFingerprint . typeOf
showFingerprint :: Fingerprint -> ShowS
showFingerprint (Fingerprint hi lo) =
showString "(" . showHex hi . showString "," . showHex lo . showString ")"