#include "inline.hs"

-- |
-- Module      : Streamly.Internal.FileSystem.Dir
-- Copyright   : (c) 2018 Composewell Technologies
--
-- License     : BSD3
-- Maintainer  : streamly@composewell.com
-- Portability : GHC

module Streamly.Internal.FileSystem.Dir
{-# DEPRECATED "Please use \"Streamly.Internal.FileSystem.DirIO\" instead." #-}
    (
    -- * Streams
      read

    -- read not just the names but also the inode attrs of the children. This
    -- abstraction makes sense because when we read the dir contents we also
    -- get the inodes, and it is cheaper to get the attrs from the inodes
    -- instead of resolving the paths and get those. This abstraction may be
    -- less portable as different platforms may have different attrs. To
    -- optimize, we can also add a filter/pattern/parser on the names of the
    -- children that we want to read. We can call that readAttrsWith? Or just
    -- have the default readAttrs do that? Usually we won't need that, so it
    -- may be better to keep that a separate API.
    -- , readAttrs

    -- recursive read requires us to read the attributes of the children to
    -- determine if something is a dirctory or not. Therefore, it may be a good
    -- idea to have a low level routine that also spits out the attributes of
    -- the files, we get that for free. We can also add a filter/pattern/parser
    -- on the names of the children that we want to read.
    --, readAttrsRecursive -- Options: acyclic, follow symlinks
    , readFiles
    , readDirs
    , readEither
    , readEitherPaths

    -- We can implement this in terms of readAttrsRecursive without losing
    -- perf.
    -- , readEitherRecursive -- Options: acyclic, follow symlinks
    -- , readAncestors -- read the parent chain using the .. entry.
    -- , readAncestorsAttrs

    -- * Unfolds
    -- | Use the more convenient stream APIs instead of unfolds where possible.
    , reader
    , fileReader
    , dirReader
    , eitherReader
    , eitherReaderPaths

      {-
    , toStreamWithBufferOf

    , readChunks
    , readChunksWithBufferOf

    , toChunksWithBufferOf
    , toChunks

    , write
    , writeWithBufferOf

    -- Byte stream write (Streams)
    , fromStream
    , fromStreamWithBufferOf

    -- -- * Array Write
    , writeArray
    , writeChunks
    , writeChunksWithBufferOf

    -- -- * Array stream Write
    , fromChunks
    , fromChunksWithBufferOf
    -}
    -- * Deprecated
    , toStream
    , toEither
    , toFiles
    , toDirs
    )
where

import Control.Monad.Catch (MonadCatch)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Bifunctor (bimap)
import Streamly.Data.Stream (Stream)
import Streamly.Internal.Data.Unfold.Type (Unfold(..))
import System.FilePath ((</>))
import qualified Streamly.Data.Stream as S

import Streamly.Internal.FileSystem.Path (Path)

import qualified Streamly.Internal.FileSystem.Path as Path
import qualified Streamly.Internal.FileSystem.DirIO as DirIO
import qualified Streamly.Internal.Data.Unfold as Unfold

import Prelude hiding (read)

--------------------------------------------------------------------------------
-- Helpers
--------------------------------------------------------------------------------

{-# INLINE ePathMap #-}
ePathMap :: Either Path Path -> Either FilePath FilePath
ePathMap :: Either PosixPath PosixPath -> Either FilePath FilePath
ePathMap (Left PosixPath
a) = FilePath -> Either FilePath FilePath
forall a b. a -> Either a b
Left (PosixPath -> FilePath
forall a. IsPath PosixPath a => a -> FilePath
Path.toString PosixPath
a)
ePathMap (Right PosixPath
a) = FilePath -> Either FilePath FilePath
forall a b. b -> Either a b
Right (PosixPath -> FilePath
forall a. IsPath PosixPath a => a -> FilePath
Path.toString PosixPath
a)

{-# INLINE pMapUnfold #-}
pMapUnfold :: MonadCatch m => Unfold m Path Path -> Unfold m FilePath FilePath
pMapUnfold :: forall (m :: * -> *).
MonadCatch m =>
Unfold m PosixPath PosixPath -> Unfold m FilePath FilePath
pMapUnfold = (PosixPath -> FilePath)
-> Unfold m FilePath PosixPath -> Unfold m FilePath FilePath
forall a b. (a -> b) -> Unfold m FilePath a -> Unfold m FilePath b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap PosixPath -> FilePath
forall a. IsPath PosixPath a => a -> FilePath
Path.toString (Unfold m FilePath PosixPath -> Unfold m FilePath FilePath)
-> (Unfold m PosixPath PosixPath -> Unfold m FilePath PosixPath)
-> Unfold m PosixPath PosixPath
-> Unfold m FilePath FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FilePath -> m PosixPath)
-> Unfold m PosixPath PosixPath -> Unfold m FilePath PosixPath
forall (m :: * -> *) a c b.
Monad m =>
(a -> m c) -> Unfold m c b -> Unfold m a b
Unfold.lmapM FilePath -> m PosixPath
forall (m :: * -> *) a.
(MonadThrow m, IsPath PosixPath a) =>
FilePath -> m a
Path.fromString

{-# INLINE pMapUnfoldE #-}
pMapUnfoldE
    :: MonadCatch m
    => Unfold m Path (Either Path Path)
    -> Unfold m FilePath (Either FilePath FilePath)
pMapUnfoldE :: forall (m :: * -> *).
MonadCatch m =>
Unfold m PosixPath (Either PosixPath PosixPath)
-> Unfold m FilePath (Either FilePath FilePath)
pMapUnfoldE = (Either PosixPath PosixPath -> Either FilePath FilePath)
-> Unfold m FilePath (Either PosixPath PosixPath)
-> Unfold m FilePath (Either FilePath FilePath)
forall a b. (a -> b) -> Unfold m FilePath a -> Unfold m FilePath b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Either PosixPath PosixPath -> Either FilePath FilePath
ePathMap (Unfold m FilePath (Either PosixPath PosixPath)
 -> Unfold m FilePath (Either FilePath FilePath))
-> (Unfold m PosixPath (Either PosixPath PosixPath)
    -> Unfold m FilePath (Either PosixPath PosixPath))
-> Unfold m PosixPath (Either PosixPath PosixPath)
-> Unfold m FilePath (Either FilePath FilePath)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FilePath -> m PosixPath)
-> Unfold m PosixPath (Either PosixPath PosixPath)
-> Unfold m FilePath (Either PosixPath PosixPath)
forall (m :: * -> *) a c b.
Monad m =>
(a -> m c) -> Unfold m c b -> Unfold m a b
Unfold.lmapM FilePath -> m PosixPath
forall (m :: * -> *) a.
(MonadThrow m, IsPath PosixPath a) =>
FilePath -> m a
Path.fromString

--------------------------------------------------------------------------------
-- Functions
--------------------------------------------------------------------------------

--  | Read a directory emitting a stream with names of the children. Filter out
--  "." and ".." entries.
--
--  /Internal/
--
{-# INLINE reader #-}
reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath FilePath
reader :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m FilePath FilePath
reader = (PosixPath -> FilePath)
-> Unfold m FilePath PosixPath -> Unfold m FilePath FilePath
forall a b. (a -> b) -> Unfold m FilePath a -> Unfold m FilePath b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap PosixPath -> FilePath
forall a. IsPath PosixPath a => a -> FilePath
Path.toString (Unfold m FilePath PosixPath -> Unfold m FilePath FilePath)
-> Unfold m FilePath PosixPath -> Unfold m FilePath FilePath
forall a b. (a -> b) -> a -> b
$ (FilePath -> m PosixPath)
-> Unfold m PosixPath PosixPath -> Unfold m FilePath PosixPath
forall (m :: * -> *) a c b.
Monad m =>
(a -> m c) -> Unfold m c b -> Unfold m a b
Unfold.lmapM FilePath -> m PosixPath
forall (m :: * -> *) a.
(MonadThrow m, IsPath PosixPath a) =>
FilePath -> m a
Path.fromString Unfold m PosixPath PosixPath
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m PosixPath PosixPath
DirIO.reader

-- | Read directories as Left and files as Right. Filter out "." and ".."
-- entries.
--
--  /Internal/
--
{-# INLINE eitherReader #-}
eitherReader :: (MonadIO m, MonadCatch m) => Unfold m FilePath (Either FilePath FilePath)
eitherReader :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m FilePath (Either FilePath FilePath)
eitherReader = Unfold m PosixPath (Either PosixPath PosixPath)
-> Unfold m FilePath (Either FilePath FilePath)
forall (m :: * -> *).
MonadCatch m =>
Unfold m PosixPath (Either PosixPath PosixPath)
-> Unfold m FilePath (Either FilePath FilePath)
pMapUnfoldE Unfold m PosixPath (Either PosixPath PosixPath)
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m PosixPath (Either PosixPath PosixPath)
DirIO.eitherReader


{-# INLINE eitherReaderPaths #-}
eitherReaderPaths ::(MonadIO m, MonadCatch m) => Unfold m FilePath (Either FilePath FilePath)
eitherReaderPaths :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m FilePath (Either FilePath FilePath)
eitherReaderPaths = Unfold m PosixPath (Either PosixPath PosixPath)
-> Unfold m FilePath (Either FilePath FilePath)
forall (m :: * -> *).
MonadCatch m =>
Unfold m PosixPath (Either PosixPath PosixPath)
-> Unfold m FilePath (Either FilePath FilePath)
pMapUnfoldE Unfold m PosixPath (Either PosixPath PosixPath)
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m PosixPath (Either PosixPath PosixPath)
DirIO.eitherReaderPaths

--
-- | Read files only.
--
--  /Internal/
--
{-# INLINE fileReader #-}
fileReader :: (MonadIO m, MonadCatch m) => Unfold m FilePath FilePath
fileReader :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m FilePath FilePath
fileReader = Unfold m PosixPath PosixPath -> Unfold m FilePath FilePath
forall (m :: * -> *).
MonadCatch m =>
Unfold m PosixPath PosixPath -> Unfold m FilePath FilePath
pMapUnfold Unfold m PosixPath PosixPath
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m PosixPath PosixPath
DirIO.fileReader

-- | Read directories only. Filter out "." and ".." entries.
--
--  /Internal/
--
{-# INLINE dirReader #-}
dirReader :: (MonadIO m, MonadCatch m) => Unfold m FilePath FilePath
dirReader :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m FilePath FilePath
dirReader = Unfold m PosixPath PosixPath -> Unfold m FilePath FilePath
forall (m :: * -> *).
MonadCatch m =>
Unfold m PosixPath PosixPath -> Unfold m FilePath FilePath
pMapUnfold Unfold m PosixPath PosixPath
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m PosixPath PosixPath
DirIO.dirReader

-- | Raw read of a directory.
--
-- /Pre-release/
{-# INLINE read #-}
read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m FilePath
read :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m FilePath
read = Unfold m FilePath FilePath -> FilePath -> Stream m FilePath
forall (m :: * -> *) a b.
Applicative m =>
Unfold m a b -> a -> Stream m b
S.unfold Unfold m FilePath FilePath
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m FilePath FilePath
reader

{-# DEPRECATED toStream "Please use 'read' instead" #-}
{-# INLINE toStream #-}
toStream :: (MonadIO m, MonadCatch m) => String -> Stream m String
toStream :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m FilePath
toStream = FilePath -> Stream m FilePath
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m FilePath
read

-- | Read directories as Left and files as Right. Filter out "." and ".."
-- entries. The output contains the names of the directories and files.
--
-- /Pre-release/
{-# INLINE readEither #-}
readEither :: (MonadIO m, MonadCatch m) => FilePath -> Stream m (Either FilePath FilePath)
readEither :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m (Either FilePath FilePath)
readEither = Unfold m FilePath (Either FilePath FilePath)
-> FilePath -> Stream m (Either FilePath FilePath)
forall (m :: * -> *) a b.
Applicative m =>
Unfold m a b -> a -> Stream m b
S.unfold Unfold m FilePath (Either FilePath FilePath)
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m FilePath (Either FilePath FilePath)
eitherReader

-- | Like 'readEither' but prefix the names of the files and directories with
-- the supplied directory path.
{-# INLINE readEitherPaths #-}
readEitherPaths :: (MonadIO m, MonadCatch m) => FilePath -> Stream m (Either FilePath FilePath)
readEitherPaths :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m (Either FilePath FilePath)
readEitherPaths FilePath
dir = (Either FilePath FilePath -> Either FilePath FilePath)
-> Stream m (Either FilePath FilePath)
-> Stream m (Either FilePath FilePath)
forall a b. (a -> b) -> Stream m a -> Stream m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((FilePath -> FilePath)
-> (FilePath -> FilePath)
-> Either FilePath FilePath
-> Either FilePath FilePath
forall a b c d. (a -> b) -> (c -> d) -> Either a c -> Either b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap (FilePath
dir FilePath -> FilePath -> FilePath
</>) (FilePath
dir FilePath -> FilePath -> FilePath
</>)) (Stream m (Either FilePath FilePath)
 -> Stream m (Either FilePath FilePath))
-> Stream m (Either FilePath FilePath)
-> Stream m (Either FilePath FilePath)
forall a b. (a -> b) -> a -> b
$ FilePath -> Stream m (Either FilePath FilePath)
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m (Either FilePath FilePath)
readEither FilePath
dir

{-# DEPRECATED toEither "Please use 'readEither' instead" #-}
{-# INLINE toEither #-}
toEither :: (MonadIO m, MonadCatch m) => FilePath -> Stream m (Either FilePath FilePath)
toEither :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m (Either FilePath FilePath)
toEither = FilePath -> Stream m (Either FilePath FilePath)
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m (Either FilePath FilePath)
readEither

-- | Read files only.
--
--  /Internal/
--
{-# INLINE readFiles #-}
readFiles :: (MonadIO m, MonadCatch m) => FilePath -> Stream m FilePath
readFiles :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m FilePath
readFiles = Unfold m FilePath FilePath -> FilePath -> Stream m FilePath
forall (m :: * -> *) a b.
Applicative m =>
Unfold m a b -> a -> Stream m b
S.unfold Unfold m FilePath FilePath
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m FilePath FilePath
fileReader

{-# DEPRECATED toFiles "Please use 'readFiles' instead" #-}
{-# INLINE toFiles #-}
toFiles :: (MonadIO m, MonadCatch m) => FilePath -> Stream m FilePath
toFiles :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m FilePath
toFiles = FilePath -> Stream m FilePath
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m FilePath
readFiles

-- | Read directories only.
--
--  /Internal/
--
{-# INLINE readDirs #-}
readDirs :: (MonadIO m, MonadCatch m) => FilePath -> Stream m FilePath
readDirs :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m FilePath
readDirs = Unfold m FilePath FilePath -> FilePath -> Stream m FilePath
forall (m :: * -> *) a b.
Applicative m =>
Unfold m a b -> a -> Stream m b
S.unfold Unfold m FilePath FilePath
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
Unfold m FilePath FilePath
dirReader

{-# DEPRECATED toDirs "Please use 'readDirs' instead" #-}
{-# INLINE toDirs #-}
toDirs :: (MonadIO m, MonadCatch m) => String -> Stream m String
toDirs :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m FilePath
toDirs = FilePath -> Stream m FilePath
forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
FilePath -> Stream m FilePath
readDirs