{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE UndecidableInstances #-}
module Database.Dpi.Util where
import Database.Dpi.Internal
import Database.Dpi.Prelude
import Control.Exception
import qualified Data.Text as T
isOk :: CInt -> Bool
isOk = (== success)
data DpiException
= ErrorInfoException Data_ErrorInfo
deriving Show
instance Exception DpiException
class WithPtrs a where
withPtrs :: (a -> IO b) -> IO b
instance Storable a => WithPtrs (Ptr a) where
withPtrs = alloca
instance (WithPtrs a, WithPtrs b) => WithPtrs (a, b) where
withPtrs f = withPtrs $ \a -> withPtrs $ \b -> f (a,b)
class HasMonad m r | r -> m where
app :: m a -> (a -> r) -> r
unM :: m r -> r
unM ma = app ma id
instance Monad m => HasMonad m (m a) where
app = (>>=)
instance (HasMonad m r) => HasMonad m (a -> r) where
app mb f = app mb . flip f
inVar :: a -> (a -> r) -> r
inVar = (&)
class ToString s where
toString :: s -> String
instance ToString String where
toString = id
instance ToString Text where
toString = T.unpack
inStr :: (HasMonad IO r, ToString s) => s -> (CString -> r) -> r
inStr text f = unM $ withCString (toString text) (return . f)
inStrLen :: (HasMonad IO r, ToString s, Integral n) => s -> (Ptr CChar -> n -> r) -> r
inStrLen text f = unM $ withCStringLen (toString text) $ \(c,clen) -> return $ f c (fromIntegral clen)
inInt :: (Num n, Integral i) => i -> (n -> r) -> r
inInt n f = f $ fromIntegral n
inEnum :: (Enum e, Integral n) => e -> (n -> r) -> r
inEnum e f = f $ fe e
inBool :: Integral n => Bool -> (n -> r) -> r
inBool b f = f $ fromBool b
inPtr :: (HasMonad IO r, Storable a) => (Ptr a -> IO b) -> (Ptr a -> r) -> r
inPtr init f = unM $ withPtrs $ \c -> init c >> return (f c)
outBool :: IO CInt -> IO Bool
outBool = (isOk <$>)
setText :: (Ptr a -> Ptr CChar -> CUInt -> IO CInt) -> HasCxtPtr a -> Text -> IO Bool
setText f (cxt,p) s = f p & inStrLen s & outBool
getContextError :: PtrContext -> IO Data_ErrorInfo
getContextError p = alloca $ \pe -> libContextGetError p pe >> peek pe
throwContextError :: HasCallStack => PtrContext -> IO a
throwContextError cxt = getContextError cxt >>= throw . ErrorInfoException
outValue :: (WithPtrs a) => PtrContext -> (a -> IO b) -> (a -> IO CInt) -> IO b
outValue cxt ab = outValue' cxt ab return
outValue' :: (WithPtrs a, HasCallStack) => PtrContext -> (a -> IO b) -> (a -> IO c) -> (a -> IO CInt) -> IO b
outValue' cxt ab be lib = withPtrs $ \a -> do
be a
r <- lib a
if isOk r then ab a else throwContextError cxt
runIndex f (cxt,p) = f p & out2Value cxt go
where
go (pos,pin) = do
ok <- peekBool pin
if ok then Just <$> peekInt pos else return Nothing
out2Value :: (Storable x, Storable y) => PtrContext -> ((Ptr x, Ptr y) -> IO b) -> (Ptr x -> Ptr y -> IO CInt) -> IO b
out2Value cxt f g = outValue cxt f (uncurry g)
out3Value
:: (Storable x, Storable y, Storable z)
=> PtrContext -> (((Ptr x, Ptr y), Ptr z) -> IO b) -> (Ptr x -> Ptr y -> Ptr z -> IO CInt) -> IO b
out3Value cxt f g = outValue cxt f (go g)
where
go f ((x,y),z) = f x y z
out4Value
:: (Storable x, Storable y, Storable z, Storable w)
=> PtrContext -> (((Ptr x, Ptr y), (Ptr z,Ptr w)) -> IO b) -> (Ptr x -> Ptr y -> Ptr z -> Ptr w -> IO CInt) -> IO b
out4Value cxt f g = outValue cxt f (go g)
where
go f ((x,y),(z,w)) = f x y z w
runBool :: (Ptr a -> IO CInt) -> (PtrContext, Ptr a) -> IO Bool
runBool f (_, p) = isOk <$> f p
runInt :: (Storable i, Integral i, Integral n) => (Ptr a -> Ptr i -> IO CInt) -> HasCxtPtr a -> IO n
runInt f p = fromIntegral <$> runVar f p
runMaybeInt :: (Storable i, Integral i, Integral n) => (Ptr a -> Ptr i -> IO CInt) -> HasCxtPtr a -> IO (Maybe n)
runMaybeInt f p = fmap fromIntegral <$> runMaybeVar f p
runText :: (Ptr a -> Ptr (Ptr CChar) -> Ptr CUInt -> IO CInt) -> HasCxtPtr a -> IO Text
runText f (cxt,p) = f p & out2Value cxt peekCStrLen
runVar :: Storable i => (Ptr a -> Ptr i -> IO CInt) -> HasCxtPtr a -> IO i
runVar f (cxt,p) = f p & outValue cxt peek
runMaybeVar :: Storable i => (Ptr a -> Ptr i -> IO CInt) -> HasCxtPtr a -> IO (Maybe i)
runMaybeVar f (cxt,p) = f p & outValue cxt (mapM peek . toMaybePtr)
peekWithCxt :: Storable a => PtrContext -> Ptr a -> IO (PtrContext, a)
peekWithCxt cxt p = (cxt,) <$> peek p
peekInt :: (Num n, Integral a, Storable a) => Ptr a -> IO n
peekInt p = fromIntegral <$> peek p
peekBool :: Ptr CInt -> IO Bool
peekBool p = isOk <$> peek p
peekEnum :: (Enum e,Storable i, Integral i) => Ptr i -> IO e
peekEnum p = te <$> peek p
peekCStrLen :: (Ptr (Ptr CChar), Ptr CUInt) -> IO Text
peekCStrLen (p,plen) = join $ ts <$> peek p <*> peek plen
_get :: NativeTypeNum -> PtrData -> IO DataValue
_get t p = do
Data get <- peek p
get t