polysemy-scoped-fs-0.1.0.0: src/Polysemy/FS/Scoped/Text/Internal.hs
{-|
Copyright : (c) Hisaket VioletRed, 2022
License : AGPL-3.0-or-later
Maintainer : hisaket@outlook.jp
Stability : experimental
Portability : POSIX
-}
module Polysemy.FS.Scoped.Text.Internal where
import qualified System.IO as IO
import Polysemy
( Member, Sem, embed, Embed, InterpretersFor, Members, interpret )
import qualified Polysemy.SequentialAccess.Text as SAT
import qualified Polysemy.SequentialAccess as SA
import Polysemy.Internal.Kind ( Append )
import Polysemy.Resource ( Resource )
import Control.Category ( (>>>) )
import Data.Functor ( (<&>) )
import Polysemy.FS.Scoped.Internal as Scoped
( ScopedFile, scopedFileToIO, seekToBegin, seekToEnd )
import qualified Polysemy.FS.Scoped as Scoped
import Polysemy.Internal.Sing ( KnownList )
import qualified Data.Text.IO as TIO
import qualified GHC.IO.Handle as IO
readToIO :: Member (Embed IO) r => IO.Handle -> Sem (SAT.ReadLine ': SAT.ReadToEnd ': r) a -> Sem r a
readToIO h =
interpret (\(SA.Read SAT.Line) -> embed $ TIO.hGetLine h)
>>> interpret
( \(SA.Read SA.ToEnd) ->
embed $ (TIO.hGetContents =<< IO.hDuplicate h) <* seekToEnd h
)
extendToIO :: Member (Embed IO) r => IO.Handle -> Sem (SAT.Extend ': r) a -> Sem r a
extendToIO h = interpret \(SA.Extend t) -> embed $ restoreCursor h $ seekToEnd h *> TIO.hPutStr h t
restoreCursor :: IO.Handle -> IO a -> IO a
restoreCursor h m = do
before <- IO.hTell h
m <* IO.hSeek h IO.AbsoluteSeek before
clearToIO :: Member (Embed IO) r => IO.Handle -> Sem (SAT.Clear ': r) a -> Sem r a
clearToIO h = interpret \(SA.Resize SA.NullSize) -> embed $ IO.hSetFileSize h 0
cursorToIO :: Member (Embed IO) r => IO.Handle -> Sem (Append SAT.Cursor r) a -> Sem r a
cursorToIO h =
interpret
( \SA.GetPosition -> embed $
IO.hTell h >>= \case
0 -> pure $ SA.End SA.TOF
_ -> IO.hIsEOF h <&> \case
False -> SA.Intermediate
True -> SA.End SA.EOF
)
>>> interpret
(\(SA.Seek end) -> embed $ case end of
SA.TOF -> seekToBegin h
SA.EOF -> seekToEnd h
)
scopedTextFileToIO
:: (Members '[Embed IO, Resource] r, KnownList es)
=> IO.IOMode
-> (IO.Handle -> InterpretersFor es r)
-> (∀handle'. Sem (Scoped.ScopedFile mode es b handle' ': r) a)
-> Sem r a
scopedTextFileToIO = Scoped.scopedFileToIO IO.openFile