{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE LambdaCase #-} module Clingo.Internal.Utils ( ClingoException, getException, ClingoWarning (..), warningString, checkAndThrow, marshall0, marshall1, marshall1V, marshall1A, marshall1RT, marshall2, marshall3V, reraiseIO ) where import Control.Monad import Control.Monad.IO.Class import Control.Monad.Catch import Data.Typeable import Data.Text (Text, pack) import Foreign import Foreign.C import qualified Clingo.Raw as Raw data ClingoException = ClingoException Raw.ClingoError String deriving (Show, Typeable) instance Exception ClingoException newtype ClingoWarning = ClingoWarning Raw.ClingoWarning deriving (Show, Typeable) instance Exception ClingoWarning getException :: MonadIO m => m ClingoException getException = liftIO $ do code <- Raw.errorCode estr <- peekCString =<< Raw.errorString code return $ ClingoException code estr {-# INLINE getException #-} warningString :: MonadIO m => ClingoWarning -> m Text warningString (ClingoWarning w) = liftIO $ Raw.warningString w >>= fmap pack . peekCString checkAndThrow :: (MonadIO m, MonadThrow m) => Raw.CBool -> m () checkAndThrow b = unless (toBool b) $ getException >>= throwM {-# INLINE checkAndThrow #-} checkAndThrowRT :: (MonadIO m, MonadThrow m) => m a -> Raw.CBool -> m (Maybe a) checkAndThrowRT a b | toBool b = Just <$> a | otherwise = do exc <- getException case exc of ClingoException Raw.ErrorRuntime _ -> return Nothing _ -> throwM exc {-# INLINE checkAndThrowRT #-} marshall0 :: (MonadIO m, MonadThrow m) => IO Raw.CBool -> m () marshall0 action = liftIO action >>= checkAndThrow {-# INLINE marshall0 #-} marshall1 :: (Storable a, MonadIO m, MonadThrow m) => (Ptr a -> IO Raw.CBool) -> m a marshall1 action = do (res, a) <- liftIO $ alloca $ \ptr -> do res <- action ptr a <- peek ptr return (res, a) checkAndThrow res return a {-# INLINE marshall1 #-} marshall1V :: (Storable a, MonadIO m) => (Ptr a -> IO ()) -> m a marshall1V action = liftIO $ alloca $ \ptr -> do _ <- action ptr peek ptr {-# INLINE marshall1V #-} marshall1RT :: (Storable a, MonadIO m) => (Ptr a -> IO Raw.CBool) -> m (Maybe a) marshall1RT action = liftIO $ alloca $ \ptr -> do res <- action ptr checkAndThrowRT (peek ptr) res {-# INLINE marshall1RT #-} marshall2 :: (Storable a, Storable b, MonadIO m, MonadThrow m) => (Ptr a -> Ptr b -> IO Raw.CBool) -> m (a,b) marshall2 action = do (res, (a,b)) <- liftIO $ alloca $ \ptr1 -> alloca $ \ptr2 -> do res <- action ptr1 ptr2 a <- peek ptr1 b <- peek ptr2 return (res, (a,b)) checkAndThrow res return (a,b) {-# INLINE marshall2 #-} marshall1A :: (Storable a, MonadIO m, MonadThrow m) => (Ptr (Ptr a) -> Ptr CSize -> IO Raw.CBool) -> m [a] marshall1A action = do (res, as) <- liftIO $ alloca $ \ptr1 -> alloca $ \ptr2 -> do res <- action ptr1 ptr2 len <- peek ptr2 arrp <- peek ptr1 arr <- peekArray (fromIntegral len) arrp return (res, arr) checkAndThrow res return as {-# INLINE marshall1A #-} marshall3V :: (Storable a, Storable b, Storable c, MonadIO m) => (Ptr a -> Ptr b -> Ptr c -> IO ()) -> m (a,b,c) marshall3V action = do (a,b,c) <- liftIO $ alloca $ \ptr1 -> alloca $ \ptr2 -> alloca $ \ptr3 -> do _ <- action ptr1 ptr2 ptr3 a <- peek ptr1 b <- peek ptr2 c <- peek ptr3 return (a,b,c) return (a,b,c) {-# INLINE marshall3V #-} reraiseIO :: IO a -> IO Raw.CBool reraiseIO action = catch (action >> return (fromBool True)) $ \(ClingoException e s) -> do withCString s $ Raw.setError e return (fromBool False) {-# INLINE reraiseIO #-}