module Data.Repa.Convert.Internal.Packable
        ( Packable      (..)
        , Unpackable    (..))
where
import Data.Repa.Convert.Internal.Format
import Data.Repa.Convert.Internal.Packer
import Data.Repa.Convert.Internal.Unpacker
import Data.Word
import GHC.Exts


-- | Class of storage formats that can have values packed and unpacked
--   from foreign bufferes. 
-- 
--   The methods are written using continuations to make it easier for
--   GHC to optimise its core code when packing/unpacking many fields.
--
class Format   format 
   => Packable format where


 -- | Pack a value into a buffer using the given format.
 pack   :: format                       -- ^ Storage format.
        -> Value format                 -- ^ Value   to pack.
        -> Packer                       -- ^ Packer  that can write the value.

 pack format
format Value format
value 
  = (Addr# -> IO () -> (Addr# -> IO ()) -> IO ()) -> Packer
Packer (format
-> Value format -> Addr# -> IO () -> (Addr# -> IO ()) -> IO ()
forall format.
Packable format =>
format
-> Value format -> Addr# -> IO () -> (Addr# -> IO ()) -> IO ()
packer format
format Value format
value)
 {-# INLINE pack #-}


 -- | Low level packing function for the given format.
 packer   :: format                     -- ^ Data format.
          -> Value format               -- ^ Value to pack.
          -> Addr#                      -- ^ Pointer to start of buffer.
          -> IO ()                      -- ^ Signal failure.
          -> (Addr# -> IO ())           -- ^ Accept the address after the packed field.
          -> IO ()


class Format format
   => Unpackable format where

 -- | Unpack a value from a buffer using the given format.
 unpack :: format                       -- ^ Storage format.
        -> Unpacker (Value format)      -- ^ Unpacker for that format.

 unpack format
format 
  = (Addr#
 -> Addr#
 -> (Word8 -> Bool)
 -> IO ()
 -> (Addr# -> Value format -> IO ())
 -> IO ())
-> Unpacker (Value format)
forall a.
(Addr#
 -> Addr#
 -> (Word8 -> Bool)
 -> IO ()
 -> (Addr# -> a -> IO ())
 -> IO ())
-> Unpacker a
Unpacker (format
-> Addr#
-> Addr#
-> (Word8 -> Bool)
-> IO ()
-> (Addr# -> Value format -> IO ())
-> IO ()
forall format.
Unpackable format =>
format
-> Addr#
-> Addr#
-> (Word8 -> Bool)
-> IO ()
-> (Addr# -> Value format -> IO ())
-> IO ()
unpacker format
format)
 {-# INLINE unpack #-}


 -- | Low level unpacking function for the given format.
 unpacker :: format                     -- ^ Data format.
          -> Addr#                      -- ^ Start of buffer.
          -> Addr#                      -- ^ Pointer to first byte after end of buffer.
          -> (Word8 -> Bool)            -- ^ Detect a field terminator.
          -> IO ()                      -- ^ Signal failure.
          -> (Addr# -> Value format -> IO ())   -- ^ Accept an unpacked value.
          -> IO ()