hnix/src/Nix/Thunk/Basic.hs

118 lines
3.4 KiB
Haskell
Raw Normal View History

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
2019-03-14 23:10:41 +01:00
module Nix.Thunk.Basic (NThunkF, MonadBasicThunk) where
import Control.Exception hiding (catch)
import Control.Monad.Catch
import Nix.Fresh
import Nix.Thunk
import Nix.Utils
import Nix.Var
data Deferred m v = Deferred (m v) | Computed v
deriving (Functor, Foldable, Traversable)
-- | The type of very basic thunks
data NThunkF m v
= Value v
| Thunk Int (Var m Bool) (Var m (Deferred m v))
instance Show v => Show (NThunkF m v) where
show (Value v) = show v
show (Thunk _ _ _) = "<thunk>"
2019-03-16 01:59:38 +01:00
type MonadBasicThunk m = (MonadFreshId Int m, MonadVar m)
2019-03-16 01:59:38 +01:00
instance (MonadBasicThunk m, MonadCatch m)
2019-03-14 18:56:20 +01:00
=> MonadThunk (NThunkF m v) m v where
thunk = buildThunk
thunkId = \case
Value _ -> -1
Thunk n _ _ -> n
query = queryValue
queryM = queryThunk
force = forceThunk
forceEff = forceEffects
wrapValue = valueRef
getValue = thunkValue
valueRef :: v -> NThunkF m v
valueRef = Value
thunkValue :: NThunkF m v -> Maybe v
thunkValue (Value v) = Just v
thunkValue _ = Nothing
2019-03-16 01:59:38 +01:00
buildThunk :: MonadBasicThunk m => m v -> m (NThunkF m v)
buildThunk action =do
freshThunkId <- freshId
Thunk freshThunkId <$> newVar False <*> newVar (Deferred action)
2019-03-16 01:59:38 +01:00
queryValue :: MonadVar m => NThunkF m v -> a -> (v -> a) -> a
queryValue (Value v) _ k = k v
queryValue _ n _ = n
2019-03-16 01:59:38 +01:00
queryThunk :: MonadVar m => NThunkF m v -> m a -> (v -> m a) -> m a
queryThunk (Value v) _ k = k v
queryThunk (Thunk _ active ref) n k = do
nowActive <- atomicModifyVar active (True,)
if nowActive
then n
else do
eres <- readVar ref
res <- case eres of
Computed v -> k v
_ -> n
_ <- atomicModifyVar active (False,)
return res
forceThunk :: (MonadVar m, MonadThrow m, MonadCatch m)
=> NThunkF m v -> (v -> m a) -> m a
forceThunk (Value v) k = k v
forceThunk (Thunk n active ref) k = do
eres <- readVar ref
case eres of
Computed v -> k v
Deferred action -> do
nowActive <- atomicModifyVar active (True,)
if nowActive
then
throwM $ ThunkLoop (Just n)
else do
traceM $ "Forcing " ++ show n
v <- catch action $ \(e :: SomeException) -> do
_ <- atomicModifyVar active (False,)
throwM e
_ <- atomicModifyVar active (False,)
writeVar ref (Computed v)
k v
2019-03-15 20:49:16 +01:00
forceEffects :: MonadVar m => NThunkF m v -> (v -> m ()) -> m ()
forceEffects (Value v) k = k v
forceEffects (Thunk _ active ref) k = do
nowActive <- atomicModifyVar active (True,)
if nowActive
2019-03-15 20:49:16 +01:00
then return ()
else do
eres <- readVar ref
case eres of
Computed v -> k v
Deferred action -> do
v <- action
writeVar ref (Computed v)
_ <- atomicModifyVar active (False,)
k v