module THSH.Fn
( FnFunction (..)
, ContentFn (..), stringContentFn, stringContentIOFn, textContentFn, textContentIOFn
, LineReadFn (..), lineReadFn
, Fn, fn ) where
import System.Exit (ExitCode (..))
import System.IO (Handle, hGetContents, hGetLine, hIsEOF, hPutStr)
import qualified Data.Text as T
import qualified Data.Text.IO
import THSH.Funclet (Funclet (..))
class FnFunction f where
runFn :: f -> (Handle, Handle, Handle) -> IO ExitCode
newtype Fn f = MkFn f
fn :: FnFunction f => f -> Fn f
fn :: forall f. FnFunction f => f -> Fn f
fn = f -> Fn f
forall f. f -> Fn f
MkFn
data ContentFn m s = MkContentFn (s -> m s) (Handle -> m s) (Handle -> s -> m ())
instance FnFunction (ContentFn IO s) where
runFn :: ContentFn IO s -> (Handle, Handle, Handle) -> IO ExitCode
runFn (MkContentFn s -> IO s
f Handle -> IO s
r Handle -> s -> IO ()
w) (Handle
hIn, Handle
hOut, Handle
_) = do
content <- Handle -> IO s
r Handle
hIn
w hOut =<< f content
pure ExitSuccess
stringContentFn :: (String -> String) -> ContentFn IO String
stringContentFn :: (String -> String) -> ContentFn IO String
stringContentFn String -> String
f = (String -> IO String)
-> (Handle -> IO String)
-> (Handle -> String -> IO ())
-> ContentFn IO String
forall (m :: * -> *) s.
(s -> m s)
-> (Handle -> m s) -> (Handle -> s -> m ()) -> ContentFn m s
MkContentFn (String -> IO String
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> IO String) -> (String -> String) -> String -> IO String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
f) Handle -> IO String
hGetContents Handle -> String -> IO ()
hPutStr
stringContentIOFn :: (String -> IO String) -> ContentFn IO String
stringContentIOFn :: (String -> IO String) -> ContentFn IO String
stringContentIOFn String -> IO String
f = (String -> IO String)
-> (Handle -> IO String)
-> (Handle -> String -> IO ())
-> ContentFn IO String
forall (m :: * -> *) s.
(s -> m s)
-> (Handle -> m s) -> (Handle -> s -> m ()) -> ContentFn m s
MkContentFn String -> IO String
f Handle -> IO String
hGetContents Handle -> String -> IO ()
hPutStr
textContentFn :: (T.Text -> T.Text) -> ContentFn IO T.Text
textContentFn :: (Text -> Text) -> ContentFn IO Text
textContentFn Text -> Text
f = (Text -> IO Text)
-> (Handle -> IO Text)
-> (Handle -> Text -> IO ())
-> ContentFn IO Text
forall (m :: * -> *) s.
(s -> m s)
-> (Handle -> m s) -> (Handle -> s -> m ()) -> ContentFn m s
MkContentFn (Text -> IO Text
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> IO Text) -> (Text -> Text) -> Text -> IO Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
f) Handle -> IO Text
Data.Text.IO.hGetContents Handle -> Text -> IO ()
Data.Text.IO.hPutStr
textContentIOFn :: (T.Text -> IO T.Text) -> ContentFn IO T.Text
textContentIOFn :: (Text -> IO Text) -> ContentFn IO Text
textContentIOFn Text -> IO Text
f = (Text -> IO Text)
-> (Handle -> IO Text)
-> (Handle -> Text -> IO ())
-> ContentFn IO Text
forall (m :: * -> *) s.
(s -> m s)
-> (Handle -> m s) -> (Handle -> s -> m ()) -> ContentFn m s
MkContentFn Text -> IO Text
f Handle -> IO Text
Data.Text.IO.hGetContents Handle -> Text -> IO ()
Data.Text.IO.hPutStr
data LineReadFn m a b = Read a
=> MkLineReadFn
(a -> b -> m (b, Maybe String))
(b -> m (Maybe String))
b
lineReadFn :: forall a b.
Read a
=> (a -> b -> (b, Maybe String))
-> (b -> Maybe String)
-> b
-> LineReadFn IO a b
lineReadFn :: forall a b.
Read a =>
(a -> b -> (b, Maybe String))
-> (b -> Maybe String) -> b -> LineReadFn IO a b
lineReadFn a -> b -> (b, Maybe String)
f b -> Maybe String
fin b
b0 = (a -> b -> IO (b, Maybe String))
-> (b -> IO (Maybe String)) -> b -> LineReadFn IO a b
forall (m :: * -> *) a b.
Read a =>
(a -> b -> m (b, Maybe String))
-> (b -> m (Maybe String)) -> b -> LineReadFn m a b
MkLineReadFn (((b, Maybe String) -> IO (b, Maybe String)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((b, Maybe String) -> IO (b, Maybe String))
-> (b -> (b, Maybe String)) -> b -> IO (b, Maybe String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((b -> (b, Maybe String)) -> b -> IO (b, Maybe String))
-> (a -> b -> (b, Maybe String)) -> a -> b -> IO (b, Maybe String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b -> (b, Maybe String)
f) (Maybe String -> IO (Maybe String)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe String -> IO (Maybe String))
-> (b -> Maybe String) -> b -> IO (Maybe String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Maybe String
fin) b
b0
instance FnFunction (LineReadFn IO a b) where
runFn :: LineReadFn IO a b -> (Handle, Handle, Handle) -> IO ExitCode
runFn (MkLineReadFn a -> b -> IO (b, Maybe String)
f b -> IO (Maybe String)
fin b
b0) (Handle
hIn, Handle
hOut, Handle
_) = do
let go :: b -> [IO (Maybe a)] -> IO ()
go b
b (IO (Maybe a)
a:[IO (Maybe a)]
as) = IO (Maybe a)
a IO (Maybe a) -> (Maybe a -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just a
a' -> a -> b -> IO (b, Maybe String)
f a
a' b
b IO (b, Maybe String) -> ((b, Maybe String) -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ (b
b', Maybe String
r) ->
case Maybe String
r of
Just String
r' -> Handle -> String -> IO ()
hPutStr Handle
hOut String
r'
Maybe String
Nothing -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> b -> [IO (Maybe a)] -> IO ()
go b
b' [IO (Maybe a)]
as
Maybe a
Nothing -> b -> IO (Maybe String)
fin b
b IO (Maybe String) -> (Maybe String -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just String
a' -> Handle -> String -> IO ()
hPutStr Handle
hOut String
a'
Maybe String
Nothing -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
go b
_ [IO (Maybe a)]
_ = String -> IO ()
forall a. HasCallStack => String -> a
error String
"impossible"
b -> [IO (Maybe a)] -> IO ()
go b
b0 ([IO (Maybe a)] -> IO ()) -> [IO (Maybe a)] -> IO ()
forall a b. (a -> b) -> a -> b
$ IO (Maybe a) -> [IO (Maybe a)]
forall a. a -> [a]
repeat (Handle -> IO Bool
hIsEOF Handle
hIn IO Bool -> (Bool -> IO (Maybe a)) -> IO (Maybe a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ case
Bool
False -> Handle -> IO String
hGetLine Handle
hIn IO String -> (String -> IO (Maybe a)) -> IO (Maybe a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe a -> IO (Maybe a)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe a -> IO (Maybe a))
-> (String -> Maybe a) -> String -> IO (Maybe a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> (String -> a) -> String -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> a
forall a. Read a => String -> a
read :: String -> a)
Bool
True -> Maybe a -> IO (Maybe a)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing)
ExitCode -> IO ExitCode
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ExitCode
ExitSuccess
instance FnFunction f => Funclet (Fn f) where
runFuncletWithHandles :: Fn f -> (ExitCode -> IO ()) -> (Handle, Handle, Handle) -> IO ()
runFuncletWithHandles (MkFn f
f) ExitCode -> IO ()
cb (Handle, Handle, Handle)
handles = ExitCode -> IO ()
cb (ExitCode -> IO ()) -> IO ExitCode -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< f -> (Handle, Handle, Handle) -> IO ExitCode
forall f.
FnFunction f =>
f -> (Handle, Handle, Handle) -> IO ExitCode
runFn f
f (Handle, Handle, Handle)
handles