{-# LANGUAGE UndecidableInstances #-}

module Shrun.Configuration.Data.CommandLogging.ReadStrategy
  ( ReadStrategy (..),
    parseReadStrategy,
    readStrategyMeta,
    defaultReadStrategy,
    readBlockLineBufferNotAllowed,
  )
where

import Shrun.Command.Types (CommandP1)
import Shrun.Prelude
import Shrun.Utils qualified as Utils

-- | Different read strategies for simplicity vs. potential prettier
-- formatting.
data ReadStrategy
  = -- | Reads N bytes at a time.
    ReadBlock
  | -- | Reads N bytes at a time, but attempts to distinguish "complete" (newline
    -- terminated) vs. "partial" (anything else) reads. We do this to make
    -- the file log output prettier.
    ReadBlockLineBuffer
  deriving stock (ReadStrategy
ReadStrategy -> ReadStrategy -> Bounded ReadStrategy
forall a. a -> a -> Bounded a
$cminBound :: ReadStrategy
minBound :: ReadStrategy
$cmaxBound :: ReadStrategy
maxBound :: ReadStrategy
Bounded, Int -> ReadStrategy
ReadStrategy -> Int
ReadStrategy -> [ReadStrategy]
ReadStrategy -> ReadStrategy
ReadStrategy -> ReadStrategy -> [ReadStrategy]
ReadStrategy -> ReadStrategy -> ReadStrategy -> [ReadStrategy]
(ReadStrategy -> ReadStrategy)
-> (ReadStrategy -> ReadStrategy)
-> (Int -> ReadStrategy)
-> (ReadStrategy -> Int)
-> (ReadStrategy -> [ReadStrategy])
-> (ReadStrategy -> ReadStrategy -> [ReadStrategy])
-> (ReadStrategy -> ReadStrategy -> [ReadStrategy])
-> (ReadStrategy -> ReadStrategy -> ReadStrategy -> [ReadStrategy])
-> Enum ReadStrategy
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: ReadStrategy -> ReadStrategy
succ :: ReadStrategy -> ReadStrategy
$cpred :: ReadStrategy -> ReadStrategy
pred :: ReadStrategy -> ReadStrategy
$ctoEnum :: Int -> ReadStrategy
toEnum :: Int -> ReadStrategy
$cfromEnum :: ReadStrategy -> Int
fromEnum :: ReadStrategy -> Int
$cenumFrom :: ReadStrategy -> [ReadStrategy]
enumFrom :: ReadStrategy -> [ReadStrategy]
$cenumFromThen :: ReadStrategy -> ReadStrategy -> [ReadStrategy]
enumFromThen :: ReadStrategy -> ReadStrategy -> [ReadStrategy]
$cenumFromTo :: ReadStrategy -> ReadStrategy -> [ReadStrategy]
enumFromTo :: ReadStrategy -> ReadStrategy -> [ReadStrategy]
$cenumFromThenTo :: ReadStrategy -> ReadStrategy -> ReadStrategy -> [ReadStrategy]
enumFromThenTo :: ReadStrategy -> ReadStrategy -> ReadStrategy -> [ReadStrategy]
Enum, ReadStrategy -> ReadStrategy -> Bool
(ReadStrategy -> ReadStrategy -> Bool)
-> (ReadStrategy -> ReadStrategy -> Bool) -> Eq ReadStrategy
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ReadStrategy -> ReadStrategy -> Bool
== :: ReadStrategy -> ReadStrategy -> Bool
$c/= :: ReadStrategy -> ReadStrategy -> Bool
/= :: ReadStrategy -> ReadStrategy -> Bool
Eq, Int -> ReadStrategy -> ShowS
[ReadStrategy] -> ShowS
ReadStrategy -> String
(Int -> ReadStrategy -> ShowS)
-> (ReadStrategy -> String)
-> ([ReadStrategy] -> ShowS)
-> Show ReadStrategy
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ReadStrategy -> ShowS
showsPrec :: Int -> ReadStrategy -> ShowS
$cshow :: ReadStrategy -> String
show :: ReadStrategy -> String
$cshowList :: [ReadStrategy] -> ShowS
showList :: [ReadStrategy] -> ShowS
Show)

instance DecodeTOML ReadStrategy where
  tomlDecoder :: Decoder ReadStrategy
tomlDecoder = Decoder Text -> Decoder ReadStrategy
forall (m :: Type -> Type). MonadFail m => m Text -> m ReadStrategy
parseReadStrategy Decoder Text
forall a. DecodeTOML a => Decoder a
tomlDecoder

instance Pretty ReadStrategy where
  pretty :: forall ann. ReadStrategy -> Doc ann
pretty = \case
    ReadStrategy
ReadBlock -> Doc ann
"block"
    ReadStrategy
ReadBlockLineBuffer -> Doc ann
"block-line-buffer"

defaultReadStrategy :: Bool -> Bool -> NESeq CommandP1 -> ReadStrategy
defaultReadStrategy :: Bool -> Bool -> NESeq CommandP1 -> ReadStrategy
defaultReadStrategy Bool
isFileLog Bool
isFileLogMulti NESeq CommandP1
cmds =
  if Bool -> Bool -> NESeq CommandP1 -> Bool
readBlockLineBufferNotAllowed Bool
isFileLog Bool
isFileLogMulti NESeq CommandP1
cmds
    then ReadStrategy
ReadBlock
    else ReadStrategy
ReadBlockLineBuffer

readBlockLineBufferNotAllowed :: Bool -> Bool -> NESeq CommandP1 -> Bool
readBlockLineBufferNotAllowed :: Bool -> Bool -> NESeq CommandP1 -> Bool
readBlockLineBufferNotAllowed Bool
isFileLog Bool
isFileLogMulti NESeq CommandP1
cmds =
  Bool
isMulti
    Bool -> Bool -> Bool
&& Bool
isFileLog
    Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
isFileLogMulti
  where
    isMulti :: Bool
isMulti = NESeq CommandP1 -> Int
forall a. NESeq a -> Int
forall (t :: Type -> Type) a. Foldable t => t a -> Int
length NESeq CommandP1
cmds Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1

-- | Parses 'ReadStrategy'.
parseReadStrategy :: (MonadFail m) => m Text -> m ReadStrategy
parseReadStrategy :: forall (m :: Type -> Type). MonadFail m => m Text -> m ReadStrategy
parseReadStrategy = (m Text -> (Text -> m ReadStrategy) -> m ReadStrategy
forall a b. m a -> (a -> m b) -> m b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> (Bool, [Text]) -> Text -> m ReadStrategy
forall a (m :: Type -> Type).
(Bounded a, Enum a, MonadFail m, Pretty a) =>
Text -> (Bool, [Text]) -> Text -> m a
Utils.inversePrettyFail Text
"read-strategy" (Bool, [Text])
forall a. IsString a => (Bool, [a])
readStrategyMeta)
{-# INLINEABLE parseReadStrategy #-}

-- | Available 'ReadStrategy' strings.
readStrategyMeta :: (IsString a) => Tuple2 Bool (List a)
readStrategyMeta :: forall a. IsString a => (Bool, [a])
readStrategyMeta = (Bool
False, [a
"block", a
"block-line-buffer"])