module Network.NineP.File
( isDir
, simpleFile
, simpleFileBy
, simpleDirectory
, rwFile
, memoryFile
, memoryDirectory
) where
import Control.Concurrent.Chan
import Control.Exception
import Control.Monad
import Control.Monad.EmbedIO
import Control.Monad.Trans
import Data.ByteString.Lazy.Char8 (ByteString)
import qualified Data.ByteString.Lazy.Char8 as B
import Data.Bits
import Data.Convertible.Base
import Data.IORef
import Data.StateRef
import Data.Word
import Prelude hiding (read)
import Network.NineP.Error
import Network.NineP.Internal.File
isDir :: Word32
-> Bool
isDir perms = testBit perms 31
simpleRead :: (Monad m, EmbedIO m) => m ByteString -> Word64 -> Word32 -> m ByteString
simpleRead get offset count = do
r <- get
(return . B.take (fromIntegral count) . B.drop (fromIntegral offset)) r
simpleWrite :: (Monad m, EmbedIO m) => (ByteString -> m ()) -> Word64 -> ByteString -> m Word32
simpleWrite put offset d = case offset of
_ -> do
r <- put d
(const $ return $ fromIntegral $ B.length d) r
rwFile :: forall m. (EmbedIO m)
=> String
-> Maybe (m ByteString)
-> Maybe (ByteString -> m ())
-> NineFile m
rwFile name rc wc = simpleFileBy name (maybe (fst nulls) id rc, maybe (snd nulls) id wc) (id, id)
nulls :: MonadIO m => (m a, a -> m ())
nulls = (throw $ Underflow, const $ return ())
simpleFile :: forall a b m rr wr. (Monad m, EmbedIO m, ReadRef rr m a, Convertible a ByteString, WriteRef wr m b, Convertible ByteString b)
=> String
-> rr
-> wr
-> NineFile m
simpleFile name rr wr = simpleFileBy name (readReference rr, writeReference wr) (convert, convert)
simpleFileBy :: forall a b m. (Monad m, EmbedIO m)
=> String
-> (m a, b -> m ())
-> (a -> ByteString, ByteString -> b)
-> NineFile m
simpleFileBy name (rd, wr) (rdc, wrc) = (boringFile name :: NineFile m) {
read = simpleRead $ liftM rdc $ rd,
write = simpleWrite $ wr . wrc
}
memoryFile :: forall m. (Monad m, EmbedIO m)
=> String
-> IO (NineFile m)
memoryFile name = do
c <- newIORef "" :: IO (IORef ByteString)
return $ simpleFileBy name (
liftIO $ readIORef c,
liftIO . writeIORef c
) (id, id)
simpleDirectory :: forall m. (Monad m, EmbedIO m)
=> String
-> (String -> m (NineFile m))
-> (String -> m (NineFile m))
-> IO (NineFile m, IORef [(String, NineFile m)])
simpleDirectory name newfile newdir = do
files <- newIORef [] :: IO (IORef [(String, NineFile m)])
return $ (\f -> (f, files)) $ (boringDir name [] :: NineFile m) {
create = \name perms -> do
nf <- (if isDir perms then newdir else newfile) name
let nelem = (name, nf)
liftIO $ atomicModifyIORef' files (\l -> (nelem:l, ()))
return nf,
getFiles = liftIO $ liftM (map snd) $ readIORef files,
descend = \name -> do
d <- liftIO $ readIORef files
maybe (throw $ ENoFile name) (return) $ lookup name d
}
memoryDirectory :: forall m. (Monad m, EmbedIO m)
=> String
-> IO (NineFile m)
memoryDirectory name = liftM fst $ simpleDirectory name (liftIO . memoryFile) (liftIO . memoryDirectory)