{-# LANGUAGE OverloadedStrings #-}
module Foundation.IO.File
( FilePath
, openFile
, closeFile
, IOMode(..)
, withFile
, hGet
, hGetNonBlocking
, hGetSome
, hPut
, readFile
) where
import System.IO (Handle, IOMode)
import System.IO.Error
import qualified System.IO as S
import Foundation.Collection
import Foundation.VFS
import Basement.Types.OffsetSize
import Basement.Imports
import Foundation.Array.Internal
import Foundation.Numerical
import qualified Basement.UArray.Mutable as V
import qualified Basement.UArray as V
import Control.Exception (bracket)
import Foreign.Ptr (plusPtr)
openFile :: FilePath -> IOMode -> IO Handle
openFile :: FilePath -> IOMode -> IO Handle
openFile FilePath
filepath IOMode
mode = do
FilePath -> IOMode -> IO Handle
S.openBinaryFile (FilePath -> FilePath
filePathToLString FilePath
filepath) IOMode
mode
closeFile :: Handle -> IO ()
closeFile :: Handle -> IO ()
closeFile = Handle -> IO ()
S.hClose
hGet :: Handle -> Int -> IO (UArray Word8)
hGet :: Handle -> Int -> IO (UArray Word8)
hGet Handle
h Int
size
| Int
size forall a. Ord a => a -> a -> Bool
< Int
0 = forall a. FilePath -> Handle -> Int -> IO a
invalidBufferSize FilePath
"hGet" Handle
h Int
size
| Bool
otherwise = forall ty.
PrimType ty =>
CountOf ty -> (Ptr ty -> IO (CountOf ty)) -> IO (UArray ty)
V.createFromIO (forall ty. Int -> CountOf ty
CountOf Int
size) forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> (forall ty. Int -> CountOf ty
CountOf forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Handle -> Ptr a -> Int -> IO Int
S.hGetBuf Handle
h Ptr Word8
p Int
size)
hGetNonBlocking :: Handle -> Int -> IO (UArray Word8)
hGetNonBlocking :: Handle -> Int -> IO (UArray Word8)
hGetNonBlocking Handle
h Int
size
| Int
size forall a. Ord a => a -> a -> Bool
< Int
0 = forall a. FilePath -> Handle -> Int -> IO a
invalidBufferSize FilePath
"hGetNonBlocking" Handle
h Int
size
| Bool
otherwise = forall ty.
PrimType ty =>
CountOf ty -> (Ptr ty -> IO (CountOf ty)) -> IO (UArray ty)
V.createFromIO (forall ty. Int -> CountOf ty
CountOf Int
size) forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> (forall ty. Int -> CountOf ty
CountOf forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Handle -> Ptr a -> Int -> IO Int
S.hGetBufNonBlocking Handle
h Ptr Word8
p Int
size)
hGetSome :: Handle -> Int -> IO (UArray Word8)
hGetSome :: Handle -> Int -> IO (UArray Word8)
hGetSome Handle
h Int
size
| Int
size forall a. Ord a => a -> a -> Bool
< Int
0 = forall a. FilePath -> Handle -> Int -> IO a
invalidBufferSize FilePath
"hGetSome" Handle
h Int
size
| Bool
otherwise = forall ty.
PrimType ty =>
CountOf ty -> (Ptr ty -> IO (CountOf ty)) -> IO (UArray ty)
V.createFromIO (forall ty. Int -> CountOf ty
CountOf Int
size) forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> (forall ty. Int -> CountOf ty
CountOf forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Handle -> Ptr a -> Int -> IO Int
S.hGetBufSome Handle
h Ptr Word8
p Int
size)
hPut :: Handle -> (UArray Word8) -> IO ()
hPut :: Handle -> UArray Word8 -> IO ()
hPut Handle
h UArray Word8
arr = forall ty (prim :: * -> *) a.
(PrimMonad prim, PrimType ty) =>
UArray ty -> (Ptr ty -> prim a) -> prim a
withPtr UArray Word8
arr forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr -> forall a. Handle -> Ptr a -> Int -> IO ()
S.hPutBuf Handle
h Ptr Word8
ptr (let (CountOf Int
sz) = forall c. Collection c => c -> CountOf (Element c)
length UArray Word8
arr in Int
sz)
invalidBufferSize :: [Char] -> Handle -> Int -> IO a
invalidBufferSize :: forall a. FilePath -> Handle -> Int -> IO a
invalidBufferSize FilePath
functionName Handle
handle Int
size =
forall a. IOError -> IO a
ioError forall a b. (a -> b) -> a -> b
$ IOErrorType
-> FilePath -> Maybe Handle -> Maybe FilePath -> IOError
mkIOError IOErrorType
illegalOperationErrorType
(FilePath
functionName forall a. Semigroup a => a -> a -> a
<> FilePath
" invalid array size: " forall a. Semigroup a => a -> a -> a
<> forall l. IsList l => l -> [Item l]
toList (forall a. Show a => a -> String
show Int
size))
(forall a. a -> Maybe a
Just Handle
handle)
forall a. Maybe a
Nothing
withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
withFile :: forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
withFile FilePath
fp IOMode
mode Handle -> IO r
act = forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (FilePath -> IOMode -> IO Handle
openFile FilePath
fp IOMode
mode) Handle -> IO ()
closeFile Handle -> IO r
act
readFile :: FilePath -> IO (UArray Word8)
readFile :: FilePath -> IO (UArray Word8)
readFile FilePath
fp = forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
withFile FilePath
fp IOMode
S.ReadMode forall a b. (a -> b) -> a -> b
$ \Handle
h -> do
Integer
sz <- Handle -> IO Integer
S.hFileSize Handle
h
MUArray Word8 RealWorld
mv <- forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
CountOf ty -> prim (MUArray ty (PrimState prim))
V.newPinned (forall ty. Int -> CountOf ty
CountOf forall a b. (a -> b) -> a -> b
$ forall a. Integral a => Integer -> a
fromInteger Integer
sz)
forall (prim :: * -> *) ty a.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> (Ptr ty -> prim a) -> prim a
V.withMutablePtr MUArray Word8 RealWorld
mv forall a b. (a -> b) -> a -> b
$ forall {b}. Handle -> Int -> Ptr b -> IO ()
loop Handle
h (forall a. Integral a => Integer -> a
fromInteger Integer
sz)
forall (c :: * -> *) (prim :: * -> *).
(MutableCollection c, PrimMonad prim) =>
c (PrimState prim) -> prim (MutableFreezed c)
unsafeFreeze MUArray Word8 RealWorld
mv
where
loop :: Handle -> Int -> Ptr b -> IO ()
loop Handle
h Int
left Ptr b
dst
| Int
left forall a. Eq a => a -> a -> Bool
== Int
0 = forall (m :: * -> *) a. Monad m => a -> m a
return ()
| Bool
otherwise = do
let toRead :: Int
toRead = forall a. Ord a => a -> a -> a
min Int
blockSize Int
left
Int
r <- forall a. Handle -> Ptr a -> Int -> IO Int
S.hGetBuf Handle
h Ptr b
dst Int
toRead
if Int
r forall a. Ord a => a -> a -> Bool
> Int
0 Bool -> Bool -> Bool
&& Int
r forall a. Ord a => a -> a -> Bool
<= Int
toRead
then Handle -> Int -> Ptr b -> IO ()
loop Handle
h (Int
left forall a. Subtractive a => a -> a -> Difference a
- Int
r) (Ptr b
dst forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
r)
else forall a. HasCallStack => String -> a
error String
"readFile: "
blockSize :: Int
blockSize :: Int
blockSize = Int
4096