raaz-0.0.1: Raaz/Core/Encode/Internal.hs
{-# 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