disk-bytes-0.1.0.0: src/System/Mem/Disk/BytesPlain.hs
-- | Simpler implementation of 'DiskBytes' using 'mkWeakIORef'.
-- It looks like this implementation is not significantly worse than the
-- one trying to use GHC-specific primitives.
module System.Mem.Disk.BytesPlain
( DiskBytes
, toDiskBytes
, fromDiskBytes
) where
import Data.ByteString
( ByteString )
import Data.Int
( Int64 )
import Data.IORef
( IORef, newIORef, readIORef, mkWeakIORef )
import System.IO.Unsafe
( unsafePerformIO )
import System.Mem.Disk.DiskApi
( Disk (..) )
{-----------------------------------------------------------------------------
DiskBytes
------------------------------------------------------------------------------}
-- | A sequence of bytes that is stored on disk
-- -- if and only if the value is evaluated to WHNF.
--
-- The value is subject to normal garbage collection:
-- When the value is no longer referenced,
-- the disk memory will be freed (eventually).
newtype DiskBytes = DiskBytes { unDiskBytes :: IORef DiskBytesData }
data DiskBytesData = DiskBytesData
{ index :: !Int64
, disk :: Disk
}
-- | Offload a sequence of bytes onto a 'Disk'.
--
-- NOTE: The result must be evaluated to WHNF before the data actually
-- on disk! Also keep in mind that the original 'ByteString' needs
-- to be garbage collected.
toDiskBytes :: Disk -> ByteString -> DiskBytes
toDiskBytes disk = unsafePerformIO . mkDiskBytes disk
mkDiskBytes :: Disk -> ByteString -> IO DiskBytes
mkDiskBytes disk bytes = do
index <- put disk bytes
ptr <- newIORef DiskBytesData{index, disk}
_ <- mkWeakIORef ptr (finalizer ptr)
pure $ DiskBytes ptr
finalizer :: IORef DiskBytesData -> IO ()
finalizer ptr = do
DiskBytesData{index,disk} <- readIORef ptr
delete disk index
-- | Read the sequence of bytes back into RAM.
fromDiskBytes :: DiskBytes -> ByteString
fromDiskBytes = unsafePerformIO . unpackM
unpackM :: DiskBytes -> IO ByteString
unpackM (DiskBytes ptr) = do
DiskBytesData{index,disk} <- readIORef ptr
get disk index