effectful-core-2.7.0.0: src/Effectful/Output/Static/Local/Array.hs
-- | Support for accumulation of values in a thread local array.
--
-- @since 2.7.0.0
module Effectful.Output.Static.Local.Array
( -- * Effect
Output
-- ** Handlers
, runOutput
-- ** Operations
, output
-- * Re-exports
, Array
) where
import Control.Monad.Primitive
import Data.Kind
import Data.Primitive.Array
import Effectful
import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
import Effectful.Internal.Utils
-- | Provide access to accumulation of values of type @o@ in a thread local
-- array.
data Output (o :: Type) :: Effect
type instance DispatchOf (Output o) = Static NoSideEffects
data instance StaticRep (Output o) = Output !Int !(MutableArray RealWorld o)
-- | Run the 'Output' effect and return the final value along with the
-- accumulated array.
runOutput :: HasCallStack => Eff (Output o : es) a -> Eff es (a, Array o)
runOutput = runOutputImpl $ \(Output size arr) -> do
freezeArray arr 0 size
-- | Append the value to the end of the array.
output
:: (HasCallStack, Output o :> es)
=> o -- ^ The value.
-> Eff es ()
output !o = unsafeEff $ \es -> do
Output size arr0 <- getEnv es
let len0 = sizeofMutableArray arr0
arr <- case size `compare` len0 of
GT -> error $ "size (" ++ show size ++ ") > len0 (" ++ show len0 ++ ")"
LT -> pure arr0
EQ -> do
let len = growCapacity len0
arr <- newArray len undefinedValue
copyMutableArray arr 0 arr0 0 size
pure arr
writeArray arr size o
putEnv es $ Output (size + 1) arr
----------------------------------------
-- Helpers
runOutputImpl
:: HasCallStack
=> (StaticRep (Output o) -> IO acc)
-> Eff (Output o : es) a
-> Eff es (a, acc)
runOutputImpl f action = unsafeEff $ \es0 -> do
arr <- newArray 0 undefinedValue
inlineBracket
(consEnv (Output 0 arr) relinkOutput es0)
unconsEnv
(\es -> (,) <$> unEff action es <*> (f =<< getEnv es))
where
relinkOutput = Relinker $ \_ (Output size arr0) -> do
arr <- cloneMutableArray arr0 0 (sizeofMutableArray arr0)
pure $ Output size arr
undefinedValue :: HasCallStack => a
undefinedValue = error "Undefined value"