{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE FlexibleContexts #-} -- | Internal module that has the encode class and some utility functions. module Raaz.Core.Encode.Internal ( Encodable(..), Format(..) , encode, decode, unsafeDecode ) where import Data.Maybe import Data.ByteString (ByteString) import Data.ByteString.Internal (unsafeCreate) import Data.String import Data.Word import Foreign.Ptr import Foreign.Storable import Prelude hiding (length) import System.IO.Unsafe (unsafePerformIO) import Raaz.Core.Types.Endian import Raaz.Core.Types.Pointer import Raaz.Core.Util.ByteString(length, withByteString) -- | The type class `Encodable` captures all the types can be encoding into `ByteString`. class Encodable a where -- | Convert stuff to bytestring toByteString :: a -> ByteString -- | Try parsing back a value. Returns nothing on failure. fromByteString :: ByteString -> Maybe a -- | Unsafe version of `fromByteString` unsafeFromByteString :: ByteString -> a default toByteString :: EndianStore a => a -> ByteString toByteString w = unsafeCreate (sizeOf w) putit where putit ptr = store (castPtr ptr) w default fromByteString :: EndianStore a => ByteString -> Maybe a fromByteString bs | byteSize proxy == length bs = Just w | otherwise = Nothing where w = unsafePerformIO $ withByteString bs (load . castPtr) proxy = undefined `asTypeOf` w unsafeFromByteString = fromMaybe (error "fromByteString error") . fromByteString instance Encodable (LE Word32) instance Encodable (LE Word64) instance Encodable (BE Word32) instance Encodable (BE Word64) instance Encodable ByteString where toByteString = id {-# INLINE toByteString #-} fromByteString = Just . id {-# INLINE fromByteString #-} unsafeFromByteString = id {-# INLINE unsafeFromByteString #-} instance Encodable a => Encodable (BITS a) where toByteString (BITS a) = toByteString a fromByteString = fmap BITS . fromByteString unsafeFromByteString = BITS . unsafeFromByteString instance Encodable a => Encodable (BYTES a) where toByteString (BYTES a) = toByteString a fromByteString = fmap BYTES . fromByteString unsafeFromByteString = BYTES . unsafeFromByteString -- | A binary encoding format is something for which there is a 1:1 -- correspondence with bytestrings. We also insist that it is an -- instance of `IsString`, so that it can be easily included in source -- code, and `Show`, so that it can be easily printed out. class (IsString fmt, Show fmt, Encodable fmt) => Format fmt where encodeByteString :: ByteString -> fmt decodeFormat :: fmt -> ByteString -- | Bytestring itself is an encoding format (namely binary format). instance Format ByteString where encodeByteString = id {-# INLINE encodeByteString #-} decodeFormat = id {-# INLINE decodeFormat #-} -- | Encode in a given format. encode :: (Encodable a, Format fmt) => a -> fmt encode = encodeByteString . toByteString -- | Decode from a given format. It results in Nothing if there is a -- parse error. decode :: (Format fmt, Encodable a) => fmt -> Maybe a decode = fromByteString . decodeFormat -- | The unsafe version of `decode`. unsafeDecode :: (Format fmt, Encodable a) => fmt -> a unsafeDecode = unsafeFromByteString . decodeFormat