dataframe-1.3.0.0: src/DataFrame/IO/Utils/RandomAccess.hs
{-# LANGUAGE FlexibleInstances #-}
module DataFrame.IO.Utils.RandomAccess where
import Control.Monad.IO.Class (MonadIO (..))
import Data.ByteString (ByteString)
import Data.ByteString.Internal (ByteString (PS))
import qualified Data.Vector.Storable as VS
import Data.Word (Word8)
import DataFrame.IO.Parquet.Seeking (
FileBufferedOrSeekable,
fGet,
fSeek,
readLastBytes,
)
import Foreign (castForeignPtr)
import System.IO (
SeekMode (AbsoluteSeek),
)
uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
uncurry3 f (a, b, c) = f a b c
data Range = Range {offset :: !Integer, length :: !Int} deriving (Eq, Show)
class (Monad m) => RandomAccess m where
readBytes :: Range -> m ByteString
readRanges :: [Range] -> m [ByteString]
readRanges = mapM readBytes
readSuffix :: Int -> m ByteString
newtype ReaderIO r a = ReaderIO {runReaderIO :: r -> IO a}
instance Functor (ReaderIO r) where
fmap f (ReaderIO run) = ReaderIO $ fmap f . run
instance Applicative (ReaderIO r) where
pure a = ReaderIO $ \_ -> pure a
(ReaderIO fg) <*> (ReaderIO fa) = ReaderIO $ \r -> do
a <- fa r
g <- fg r
pure (g a)
instance Monad (ReaderIO r) where
return = pure
(ReaderIO ma) >>= f = ReaderIO $ \r -> do
a <- ma r
runReaderIO (f a) r
instance MonadIO (ReaderIO r) where
liftIO io = ReaderIO $ const io
type LocalFile = ReaderIO FileBufferedOrSeekable
instance RandomAccess LocalFile where
readBytes (Range offset' length') = ReaderIO $ \handle -> do
fSeek handle AbsoluteSeek offset'
fGet handle length'
readSuffix n = ReaderIO (readLastBytes $ fromIntegral n)
type MMappedFile = ReaderIO (VS.Vector Word8)
-- The instance exists but we don't have the means to mmap the file currently
instance RandomAccess MMappedFile where
readBytes (Range offset' length') =
ReaderIO $
pure . unsafeToByteString . VS.slice (fromInteger offset') length'
readSuffix n =
ReaderIO $ \v ->
let len = VS.length v
n' = min n len
start = len - n'
in pure . unsafeToByteString $ VS.slice start n' v
unsafeToByteString :: VS.Vector Word8 -> ByteString
unsafeToByteString v = PS (castForeignPtr ptr) offset' len
where
(ptr, offset', len) = VS.unsafeToForeignPtr v