{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} module Hercules.CNix.Exception ( handleExceptions, handleExceptions', handleExceptionPtr, ) where import Hercules.CNix.Store.Context (context) import qualified Language.C.Inline.Cpp as C import qualified Language.C.Inline.Cpp.Exception as C import Protolude import qualified System.Environment C.context context C.include "" C.include "" C.include "" -- | Log C++ exceptions and call 'exitWith' the way Nix would exit when an -- exception occurs. handleExceptions :: IO a -> IO a handleExceptions io = do progName <- System.Environment.getProgName handleExceptions' exitWith (toS progName) io -- | Log C++ exceptions and call 'exitWith' the way Nix would exit. handleExceptions' :: -- | What to do when Nix would want to exit with 'ExitCode' (ExitCode -> IO a) -> -- | Program name (command name) Text -> IO a -> IO a handleExceptions' handleExit programName io = let select (C.CppStdException eptr _msg _t) = Just eptr select _ = Nothing convertExit 0 = ExitSuccess convertExit e = ExitFailure (fromIntegral e) doHandle = handleExit . convertExit <=< handleExceptionPtr (encodeUtf8 programName) in handleJust select doHandle io -- | Low-level wrapper around @nix::handleExceptions(rethrow_exception(e))@. handleExceptionPtr :: ByteString -> C.CppExceptionPtr -> IO C.CInt handleExceptionPtr programName eptr = [C.throwBlock| int { auto & eptr = *$fptr-ptr:(std::exception_ptr *eptr); std::string programName($bs-ptr:programName, $bs-len:programName); return nix::handleExceptions(programName, [&]() { std::rethrow_exception(eptr); }); }|]