hnix-0.13.0: src/Nix/String/Coerce.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
module Nix.String.Coerce where
import Control.Monad.Catch ( MonadThrow )
import qualified Data.HashMap.Lazy as M
import Nix.Atoms
import Nix.Effects
import Nix.Frames
import Nix.String
import Nix.Value
import Nix.Value.Monad
#ifdef MIN_VERSION_ghc_datasize
#if MIN_VERSION_ghc_datasize(0,2,0)
import GHC.DataSize
#endif
#endif
-- | Data type to avoid boolean blindness on what used to be called coerceMore
data CoercionLevel
= CoerceStringy
-- ^ Coerce only stringlike types: strings, paths, and appropriate sets
| CoerceAny
-- ^ Coerce everything but functions
deriving (Eq,Ord,Enum,Bounded)
-- | Data type to avoid boolean blindness on what used to be called copyToStore
data CopyToStoreMode
= CopyToStore
-- ^ Add paths to the store as they are encountered
| DontCopyToStore
-- ^ Add paths to the store as they are encountered
deriving (Eq,Ord,Enum,Bounded)
coerceToString
:: ( Framed e m
, MonadStore m
, MonadThrow m
, MonadDataErrorContext t f m
, MonadValue (NValue t f m) m
)
=> (NValue t f m -> NValue t f m -> m (NValue t f m))
-> CopyToStoreMode
-> CoercionLevel
-> NValue t f m
-> m NixString
coerceToString call ctsm clevel = go
where
go x =
do
x' <- demand x
bool
(coerceStringy x')
(coerceAny x')
(clevel == CoerceAny)
where
coerceAny x' =
case x' of
-- TODO Return a singleton for "" and "1"
NVConstant (NBool b) ->
castToNixString $
bool
""
"1"
b
NVConstant (NInt n) ->
castToNixString $
show n
NVConstant (NFloat n) ->
castToNixString $
show n
NVConstant NNull ->
castToNixString ""
-- NVConstant: NAtom (NURI Text) is not matched
NVList l ->
nixStringUnwords <$> traverse (go <=< demand) l
v -> coerceStringy v
coerceStringy x' =
case x' of
NVStr ns -> pure ns
NVPath p ->
bool
(castToNixString . toText)
(fmap storePathToNixString . addPath)
(ctsm == CopyToStore)
p
v@(NVSet s _) ->
maybe
(maybe
(err v)
(gosw False)
(M.lookup "outPath" s)
)
(gosw True)
(M.lookup "__toString" s)
where
gosw b p =
do
p' <- demand p
bool
go
(go <=< (`call` v))
b
p'
v -> err v
err v = throwError $ ErrorCall $ "Expected a string, but saw: " <> show v
castToNixString = pure . makeNixStringWithoutContext
nixStringUnwords = intercalateNixString (makeNixStringWithoutContext " ")
storePathToNixString :: StorePath -> NixString
storePathToNixString sp = makeNixStringWithSingletonContext
t
(StringContext t DirectPath)
where
t = toText $ unStorePath sp