{-# LINE 1 "Data/GI/Base/Utils.hsc" #-}
{-# LANGUAGE ScopedTypeVariables, TupleSections, OverloadedStrings,
FlexibleContexts, ConstraintKinds #-}
module Data.GI.Base.Utils
( whenJust
, maybeM
, maybeFromPtr
, mapFirst
, mapFirstA
, mapSecond
, mapSecondA
, convertIfNonNull
, convertFunPtrIfNonNull
, callocBytes
, callocBoxedBytes
, callocMem
, allocBytes
, allocMem
, freeMem
, ptr_to_g_free
, memcpy
, safeFreeFunPtr
, safeFreeFunPtrPtr
, maybeReleaseFunPtr
, checkUnexpectedReturnNULL
, checkUnexpectedNothing
, dbgLog
) where
import Control.Exception (throwIO)
import Control.Monad (void)
import qualified Data.Text as T
import qualified Data.Text.Foreign as TF
{-# LINE 40 "Data/GI/Base/Utils.hsc" #-}
import Data.Word
{-# LINE 45 "Data/GI/Base/Utils.hsc" #-}
import Foreign.C.Types (CSize(..), CChar)
import Foreign.Ptr (Ptr, nullPtr, FunPtr, nullFunPtr, freeHaskellFunPtr)
import Foreign.Storable (Storable(..))
import Data.GI.Base.BasicTypes (GType(..), CGType, BoxedObject(..),
UnexpectedNullPointerReturn(..))
import Data.GI.Base.CallStack (HasCallStack, callStack, prettyCallStack)
whenJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust :: Maybe a -> (a -> m ()) -> m ()
whenJust (Just v :: a
v) f :: a -> m ()
f = a -> m ()
f a
v
whenJust Nothing _ = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
maybeM :: Monad m => b -> Maybe a -> (a -> m b) -> m b
maybeM :: b -> Maybe a -> (a -> m b) -> m b
maybeM d :: b
d Nothing _ = b -> m b
forall (m :: * -> *) a. Monad m => a -> m a
return b
d
maybeM _ (Just v :: a
v) action :: a -> m b
action = a -> m b
action a
v
maybeFromPtr :: Ptr a -> Maybe (Ptr a)
maybeFromPtr :: Ptr a -> Maybe (Ptr a)
maybeFromPtr ptr :: Ptr a
ptr = if Ptr a
ptr Ptr a -> Ptr a -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr a
forall a. Ptr a
nullPtr
then Maybe (Ptr a)
forall a. Maybe a
Nothing
else Ptr a -> Maybe (Ptr a)
forall a. a -> Maybe a
Just Ptr a
ptr
mapFirst :: (a -> c) -> [(a,b)] -> [(c,b)]
mapFirst :: (a -> c) -> [(a, b)] -> [(c, b)]
mapFirst _ [] = []
mapFirst f :: a -> c
f ((x :: a
x,y :: b
y) : rest :: [(a, b)]
rest) = (a -> c
f a
x, b
y) (c, b) -> [(c, b)] -> [(c, b)]
forall a. a -> [a] -> [a]
: (a -> c) -> [(a, b)] -> [(c, b)]
forall a c b. (a -> c) -> [(a, b)] -> [(c, b)]
mapFirst a -> c
f [(a, b)]
rest
mapSecond :: (b -> c) -> [(a,b)] -> [(a,c)]
mapSecond :: (b -> c) -> [(a, b)] -> [(a, c)]
mapSecond _ [] = []
mapSecond f :: b -> c
f ((x :: a
x,y :: b
y) : rest :: [(a, b)]
rest) = (a
x, b -> c
f b
y) (a, c) -> [(a, c)] -> [(a, c)]
forall a. a -> [a] -> [a]
: (b -> c) -> [(a, b)] -> [(a, c)]
forall b c a. (b -> c) -> [(a, b)] -> [(a, c)]
mapSecond b -> c
f [(a, b)]
rest
mapFirstA :: Applicative f => (a -> f c) -> [(a,b)] -> f [(c,b)]
mapFirstA :: (a -> f c) -> [(a, b)] -> f [(c, b)]
mapFirstA _ [] = [(c, b)] -> f [(c, b)]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
mapFirstA f :: a -> f c
f ((x :: a
x,y :: b
y) : rest :: [(a, b)]
rest) = (:) ((c, b) -> [(c, b)] -> [(c, b)])
-> f (c, b) -> f ([(c, b)] -> [(c, b)])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((,b
y) (c -> (c, b)) -> f c -> f (c, b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> f c
f a
x) f ([(c, b)] -> [(c, b)]) -> f [(c, b)] -> f [(c, b)]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (a -> f c) -> [(a, b)] -> f [(c, b)]
forall (f :: * -> *) a c b.
Applicative f =>
(a -> f c) -> [(a, b)] -> f [(c, b)]
mapFirstA a -> f c
f [(a, b)]
rest
mapSecondA :: Applicative f => (b -> f c) -> [(a,b)] -> f [(a,c)]
mapSecondA :: (b -> f c) -> [(a, b)] -> f [(a, c)]
mapSecondA _ [] = [(a, c)] -> f [(a, c)]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
mapSecondA f :: b -> f c
f ((x :: a
x,y :: b
y) : rest :: [(a, b)]
rest) = (:) ((a, c) -> [(a, c)] -> [(a, c)])
-> f (a, c) -> f ([(a, c)] -> [(a, c)])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((a
x,) (c -> (a, c)) -> f c -> f (a, c)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> b -> f c
f b
y) f ([(a, c)] -> [(a, c)]) -> f [(a, c)] -> f [(a, c)]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (b -> f c) -> [(a, b)] -> f [(a, c)]
forall (f :: * -> *) b c a.
Applicative f =>
(b -> f c) -> [(a, b)] -> f [(a, c)]
mapSecondA b -> f c
f [(a, b)]
rest
convertIfNonNull :: Ptr a -> (Ptr a -> IO b) -> IO (Maybe b)
convertIfNonNull :: Ptr a -> (Ptr a -> IO b) -> IO (Maybe b)
convertIfNonNull ptr :: Ptr a
ptr convert :: Ptr a -> IO b
convert = if Ptr a
ptr Ptr a -> Ptr a -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr a
forall a. Ptr a
nullPtr
then Maybe b -> IO (Maybe b)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe b
forall a. Maybe a
Nothing
else b -> Maybe b
forall a. a -> Maybe a
Just (b -> Maybe b) -> IO b -> IO (Maybe b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr a -> IO b
convert Ptr a
ptr
convertFunPtrIfNonNull :: FunPtr a -> (FunPtr a -> IO b) -> IO (Maybe b)
convertFunPtrIfNonNull :: FunPtr a -> (FunPtr a -> IO b) -> IO (Maybe b)
convertFunPtrIfNonNull ptr :: FunPtr a
ptr convert :: FunPtr a -> IO b
convert = if FunPtr a
ptr FunPtr a -> FunPtr a -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr a
forall a. FunPtr a
nullFunPtr
then Maybe b -> IO (Maybe b)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe b
forall a. Maybe a
Nothing
else b -> Maybe b
forall a. a -> Maybe a
Just (b -> Maybe b) -> IO b -> IO (Maybe b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FunPtr a -> IO b
convert FunPtr a
ptr
foreign import ccall "g_malloc0" g_malloc0 ::
Word64 -> IO (Ptr a)
{-# LINE 109 "Data/GI/Base/Utils.hsc" #-}
{-# INLINE callocBytes #-}
callocBytes :: Int -> IO (Ptr a)
callocBytes :: Int -> IO (Ptr a)
callocBytes n :: Int
n = Word64 -> IO (Ptr a)
forall a. Word64 -> IO (Ptr a)
g_malloc0 (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n)
{-# INLINE callocMem #-}
callocMem :: forall a. Storable a => IO (Ptr a)
callocMem :: IO (Ptr a)
callocMem = Word64 -> IO (Ptr a)
forall a. Word64 -> IO (Ptr a)
g_malloc0 (Word64 -> IO (Ptr a)) -> Word64 -> IO (Ptr a)
forall a b. (a -> b) -> a -> b
$ (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word64) -> (a -> Int) -> a -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Int
forall a. Storable a => a -> Int
sizeOf) (a
forall a. HasCallStack => a
undefined :: a)
foreign import ccall "g_boxed_copy" g_boxed_copy ::
CGType -> Ptr a -> IO (Ptr a)
callocBoxedBytes :: forall a. BoxedObject a => Int -> IO (Ptr a)
callocBoxedBytes :: Int -> IO (Ptr a)
callocBoxedBytes n :: Int
n = do
Ptr a
ptr <- Int -> IO (Ptr a)
forall a. Int -> IO (Ptr a)
callocBytes Int
n
GType cgtype :: Word64
cgtype <- a -> IO GType
forall a. BoxedObject a => a -> IO GType
boxedType (a
forall a. HasCallStack => a
undefined :: a)
Ptr a
result <- Word64 -> Ptr a -> IO (Ptr a)
forall a. Word64 -> Ptr a -> IO (Ptr a)
g_boxed_copy Word64
cgtype Ptr a
ptr
Ptr a -> IO ()
forall a. Ptr a -> IO ()
freeMem Ptr a
ptr
Ptr a -> IO (Ptr a)
forall (m :: * -> *) a. Monad m => a -> m a
return Ptr a
result
foreign import ccall "g_malloc" g_malloc ::
Word64 -> IO (Ptr a)
{-# LINE 140 "Data/GI/Base/Utils.hsc" #-}
{-# INLINE allocBytes #-}
allocBytes :: Integral a => a -> IO (Ptr b)
allocBytes :: a -> IO (Ptr b)
allocBytes n :: a
n = Word64 -> IO (Ptr b)
forall a. Word64 -> IO (Ptr a)
g_malloc (a -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n)
{-# INLINE allocMem #-}
allocMem :: forall a. Storable a => IO (Ptr a)
allocMem :: IO (Ptr a)
allocMem = Word64 -> IO (Ptr a)
forall a. Word64 -> IO (Ptr a)
g_malloc (Word64 -> IO (Ptr a)) -> Word64 -> IO (Ptr a)
forall a b. (a -> b) -> a -> b
$ (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word64) -> (a -> Int) -> a -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Int
forall a. Storable a => a -> Int
sizeOf) (a
forall a. HasCallStack => a
undefined :: a)
foreign import ccall "g_free" freeMem :: Ptr a -> IO ()
foreign import ccall "&g_free" ptr_to_g_free :: FunPtr (Ptr a -> IO ())
foreign import ccall unsafe "string.h memcpy" _memcpy :: Ptr a -> Ptr b -> CSize -> IO (Ptr ())
{-# INLINE memcpy #-}
memcpy :: Ptr a -> Ptr b -> Int -> IO ()
memcpy :: Ptr a -> Ptr b -> Int -> IO ()
memcpy dest :: Ptr a
dest src :: Ptr b
src n :: Int
n = IO (Ptr ()) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Ptr ()) -> IO ()) -> IO (Ptr ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ Ptr a -> Ptr b -> CSize -> IO (Ptr ())
forall a b. Ptr a -> Ptr b -> CSize -> IO (Ptr ())
_memcpy Ptr a
dest Ptr b
src (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n)
foreign import ccall "safeFreeFunPtr" safeFreeFunPtr ::
Ptr a -> IO ()
foreign import ccall "& safeFreeFunPtr" safeFreeFunPtrPtr ::
FunPtr (Ptr a -> IO ())
maybeReleaseFunPtr :: Maybe (Ptr (FunPtr a)) -> IO ()
maybeReleaseFunPtr :: Maybe (Ptr (FunPtr a)) -> IO ()
maybeReleaseFunPtr Nothing = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
maybeReleaseFunPtr (Just f :: Ptr (FunPtr a)
f) = do
Ptr (FunPtr a) -> IO (FunPtr a)
forall a. Storable a => Ptr a -> IO a
peek Ptr (FunPtr a)
f IO (FunPtr a) -> (FunPtr a -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FunPtr a -> IO ()
forall a. FunPtr a -> IO ()
freeHaskellFunPtr
Ptr (FunPtr a) -> IO ()
forall a. Ptr a -> IO ()
freeMem Ptr (FunPtr a)
f
checkUnexpectedReturnNULL :: HasCallStack => T.Text -> Ptr a -> IO ()
checkUnexpectedReturnNULL :: Text -> Ptr a -> IO ()
checkUnexpectedReturnNULL fnName :: Text
fnName ptr :: Ptr a
ptr
| Ptr a
ptr Ptr a -> Ptr a -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr a
forall a. Ptr a
nullPtr =
UnexpectedNullPointerReturn -> IO ()
forall e a. Exception e => e -> IO a
throwIO (UnexpectedNullPointerReturn :: Text -> UnexpectedNullPointerReturn
UnexpectedNullPointerReturn {
nullPtrErrorMsg :: Text
nullPtrErrorMsg = "Received unexpected nullPtr in \""
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
fnName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "\".\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"This might be a bug in the introspection data, or perhaps a use-after-free bug.\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"If in doubt, please report it at\n\thttps://github.com/haskell-gi/haskell-gi/issues\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
String -> Text
T.pack (CallStack -> String
prettyCallStack CallStack
HasCallStack => CallStack
callStack)
})
| Bool
otherwise = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
checkUnexpectedNothing :: HasCallStack => T.Text -> IO (Maybe a) -> IO a
checkUnexpectedNothing :: Text -> IO (Maybe a) -> IO a
checkUnexpectedNothing fnName :: Text
fnName action :: IO (Maybe a)
action = do
Maybe a
result <- IO (Maybe a)
action
case Maybe a
result of
Just r :: a
r -> a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
r
Nothing -> UnexpectedNullPointerReturn -> IO a
forall e a. Exception e => e -> IO a
throwIO (UnexpectedNullPointerReturn :: Text -> UnexpectedNullPointerReturn
UnexpectedNullPointerReturn {
nullPtrErrorMsg :: Text
nullPtrErrorMsg = "Received unexpected Nothing in \""
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
fnName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "\".\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"This might be a bug in the introspection data, or perhaps a use-after-free bug.\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
"If in doubt, please report it at\n\thttps://github.com/haskell-gi/haskell-gi/issues\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
String -> Text
T.pack (CallStack -> String
prettyCallStack CallStack
HasCallStack => CallStack
callStack)
})
foreign import ccall unsafe "dbg_log_with_len" dbg_log_with_len ::
Ptr CChar -> Int -> IO ()
dbgLog :: T.Text -> IO ()
dbgLog :: Text -> IO ()
dbgLog msg :: Text
msg = Text -> (CStringLen -> IO ()) -> IO ()
forall a. Text -> (CStringLen -> IO a) -> IO a
TF.withCStringLen Text
msg ((CStringLen -> IO ()) -> IO ()) -> (CStringLen -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(ptr :: Ptr CChar
ptr, len :: Int
len) -> Ptr CChar -> Int -> IO ()
dbg_log_with_len Ptr CChar
ptr Int
len