    {-|

    The memory subsystem associated with raaz.

    __Warning:__ This module is pretty low level and should not be needed in typical
    use cases. Only developers of protocols and primitives might have a
    reason to look into this module.

    -}

    {-# LANGUAGE TypeFamilies               #-}
    {-# LANGUAGE GADTs                      #-}
    {-# LANGUAGE RankNTypes                 #-}
    {-# LANGUAGE MultiParamTypeClasses      #-}
    {-# LANGUAGE FlexibleInstances          #-}

    module Raaz.Core.Memory
           (
           -- * The Memory subsystem.
           -- $memorysubsystem$

           -- ** Memory elements.
             Memory(..), VoidMemory, copyMemory
           -- *** Initialisation and Extraction.
           -- $init-extract$
           , Initialisable(..), Extractable(..)
           , InitialisableFromBuffer(..), ExtractableToBuffer(..)
           -- *** A basic memory cell.
           , MemoryCell, withCellPointer, getCellPointer

           -- ** Memory threads.
           , MemoryThread(..), doIO , getMemory, modify, execute
           , MT
           -- **** Some low level `MT` actions.

           , liftPointerAction

           -- ** Memory allocation
           ,  Alloc, pointerAlloc
           ) where

    import           Control.Applicative
    import           Control.Monad.IO.Class
    import           Foreign.Storable            ( Storable )
    import           Foreign.Ptr                 ( castPtr, Ptr )
    import           Raaz.Core.MonoidalAction
    import           Raaz.Core.Transfer
    import           Raaz.Core.Types

    -- $memorysubsystem$
    --
    -- Cryptographic operations often need to keep sensitive information
    -- like private keys in its memory space. Such sensitive information
    -- can leak to the external would if the memory where the data is
    -- stored is swapped out to a disk. What makes this particularly
    -- dangerous is that the data can reside on the disk almost
    -- permanently and might even survive when the hardware is
    -- scrapped. The primary purpose of the memory subsystem is to provide
    -- a way to allocate and manage /secure memory/, i.e. memory that will
    -- not be swapped out as long as the memory is used and will be wiped
    -- clean after use. It consists of the following components:
    --
    -- [The `Memory` type class:] A memory element is some type that holds
    -- an internal buffer inside it.
    --
    -- [The `Alloc` type:] Memory elements need to be allocated and this
    -- is involves a lot of low lever pointer arithmetic. The `Alloc`
    -- types gives a high level interface for memory allocation. For a
    -- memory type `mem`, the type `Alloc mem` can be seen as the
    -- _allocation strategy_ for mem. For example, one of the things that
    -- it keeps track of is the space required to create an memory element
    -- of type `mem`. There is a natural applicative instance for `Alloc`
    -- which helps build the allocation strategy for a compound memory
    -- type from its components in a modular fashion _without_ explicit
    -- size calculation or offset computation.
    --
    -- [`MemoryThread`s:] Instances of this class are actions that use
    -- some kind of memory elements inside it. Such a thread can be run
    -- using the combinator `securely` or the combinator `insecurely`. If
    -- one use the combinator `securely`, then the allocation of the
    -- memory element to be used by the action is done using a locked
    -- memory pool which is wiped clean before de-allocation.

    -- $init-extract$
    --
    -- Memory elements often needs to be initialised. Similarly data needs
    -- to be extracted out of memory. An instance declaration
    -- @`Initialisable` mem a@ for the memory type @mem@ indicates that it
    -- can be initialised with the pure value @a@. Similary, if values of
    -- type @b@ can be extracted out of a memory element @mem@, we can
    -- indicate it with an instance of @`Extractable` mem a@.
    --
    -- There is an inherent danger in initialising and extracting pure
    -- values out of memory. Pure values are stored on the Haskell heap
    -- and hence can be swapped out. Consider a memory element @mem@ that
    -- stores some sensitive information, say for example the unencrypted
    -- private key. Suppose we extract this key out of the memory element
    -- as a pure value before its encryption and storage into the key
    -- file. It is likely that the key is swapped out to the disk as the
    -- extracted key is part of the the haskell heap.
    --
    -- The `InitialiseFromBuffer` (`ExtractableToBuffer`) class gives an
    -- interface for reading from (writing to) buffers directly minimising
    -- the chances of inadvertent exposure of sensitive information from
    -- the Haskell heap due to swapping.

    -- | An action of type @`MT` mem a@ is an action that uses internally
    -- a single memory object of type @mem@ and returns a result of type
    -- @a@. All the actions are performed on a single memory element and
    -- hence the side effects persist. It is analogues to the @ST@ monad.
    newtype MT mem a = MT { MT mem a -> mem -> IO a
    unMT :: mem -> IO a }

    instance Functor (MT mem) where
      fmap :: (a -> b) -> MT mem a -> MT mem b
    fmap f :: a -> b
    f mst :: MT mem a
    mst = (mem -> IO b) -> MT mem b
    forall mem a. (mem -> IO a) -> MT mem a
    MT ((mem -> IO b) -> MT mem b) -> (mem -> IO b) -> MT mem b
    forall a b. (a -> b) -> a -> b
    $ \ m :: mem
    m -> a -> b
    f (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> MT mem a -> mem -> IO a
    forall mem a. MT mem a -> mem -> IO a
    unMT MT mem a
    mst mem
    m

    instance Applicative (MT mem) where
      pure :: a -> MT mem a
    pure       = (mem -> IO a) -> MT mem a
    forall mem a. (mem -> IO a) -> MT mem a
    MT ((mem -> IO a) -> MT mem a) -> (a -> mem -> IO a) -> a -> MT mem a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IO a -> mem -> IO a
    forall a b. a -> b -> a
    const (IO a -> mem -> IO a) -> (a -> IO a) -> a -> mem -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure
      mf :: MT mem (a -> b)
    mf <*> :: MT mem (a -> b) -> MT mem a -> MT mem b
    <*> ma :: MT mem a
    ma  = (mem -> IO b) -> MT mem b
    forall mem a. (mem -> IO a) -> MT mem a
    MT ((mem -> IO b) -> MT mem b) -> (mem -> IO b) -> MT mem b
    forall a b. (a -> b) -> a -> b
    $ \ m :: mem
    m -> MT mem (a -> b) -> mem -> IO (a -> b)
    forall mem a. MT mem a -> mem -> IO a
    unMT MT mem (a -> b)
    mf mem
    m IO (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> MT mem a -> mem -> IO a
    forall mem a. MT mem a -> mem -> IO a
    unMT MT mem a
    ma mem
    m

    instance Monad (MT mem) where
      return :: a -> MT mem a
    return    =  (mem -> IO a) -> MT mem a
    forall mem a. (mem -> IO a) -> MT mem a
    MT ((mem -> IO a) -> MT mem a) -> (a -> mem -> IO a) -> a -> MT mem a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IO a -> mem -> IO a
    forall a b. a -> b -> a
    const (IO a -> mem -> IO a) -> (a -> IO a) -> a -> mem -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return
      ma :: MT mem a
    ma >>= :: MT mem a -> (a -> MT mem b) -> MT mem b
    >>= f :: a -> MT mem b
    f  =  (mem -> IO b) -> MT mem b
    forall mem a. (mem -> IO a) -> MT mem a
    MT mem -> IO b
    runIt
        where runIt :: mem -> IO b
    runIt mem :: mem
    mem = MT mem a -> mem -> IO a
    forall mem a. MT mem a -> mem -> IO a
    unMT MT mem a
    ma mem
    mem IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \ a :: a
    a -> MT mem b -> mem -> IO b
    forall mem a. MT mem a -> mem -> IO a
    unMT (a -> MT mem b
    f a
    a) mem
    mem

    -- | __WARNING:__ do not lift a secure memory action.
    instance MonadIO (MT mem) where
      liftIO :: IO a -> MT mem a
    liftIO = (mem -> IO a) -> MT mem a
    forall mem a. (mem -> IO a) -> MT mem a
    MT ((mem -> IO a) -> MT mem a)
    -> (IO a -> mem -> IO a) -> IO a -> MT mem a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IO a -> mem -> IO a
    forall a b. a -> b -> a
    const

    -- | A class that captures abstract "memory threads". A memory thread
    -- can either be run `securely` or `insecurely`. Pure IO actions can
    -- be run inside a memory thread using the @runIO@.  However, the IO
    -- action that is being run /must not/ directly or indirectly run a
    -- `secure` action ever. In particular, the following code is bad.
    --
    -- > -- BAD EXAMPLE: DO NOT USE.
    -- > runIO $ securely $ foo
    -- >
    --
    -- On the other hand the following code is fine
    --
    -- >
    -- > runIO $ insecurely $ someMemoryAction
    -- >
    --
    -- As to why this is dangerous, it has got to do with the fact that
    -- @mlock@ and @munlock@ do not nest correctly. A single @munlock@ can
    -- unlock multiple calls of @mlock@ on the same page.  Whether a given
    -- @IO@ action unlocks memory is difficult to keep track of; for all
    -- you know, it might be a FFI call that does an @memunlock@. Hence,
    -- currently there is no easy way to enforce this.
    --

    class MemoryThread (mT :: * -> * -> *) where
      -- | Run a memory action with the internal memory allocated from a
      -- locked memory buffer. This memory buffer will never be swapped
      -- out by the operating system and will be wiped clean before
      -- releasing.
      --
      -- Memory locking is an expensive operation and usually there would be
      -- a limit to how much locked memory can be allocated. Nonetheless,
      -- actions that work with sensitive information like passwords should
      -- use this to run an memory action.
      securely   :: Memory mem => mT mem a -> IO a

      -- | Run a memory action with the internal memory used by the action
      -- being allocated from unlocked memory. Use this function when you
      -- work with data that is not sensitive to security considerations
      -- (for example, when you want to verify checksums of files).
      insecurely :: Memory mem => mT mem a -> IO a

      -- | Lift an actual memory thread.
      liftMT :: MT mem a -> mT mem a

      -- | Combinator that allows us to run a memory action on a
      -- sub-memory element. A sub-memory of @submem@ of a memory element
      -- @mem@ is given by a projection @proj : mem -> submem@. The action
      -- @onSubMemory proj@ lifts the a memory thread on the sub element
      -- to the compound element.
      --
      onSubMemory :: (mem -> submem) -> mT submem a -> mT mem a

    instance MemoryThread MT where
      securely :: MT mem a -> IO a
    securely               = (mem -> IO a) -> IO a
    forall m a. Memory m => (m -> IO a) -> IO a
    withSecureMemory ((mem -> IO a) -> IO a)
    -> (MT mem a -> mem -> IO a) -> MT mem a -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . MT mem a -> mem -> IO a
    forall mem a. MT mem a -> mem -> IO a
    unMT
      insecurely :: MT mem a -> IO a
    insecurely             = (mem -> IO a) -> IO a
    forall m a. Memory m => (m -> IO a) -> IO a
    withMemory ((mem -> IO a) -> IO a)
    -> (MT mem a -> mem -> IO a) -> MT mem a -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . MT mem a -> mem -> IO a
    forall mem a. MT mem a -> mem -> IO a
    unMT
      liftMT :: MT mem a -> MT mem a
    liftMT                 = MT mem a -> MT mem a
    forall a. a -> a
    id
      onSubMemory :: (mem -> submem) -> MT submem a -> MT mem a
    onSubMemory proj :: mem -> submem
    proj mtsub :: MT submem a
    mtsub = (mem -> IO a) -> MT mem a
    forall mem a. (mem -> IO a) -> MT mem a
    MT ((mem -> IO a) -> MT mem a) -> (mem -> IO a) -> MT mem a
    forall a b. (a -> b) -> a -> b
    $ MT submem a -> submem -> IO a
    forall mem a. MT mem a -> mem -> IO a
    unMT MT submem a
    mtsub (submem -> IO a) -> (mem -> submem) -> mem -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . mem -> submem
    proj

    ------------- Lifting pointer actions -----------------------------

    -- | Run a given memory action in the memory thread.
    execute :: MemoryThread mT => (mem -> IO a) -> mT mem a
    execute :: (mem -> IO a) -> mT mem a
    execute = MT mem a -> mT mem a
    forall (mT :: * -> * -> *) mem a.
    MemoryThread mT =>
    MT mem a -> mT mem a
    liftMT (MT mem a -> mT mem a)
    -> ((mem -> IO a) -> MT mem a) -> (mem -> IO a) -> mT mem a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (mem -> IO a) -> MT mem a
    forall mem a. (mem -> IO a) -> MT mem a
    MT

    -- | Perform an IO action inside the memory thread.
    doIO :: MemoryThread mT => IO a -> mT mem a
    doIO :: IO a -> mT mem a
    doIO = (mem -> IO a) -> mT mem a
    forall (mT :: * -> * -> *) mem a.
    MemoryThread mT =>
    (mem -> IO a) -> mT mem a
    execute ((mem -> IO a) -> mT mem a)
    -> (IO a -> mem -> IO a) -> IO a -> mT mem a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IO a -> mem -> IO a
    forall a b. a -> b -> a
    const

    -- | A pointer action inside a monad @m@ is some function that takes a
    -- pointer action of type @Pointer -> m a@ and supplies it with an
    -- appropriate pointer. In particular, memory allocators are pointer
    -- actions.
    type PointerAction m a b = (Pointer -> m a) -> m b

    -- | An IO allocator can be lifted to the memory thread level as follows.
    liftPointerAction :: PointerAction IO a b -> PointerAction (MT mem) a b
    liftPointerAction :: PointerAction IO a b -> PointerAction (MT mem) a b
    liftPointerAction allocator :: PointerAction IO a b
    allocator mtAction :: Pointer -> MT mem a
    mtAction
      = (mem -> IO b) -> MT mem b
    forall (mT :: * -> * -> *) mem a.
    MemoryThread mT =>
    (mem -> IO a) -> mT mem a
    execute ((mem -> IO b) -> MT mem b) -> (mem -> IO b) -> MT mem b
    forall a b. (a -> b) -> a -> b
    $ \ mem :: mem
    mem -> PointerAction IO a b
    allocator (\ ptr :: Pointer
    ptr -> MT mem a -> mem -> IO a
    forall mem a. MT mem a -> mem -> IO a
    unMT (Pointer -> MT mem a
    mtAction Pointer
    ptr) mem
    mem)

    -- TODO: This is a very general pattern needs more exploration.

    -- | Get the underlying memory element of the memory thread.
    getMemory :: MemoryThread mT => mT mem mem
    getMemory :: mT mem mem
    getMemory = (mem -> IO mem) -> mT mem mem
    forall (mT :: * -> * -> *) mem a.
    MemoryThread mT =>
    (mem -> IO a) -> mT mem a
    execute mem -> IO mem
    forall (m :: * -> *) a. Monad m => a -> m a
    return

    ------------------------ A memory allocator -----------------------

    type AllocField = Field Pointer

    -- | A memory allocator for the memory type @mem@. The `Applicative`
    -- instance of @Alloc@ can be used to build allocations for
    -- complicated memory elements from simpler ones.
    type Alloc mem = TwistRF AllocField (BYTES Int) mem

    -- | Make an allocator for a given memory type.
    makeAlloc :: LengthUnit l => l -> (Pointer -> mem) -> Alloc mem
    makeAlloc :: l -> (Pointer -> mem) -> Alloc mem
    makeAlloc l :: l
    l memCreate :: Pointer -> mem
    memCreate = WrappedArrow (->) Pointer mem -> BYTES Int -> Alloc mem
    forall (f :: * -> *) m a. f a -> m -> TwistRF f m a
    TwistRF ((Pointer -> mem) -> WrappedArrow (->) Pointer mem
    forall (a :: * -> * -> *) b c. a b c -> WrappedArrow a b c
    WrapArrow Pointer -> mem
    memCreate) (BYTES Int -> Alloc mem) -> BYTES Int -> Alloc mem
    forall a b. (a -> b) -> a -> b
    $ l -> BYTES Int
    forall src dest. (LengthUnit src, LengthUnit dest) => src -> dest
    atLeast l
    l

    -- | Allocates a buffer of size @l@ and returns the pointer to it pointer.
    pointerAlloc :: LengthUnit l => l -> Alloc Pointer
    pointerAlloc :: l -> Alloc Pointer
    pointerAlloc l :: l
    l = l -> (Pointer -> Pointer) -> Alloc Pointer
    forall l mem. LengthUnit l => l -> (Pointer -> mem) -> Alloc mem
    makeAlloc l
    l Pointer -> Pointer
    forall a. a -> a
    id

    ---------------------------------------------------------------------

    -- | Any cryptographic primitives use memory to store stuff. This
    -- class abstracts all types that hold some memory. Cryptographic
    -- application often requires securing the memory from being swapped
    -- out (think of memory used to store private keys or passwords). This
    -- abstraction supports memory securing. If your platform supports
    -- memory locking, then securing a memory will prevent the memory from
    -- being swapped to the disk. Once secured the memory location is
    -- overwritten by nonsense before being freed.
    --
    -- While some basic memory elements like `MemoryCell` are exposed from
    -- the library, often we require compound memory objects built out of
    -- simpler ones. The `Applicative` instance of the `Alloc` can be made
    -- use of in such situation to simplify such instance declaration as
    -- illustrated in the instance declaration for a pair of memory
    -- elements.
    --
    -- > instance (Memory ma, Memory mb) => Memory (ma, mb) where
    -- >
    -- >    memoryAlloc             = (,) <$> memoryAlloc <*> memoryAlloc
    -- >
    -- >    unsafeToPointer (ma, _) =  unsafeToPointer ma
    --
    class Memory m where

      -- | Returns an allocator for this memory.
      memoryAlloc     :: Alloc m

      -- | Returns the pointer to the underlying buffer.
      unsafeToPointer :: m -> Pointer

    -- | A memory element that holds nothing.
    data VoidMemory = VoidMemory { VoidMemory -> Pointer
    unVoidMemory :: Pointer  }

    instance Memory VoidMemory where
      memoryAlloc :: Alloc VoidMemory
    memoryAlloc      = BYTES Int -> (Pointer -> VoidMemory) -> Alloc VoidMemory
    forall l mem. LengthUnit l => l -> (Pointer -> mem) -> Alloc mem
    makeAlloc (0 :: BYTES Int) Pointer -> VoidMemory
    VoidMemory
      unsafeToPointer :: VoidMemory -> Pointer
    unsafeToPointer  = VoidMemory -> Pointer
    unVoidMemory

    instance ( Memory ma, Memory mb ) => Memory (ma, mb) where
        memoryAlloc :: Alloc (ma, mb)
    memoryAlloc             = (,) (ma -> mb -> (ma, mb))
    -> TwistRF AllocField (BYTES Int) ma
    -> TwistRF AllocField (BYTES Int) (mb -> (ma, mb))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> TwistRF AllocField (BYTES Int) ma
    forall m. Memory m => Alloc m
    memoryAlloc TwistRF AllocField (BYTES Int) (mb -> (ma, mb))
    -> TwistRF AllocField (BYTES Int) mb -> Alloc (ma, mb)
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) mb
    forall m. Memory m => Alloc m
    memoryAlloc
        unsafeToPointer :: (ma, mb) -> Pointer
    unsafeToPointer (ma :: ma
    ma, _) =  ma -> Pointer
    forall m. Memory m => m -> Pointer
    unsafeToPointer ma
    ma

    instance ( Memory ma
             , Memory mb
             , Memory mc
             )
             => Memory (ma, mb, mc) where
      memoryAlloc :: Alloc (ma, mb, mc)
    memoryAlloc              = (,,)
                                 (ma -> mb -> mc -> (ma, mb, mc))
    -> TwistRF AllocField (BYTES Int) ma
    -> TwistRF AllocField (BYTES Int) (mb -> mc -> (ma, mb, mc))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> TwistRF AllocField (BYTES Int) ma
    forall m. Memory m => Alloc m
    memoryAlloc
                                 TwistRF AllocField (BYTES Int) (mb -> mc -> (ma, mb, mc))
    -> TwistRF AllocField (BYTES Int) mb
    -> TwistRF AllocField (BYTES Int) (mc -> (ma, mb, mc))
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) mb
    forall m. Memory m => Alloc m
    memoryAlloc
                                 TwistRF AllocField (BYTES Int) (mc -> (ma, mb, mc))
    -> TwistRF AllocField (BYTES Int) mc -> Alloc (ma, mb, mc)
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) mc
    forall m. Memory m => Alloc m
    memoryAlloc
      unsafeToPointer :: (ma, mb, mc) -> Pointer
    unsafeToPointer (ma :: ma
    ma,_,_) =  ma -> Pointer
    forall m. Memory m => m -> Pointer
    unsafeToPointer ma
    ma

    instance ( Memory ma
             , Memory mb
             , Memory mc
             , Memory md
             )
             => Memory (ma, mb, mc, md) where
      memoryAlloc :: Alloc (ma, mb, mc, md)
    memoryAlloc                = (,,,)
                                   (ma -> mb -> mc -> md -> (ma, mb, mc, md))
    -> TwistRF AllocField (BYTES Int) ma
    -> TwistRF
         AllocField (BYTES Int) (mb -> mc -> md -> (ma, mb, mc, md))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> TwistRF AllocField (BYTES Int) ma
    forall m. Memory m => Alloc m
    memoryAlloc
                                   TwistRF AllocField (BYTES Int) (mb -> mc -> md -> (ma, mb, mc, md))
    -> TwistRF AllocField (BYTES Int) mb
    -> TwistRF AllocField (BYTES Int) (mc -> md -> (ma, mb, mc, md))
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) mb
    forall m. Memory m => Alloc m
    memoryAlloc
                                   TwistRF AllocField (BYTES Int) (mc -> md -> (ma, mb, mc, md))
    -> TwistRF AllocField (BYTES Int) mc
    -> TwistRF AllocField (BYTES Int) (md -> (ma, mb, mc, md))
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) mc
    forall m. Memory m => Alloc m
    memoryAlloc
                                   TwistRF AllocField (BYTES Int) (md -> (ma, mb, mc, md))
    -> TwistRF AllocField (BYTES Int) md -> Alloc (ma, mb, mc, md)
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) md
    forall m. Memory m => Alloc m
    memoryAlloc

      unsafeToPointer :: (ma, mb, mc, md) -> Pointer
    unsafeToPointer (ma :: ma
    ma,_,_,_) =  ma -> Pointer
    forall m. Memory m => m -> Pointer
    unsafeToPointer ma
    ma

    -- | Copy data from a given memory location to the other. The first
    -- argument is destionation and the second argument is source to match
    -- with the convention followed in memcpy.
    copyMemory :: Memory m => Dest m -- ^ Destination
                           -> Src  m -- ^ Source
                           -> IO ()
    copyMemory :: Dest m -> Src m -> IO ()
    copyMemory dmem :: Dest m
    dmem smem :: Src m
    smem = Dest Pointer -> Src Pointer -> BYTES Int -> IO ()
    forall (m :: * -> *) l.
    (MonadIO m, LengthUnit l) =>
    Dest Pointer -> Src Pointer -> l -> m ()
    memcpy (m -> Pointer
    forall m. Memory m => m -> Pointer
    unsafeToPointer (m -> Pointer) -> Dest m -> Dest Pointer
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Dest m
    dmem) (m -> Pointer
    forall m. Memory m => m -> Pointer
    unsafeToPointer (m -> Pointer) -> Src m -> Src Pointer
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Src m
    smem) BYTES Int
    sz
      where sz :: BYTES Int
    sz       = TwistRF AllocField (BYTES Int) m -> BYTES Int
    forall (f :: * -> *) m a. TwistRF f m a -> m
    twistMonoidValue (TwistRF AllocField (BYTES Int) m -> BYTES Int)
    -> TwistRF AllocField (BYTES Int) m -> BYTES Int
    forall a b. (a -> b) -> a -> b
    $ Src m -> TwistRF AllocField (BYTES Int) m
    forall m. Memory m => Src m -> Alloc m
    getAlloc Src m
    smem
            getAlloc :: Memory m => Src m -> Alloc m
            getAlloc :: Src m -> Alloc m
    getAlloc _ = Alloc m
    forall m. Memory m => Alloc m
    memoryAlloc

    -- | Perform an action which makes use of this memory. The memory
    -- allocated will automatically be freed when the action finishes
    -- either gracefully or with some exception. Besides being safer,
    -- this method might be more efficient as the memory might be
    -- allocated from the stack directly and will have very little GC
    -- overhead.
    withMemory   :: Memory m => (m -> IO a) -> IO a
    withMemory :: (m -> IO a) -> IO a
    withMemory   = Alloc m -> (m -> IO a) -> IO a
    forall m a. Alloc m -> (m -> IO a) -> IO a
    withM Alloc m
    forall m. Memory m => Alloc m
    memoryAlloc
      where withM :: Alloc m -> (m -> IO a) -> IO a
            withM :: Alloc m -> (m -> IO a) -> IO a
    withM alctr :: Alloc m
    alctr action :: m -> IO a
    action = BYTES Int -> (Pointer -> IO a) -> IO a
    forall l b. LengthUnit l => l -> (Pointer -> IO b) -> IO b
    allocaBuffer BYTES Int
    sz Pointer -> IO a
    actualAction
              where sz :: BYTES Int
    sz                 = Alloc m -> BYTES Int
    forall (f :: * -> *) m a. TwistRF f m a -> m
    twistMonoidValue Alloc m
    alctr
                    getM :: Pointer -> m
    getM               = Field Pointer m -> Pointer -> m
    forall space b. Field space b -> space -> b
    computeField (Field Pointer m -> Pointer -> m)
    -> Field Pointer m -> Pointer -> m
    forall a b. (a -> b) -> a -> b
    $ Alloc m -> Field Pointer m
    forall (f :: * -> *) m a. TwistRF f m a -> f a
    twistFunctorValue Alloc m
    alctr
                    wipeIt :: Pointer -> IO ()
    wipeIt cptr :: Pointer
    cptr        = Pointer -> Word8 -> BYTES Int -> IO ()
    forall (m :: * -> *) l.
    (MonadIO m, LengthUnit l) =>
    Pointer -> Word8 -> l -> m ()
    memset Pointer
    cptr 0 BYTES Int
    sz
                    actualAction :: Pointer -> IO a
    actualAction  cptr :: Pointer
    cptr = m -> IO a
    action (Pointer -> m
    getM Pointer
    cptr) IO a -> IO () -> IO a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Pointer -> IO ()
    wipeIt Pointer
    cptr

    -- | Similar to `withMemory` but allocates a secure memory for the
    -- action. Secure memories are never swapped on to disk and will be
    -- wiped clean of sensitive data after use. However, be careful when
    -- using this function in a child thread. Due to the daemonic nature
    -- of Haskell threads, if the main thread exists before the child
    -- thread is done with its job, sensitive data can leak. This is
    -- essentially a limitation of the bracket which is used internally.
    withSecureMemory :: Memory m => (m -> IO a) -> IO a
    withSecureMemory :: (m -> IO a) -> IO a
    withSecureMemory = TwistRF AllocField (BYTES Int) m -> (m -> IO a) -> IO a
    forall l b b.
    LengthUnit l =>
    TwistRF AllocField l b -> (b -> IO b) -> IO b
    withSM TwistRF AllocField (BYTES Int) m
    forall m. Memory m => Alloc m
    memoryAlloc
      where -- withSM :: Memory m => Alloc m -> (m -> IO a) -> IO a
            withSM :: TwistRF AllocField l b -> (b -> IO b) -> IO b
    withSM alctr :: TwistRF AllocField l b
    alctr action :: b -> IO b
    action = l -> (Pointer -> IO b) -> IO b
    forall l b. LengthUnit l => l -> (Pointer -> IO b) -> IO b
    allocaSecure l
    sz ((Pointer -> IO b) -> IO b) -> (Pointer -> IO b) -> IO b
    forall a b. (a -> b) -> a -> b
    $ b -> IO b
    action (b -> IO b) -> (Pointer -> b) -> Pointer -> IO b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Pointer -> b
    getM
              where sz :: l
    sz     = TwistRF AllocField l b -> l
    forall (f :: * -> *) m a. TwistRF f m a -> m
    twistMonoidValue TwistRF AllocField l b
    alctr
                    getM :: Pointer -> b
    getM   = Field Pointer b -> Pointer -> b
    forall space b. Field space b -> space -> b
    computeField (Field Pointer b -> Pointer -> b)
    -> Field Pointer b -> Pointer -> b
    forall a b. (a -> b) -> a -> b
    $ TwistRF AllocField l b -> Field Pointer b
    forall (f :: * -> *) m a. TwistRF f m a -> f a
    twistFunctorValue TwistRF AllocField l b
    alctr

    ----------------------- Initialising and Extracting stuff ----------------------

    -- | Memories that can be initialised with a pure value. The pure
    -- value resides in the Haskell heap and hence can potentially be
    -- swapped. Therefore, this class should be avoided if compromising
    -- the initialisation value can be dangerous. Consider using
    -- `InitialiseableFromBuffer`
    --

    class Memory m => Initialisable m v where
      initialise :: v -> MT m ()

    -- | Memories from which pure values can be extracted. Once a pure value is
    -- extracted,
    class Memory m => Extractable m v where
      extract  :: MT m v

    -- | Apply the given function to the value in the cell. For a function @f :: b -> a@,
    -- the action @modify f@ first extracts a value of type @b@ from the
    -- memory element, applies @f@ to it and puts the result back into the
    -- memory.
    --
    -- > modify f = do b          <- extract
    -- >               initialise $  f b
    --
    modify :: (Initialisable mem a, Extractable mem b, MemoryThread mT ) =>  (b -> a) -> mT mem ()
    modify :: (b -> a) -> mT mem ()
    modify f :: b -> a
    f = MT mem () -> mT mem ()
    forall (mT :: * -> * -> *) mem a.
    MemoryThread mT =>
    MT mem a -> mT mem a
    liftMT (MT mem () -> mT mem ()) -> MT mem () -> mT mem ()
    forall a b. (a -> b) -> a -> b
    $ MT mem b
    forall m v. Extractable m v => MT m v
    extract MT mem b -> (b -> MT mem ()) -> MT mem ()
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= a -> MT mem ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise (a -> MT mem ()) -> (b -> a) -> b -> MT mem ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . b -> a
    f

    -- | A memory type that can be initialised from a pointer buffer. The initialisation performs
    -- a direct copy from the input buffer and hence the chances of the
    -- initialisation value ending up in the swap is minimised.
    class Memory m => InitialisableFromBuffer m where
      initialiser :: m -> ReadM (MT m)

    -- | A memory type that can extract bytes into a buffer. The extraction will perform
    -- a direct copy and hence the chances of the extracted value ending
    -- up in the swap space is minimised.
    class Memory m => ExtractableToBuffer m where
      extractor :: m -> WriteM (MT m)

    --------------------- Some instances of Memory --------------------

    -- | A memory location to store a value of type having `Storable`
    -- instance.
    newtype MemoryCell a = MemoryCell { MemoryCell a -> Ptr a
    unMemoryCell :: Ptr a }

    instance Storable a => Memory (MemoryCell a) where

      memoryAlloc :: Alloc (MemoryCell a)
    memoryAlloc = a -> Alloc (MemoryCell a)
    forall b. Storable b => b -> Alloc (MemoryCell b)
    allocator a
    forall a. HasCallStack => a
    undefined
        where allocator :: Storable b => b -> Alloc (MemoryCell b)
              allocator :: b -> Alloc (MemoryCell b)
    allocator b :: b
    b = ALIGN -> (Pointer -> MemoryCell b) -> Alloc (MemoryCell b)
    forall l mem. LengthUnit l => l -> (Pointer -> mem) -> Alloc mem
    makeAlloc (b -> ALIGN
    forall a. Storable a => a -> ALIGN
    alignedSizeOf b
    b) ((Pointer -> MemoryCell b) -> Alloc (MemoryCell b))
    -> (Pointer -> MemoryCell b) -> Alloc (MemoryCell b)
    forall a b. (a -> b) -> a -> b
    $ Ptr b -> MemoryCell b
    forall a. Ptr a -> MemoryCell a
    MemoryCell (Ptr b -> MemoryCell b)
    -> (Pointer -> Ptr b) -> Pointer -> MemoryCell b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Pointer -> Ptr b
    forall a b. Ptr a -> Ptr b
    castPtr

      unsafeToPointer :: MemoryCell a -> Pointer
    unsafeToPointer  = Ptr a -> Pointer
    forall a b. Ptr a -> Ptr b
    castPtr (Ptr a -> Pointer)
    -> (MemoryCell a -> Ptr a) -> MemoryCell a -> Pointer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . MemoryCell a -> Ptr a
    forall a. MemoryCell a -> Ptr a
    unMemoryCell

    -- | The location where the actual storing of element happens. This
    -- pointer is guaranteed to be aligned to the alignment restriction of @a@
    actualCellPtr :: Storable a => MemoryCell a -> Ptr a
    actualCellPtr :: MemoryCell a -> Ptr a
    actualCellPtr = Ptr a -> Ptr a
    forall a. Storable a => Ptr a -> Ptr a
    nextAlignedPtr (Ptr a -> Ptr a)
    -> (MemoryCell a -> Ptr a) -> MemoryCell a -> Ptr a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . MemoryCell a -> Ptr a
    forall a. MemoryCell a -> Ptr a
    unMemoryCell

    -- | Work with the underlying pointer of the memory cell. Useful while
    -- working with ffi functions.
    withCellPointer :: (MemoryThread mT, Storable a) => (Ptr a -> IO b) -> mT (MemoryCell a) b
    {-# INLINE withCellPointer #-}
    withCellPointer :: (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer action :: Ptr a -> IO b
    action = (MemoryCell a -> IO b) -> mT (MemoryCell a) b
    forall (mT :: * -> * -> *) mem a.
    MemoryThread mT =>
    (mem -> IO a) -> mT mem a
    execute ((MemoryCell a -> IO b) -> mT (MemoryCell a) b)
    -> (MemoryCell a -> IO b) -> mT (MemoryCell a) b
    forall a b. (a -> b) -> a -> b
    $ Ptr a -> IO b
    action (Ptr a -> IO b) -> (MemoryCell a -> Ptr a) -> MemoryCell a -> IO b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . MemoryCell a -> Ptr a
    forall a. Storable a => MemoryCell a -> Ptr a
    actualCellPtr

    -- | Get the pointer associated with the given memory cell.
    getCellPointer :: (MemoryThread mT, Storable a) => mT (MemoryCell a) (Ptr a)
    {-# INLINE getCellPointer #-}
    getCellPointer :: mT (MemoryCell a) (Ptr a)
    getCellPointer = MT (MemoryCell a) (Ptr a) -> mT (MemoryCell a) (Ptr a)
    forall (mT :: * -> * -> *) mem a.
    MemoryThread mT =>
    MT mem a -> mT mem a
    liftMT (MT (MemoryCell a) (Ptr a) -> mT (MemoryCell a) (Ptr a))
    -> MT (MemoryCell a) (Ptr a) -> mT (MemoryCell a) (Ptr a)
    forall a b. (a -> b) -> a -> b
    $ MemoryCell a -> Ptr a
    forall a. Storable a => MemoryCell a -> Ptr a
    actualCellPtr (MemoryCell a -> Ptr a)
    -> MT (MemoryCell a) (MemoryCell a) -> MT (MemoryCell a) (Ptr a)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> MT (MemoryCell a) (MemoryCell a)
    forall (mT :: * -> * -> *) mem. MemoryThread mT => mT mem mem
    getMemory

    instance Storable a => Initialisable (MemoryCell a) a where
      initialise :: a -> MT (MemoryCell a) ()
    initialise a :: a
    a = (MemoryCell a -> IO ()) -> MT (MemoryCell a) ()
    forall (mT :: * -> * -> *) mem a.
    MemoryThread mT =>
    (mem -> IO a) -> mT mem a
    execute ((MemoryCell a -> IO ()) -> MT (MemoryCell a) ())
    -> (MemoryCell a -> IO ()) -> MT (MemoryCell a) ()
    forall a b. (a -> b) -> a -> b
    $ (Ptr a -> a -> IO ()) -> a -> Ptr a -> IO ()
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Ptr a -> a -> IO ()
    forall a. Storable a => Ptr a -> a -> IO ()
    pokeAligned a
    a (Ptr a -> IO ())
    -> (MemoryCell a -> Ptr a) -> MemoryCell a -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . MemoryCell a -> Ptr a
    forall a. MemoryCell a -> Ptr a
    unMemoryCell
      {-# INLINE initialise #-}

    instance Storable a => Extractable (MemoryCell a) a where
      extract :: MT (MemoryCell a) a
    extract = (MemoryCell a -> IO a) -> MT (MemoryCell a) a
    forall (mT :: * -> * -> *) mem a.
    MemoryThread mT =>
    (mem -> IO a) -> mT mem a
    execute ((MemoryCell a -> IO a) -> MT (MemoryCell a) a)
    -> (MemoryCell a -> IO a) -> MT (MemoryCell a) a
    forall a b. (a -> b) -> a -> b
    $ Ptr a -> IO a
    forall a. Storable a => Ptr a -> IO a
    peekAligned (Ptr a -> IO a) -> (MemoryCell a -> Ptr a) -> MemoryCell a -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . MemoryCell a -> Ptr a
    forall a. MemoryCell a -> Ptr a
    unMemoryCell
      {-# INLINE extract #-}

    instance EndianStore a => InitialisableFromBuffer (MemoryCell a) where
      initialiser :: MemoryCell a -> ReadM (MT (MemoryCell a))
    initialiser  = Int -> Dest (Ptr a) -> ReadM (MT (MemoryCell a))
    forall a (m :: * -> *).
    (EndianStore a, MonadIO m) =>
    Int -> Dest (Ptr a) -> ReadM m
    readInto 1 (Dest (Ptr a) -> ReadM (MT (MemoryCell a)))
    -> (MemoryCell a -> Dest (Ptr a))
    -> MemoryCell a
    -> ReadM (MT (MemoryCell a))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Ptr a -> Dest (Ptr a)
    forall a. a -> Dest a
    destination (Ptr a -> Dest (Ptr a))
    -> (MemoryCell a -> Ptr a) -> MemoryCell a -> Dest (Ptr a)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . MemoryCell a -> Ptr a
    forall a. Storable a => MemoryCell a -> Ptr a
    actualCellPtr

    instance EndianStore a => ExtractableToBuffer (MemoryCell a) where
      extractor :: MemoryCell a -> WriteM (MT (MemoryCell a))
    extractor  = Int -> Src (Ptr a) -> WriteM (MT (MemoryCell a))
    forall (m :: * -> *) a.
    (MonadIO m, EndianStore a) =>
    Int -> Src (Ptr a) -> WriteM m
    writeFrom 1 (Src (Ptr a) -> WriteM (MT (MemoryCell a)))
    -> (MemoryCell a -> Src (Ptr a))
    -> MemoryCell a
    -> WriteM (MT (MemoryCell a))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Ptr a -> Src (Ptr a)
    forall a. a -> Src a
    source (Ptr a -> Src (Ptr a))
    -> (MemoryCell a -> Ptr a) -> MemoryCell a -> Src (Ptr a)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . MemoryCell a -> Ptr a
    forall a. Storable a => MemoryCell a -> Ptr a
    actualCellPtr