{-# LINE 1 "Data/GI/Base/Utils.hsc" #-}
{-# LANGUAGE ScopedTypeVariables, TupleSections, OverloadedStrings,
FlexibleContexts, ConstraintKinds, TypeApplications #-}
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
, 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 41 "Data/GI/Base/Utils.hsc" #-}
import Data.Word
{-# LINE 46 "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, GBoxed,
TypedObject(glibType),
UnexpectedNullPointerReturn(..))
import Data.GI.Base.CallStack (HasCallStack, callStack, prettyCallStack)
whenJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust :: forall (m :: * -> *) a. Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust (Just a
v) a -> m ()
f = a -> m ()
f a
v
whenJust Maybe a
Nothing a -> m ()
_ = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
maybeM :: Monad m => b -> Maybe a -> (a -> m b) -> m b
maybeM :: forall (m :: * -> *) b a.
Monad m =>
b -> Maybe a -> (a -> m b) -> m b
maybeM b
d Maybe a
Nothing a -> m b
_ = b -> m b
forall (m :: * -> *) a. Monad m => a -> m a
return b
d
maybeM b
_ (Just a
v) a -> m b
action = a -> m b
action a
v
maybeFromPtr :: Ptr a -> Maybe (Ptr a)
maybeFromPtr :: forall a. Ptr a -> Maybe (Ptr a)
maybeFromPtr 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 :: forall a c b. (a -> c) -> [(a, b)] -> [(c, b)]
mapFirst a -> c
_ [] = []
mapFirst a -> c
f ((a
x,b
y) : [(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 :: forall b c a. (b -> c) -> [(a, b)] -> [(a, c)]
mapSecond b -> c
_ [] = []
mapSecond b -> c
f ((a
x,b
y) : [(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 :: forall (f :: * -> *) a c b.
Applicative f =>
(a -> f c) -> [(a, b)] -> f [(c, b)]
mapFirstA a -> f c
_ [] = [(c, b)] -> f [(c, b)]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
mapFirstA a -> f c
f ((a
x,b
y) : [(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 :: forall (f :: * -> *) b c a.
Applicative f =>
(b -> f c) -> [(a, b)] -> f [(a, c)]
mapSecondA b -> f c
_ [] = [(a, c)] -> f [(a, c)]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
mapSecondA b -> f c
f ((a
x,b
y) : [(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 :: forall a b. Ptr a -> (Ptr a -> IO b) -> IO (Maybe b)
convertIfNonNull Ptr a
ptr 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 :: forall a b. FunPtr a -> (FunPtr a -> IO b) -> IO (Maybe b)
convertFunPtrIfNonNull FunPtr a
ptr 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 111 "Data/GI/Base/Utils.hsc" #-}
{-# INLINE callocBytes #-}
callocBytes :: Int -> IO (Ptr a)
callocBytes :: forall a. Int -> IO (Ptr a)
callocBytes 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 :: forall a. Storable a => 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. GBoxed a => Int -> IO (Ptr a)
callocBoxedBytes :: forall a. GBoxed a => Int -> IO (Ptr a)
callocBoxedBytes Int
n = do
Ptr a
ptr <- Int -> IO (Ptr a)
forall a. Int -> IO (Ptr a)
callocBytes Int
n
GType Word64
cgtype <- forall a. TypedObject a => IO GType
glibType @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 142 "Data/GI/Base/Utils.hsc" #-}
{-# INLINE allocBytes #-}
allocBytes :: Integral a => a -> IO (Ptr b)
allocBytes :: forall a b. Integral a => a -> IO (Ptr b)
allocBytes 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 :: forall a. Storable a => 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 :: forall a b. Ptr a -> Ptr b -> Int -> IO ()
memcpy Ptr a
dest Ptr b
src 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 ())
foreign import ccall "& safeFreeFunPtr2" safeFreeFunPtrPtr' ::
FunPtr (Ptr a -> Ptr b -> IO ())
maybeReleaseFunPtr :: Maybe (Ptr (FunPtr a)) -> IO ()
maybeReleaseFunPtr :: forall a. Maybe (Ptr (FunPtr a)) -> IO ()
maybeReleaseFunPtr Maybe (Ptr (FunPtr a))
Nothing = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
maybeReleaseFunPtr (Just 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 :: forall a. HasCallStack => Text -> Ptr a -> IO ()
checkUnexpectedReturnNULL Text
fnName 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 {
nullPtrErrorMsg :: Text
nullPtrErrorMsg = Text
"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
<> Text
"\".\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
Text
"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
<>
Text
"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 :: forall a. HasCallStack => Text -> IO (Maybe a) -> IO a
checkUnexpectedNothing Text
fnName IO (Maybe a)
action = do
Maybe a
result <- IO (Maybe a)
action
case Maybe a
result of
Just a
r -> a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
r
Maybe a
Nothing -> UnexpectedNullPointerReturn -> IO a
forall e a. Exception e => e -> IO a
throwIO (UnexpectedNullPointerReturn {
nullPtrErrorMsg :: Text
nullPtrErrorMsg = Text
"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
<> Text
"\".\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
Text
"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
<>
Text
"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 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 CChar
ptr, Int
len) -> Ptr CChar -> Int -> IO ()
dbg_log_with_len Ptr CChar
ptr Int
len