    {- |
    Copyright  : Will Thompson, Iñaki García Etxebarria and Jonas Platte
    License    : LGPL-2.1
    Maintainer : Iñaki García Etxebarria (garetxe@gmail.com)

    The GRecMutex struct is an opaque data structure to represent a
    recursive mutex. It is similar to a 'GI.GLib.Unions.Mutex.Mutex' with the difference
    that it is possible to lock a GRecMutex multiple times in the same
    thread without deadlock. When doing so, care has to be taken to
    unlock the recursive mutex as often as it has been locked.

    If a 'GI.GLib.Structs.RecMutex.RecMutex' is allocated in static storage then it can be used
    without initialisation.  Otherwise, you should call
    'GI.GLib.Structs.RecMutex.recMutexInit' on it and 'GI.GLib.Structs.RecMutex.recMutexClear' when done.

    A GRecMutex should only be accessed with the
    g_rec_mutex_ functions.

    /Since: 2.32/
    -}

    #define ENABLE_OVERLOADING \
           (!defined(__HADDOCK_VERSION__))

    module GI.GLib.Structs.RecMutex
        (

    -- * Exported types
        RecMutex(..)                            ,
        newZeroRecMutex                         ,
        noRecMutex                              ,

     -- * Methods
    -- ** clear #method:clear#

    #if ENABLE_OVERLOADING
        RecMutexClearMethodInfo                 ,
    #endif
        recMutexClear                           ,

    -- ** init #method:init#

    #if ENABLE_OVERLOADING
        RecMutexInitMethodInfo                  ,
    #endif
        recMutexInit                            ,

    -- ** lock #method:lock#

    #if ENABLE_OVERLOADING
        RecMutexLockMethodInfo                  ,
    #endif
        recMutexLock                            ,

    -- ** trylock #method:trylock#

    #if ENABLE_OVERLOADING
        RecMutexTrylockMethodInfo               ,
    #endif
        recMutexTrylock                         ,

    -- ** unlock #method:unlock#

    #if ENABLE_OVERLOADING
        RecMutexUnlockMethodInfo                ,
    #endif
        recMutexUnlock                          ,

        ) where

    import Data.GI.Base.ShortPrelude
    import qualified Data.GI.Base.ShortPrelude as SP
    import qualified Data.GI.Base.Overloading as O
    import qualified Prelude as P

    import qualified Data.GI.Base.Attributes as GI.Attributes
    import qualified Data.GI.Base.ManagedPtr as B.ManagedPtr
    import qualified Data.GI.Base.GError as B.GError
    import qualified Data.GI.Base.GVariant as B.GVariant
    import qualified Data.GI.Base.GValue as B.GValue
    import qualified Data.GI.Base.GParamSpec as B.GParamSpec
    import qualified Data.GI.Base.CallStack as B.CallStack
    import qualified Data.Text as T
    import qualified Data.ByteString.Char8 as B
    import qualified Data.Map as Map
    import qualified Foreign.Ptr as FP

    -- | Memory-managed wrapper type.
    newtype RecMutex = RecMutex (ManagedPtr RecMutex)
    instance WrappedPtr RecMutex where
        wrappedPtrCalloc = callocBytes 16
        wrappedPtrCopy = \p -> withManagedPtr p (copyBytes 16 >=> wrapPtr RecMutex)
        wrappedPtrFree = Just ptr_to_g_free

    -- | Construct a `RecMutex` struct initialized to zero.
    newZeroRecMutex :: MonadIO m => m RecMutex
    newZeroRecMutex = liftIO $ wrappedPtrCalloc >>= wrapPtr RecMutex

    instance tag ~ 'AttrSet => Constructible RecMutex tag where
        new _ attrs = do
            o <- newZeroRecMutex
            GI.Attributes.set o attrs
            return o

    -- | A convenience alias for `Nothing` :: `Maybe` `RecMutex`.
    noRecMutex :: Maybe RecMutex
    noRecMutex = Nothing

    #if ENABLE_OVERLOADING
    instance O.HasAttributeList RecMutex
    type instance O.AttributeList RecMutex = RecMutexAttributeList
    type RecMutexAttributeList = ('[ ] :: [(Symbol, *)])
    #endif

    -- method RecMutex::clear
    -- method type : OrdinaryMethod
    -- Args : [Arg {argCName = "rec_mutex", argType = TInterface (Name {namespace = "GLib", name = "RecMutex"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "an initialized #GRecMutex", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
    -- Lengths : []
    -- returnType : Nothing
    -- throws : False
    -- Skip return : False

    foreign import ccall "g_rec_mutex_clear" g_rec_mutex_clear ::
        Ptr RecMutex ->                         -- rec_mutex : TInterface (Name {namespace = "GLib", name = "RecMutex"})
        IO ()

    {- |
    Frees the resources allocated to a recursive mutex with
    'GI.GLib.Structs.RecMutex.recMutexInit'.

    This function should not be used with a 'GI.GLib.Structs.RecMutex.RecMutex' that has been
    statically allocated.

    Calling 'GI.GLib.Structs.RecMutex.recMutexClear' on a locked recursive mutex leads
    to undefined behaviour.

    Sine: 2.32
    -}
    recMutexClear ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        RecMutex
        {- ^ /@recMutex@/: an initialized 'GI.GLib.Structs.RecMutex.RecMutex' -}
        -> m ()
    recMutexClear recMutex = liftIO $ do
        recMutex' <- unsafeManagedPtrGetPtr recMutex
        g_rec_mutex_clear recMutex'
        touchManagedPtr recMutex
        return ()

    #if ENABLE_OVERLOADING
    data RecMutexClearMethodInfo
    instance (signature ~ (m ()), MonadIO m) => O.MethodInfo RecMutexClearMethodInfo RecMutex signature where
        overloadedMethod _ = recMutexClear

    #endif

    -- method RecMutex::init
    -- method type : OrdinaryMethod
    -- Args : [Arg {argCName = "rec_mutex", argType = TInterface (Name {namespace = "GLib", name = "RecMutex"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "an uninitialized #GRecMutex", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
    -- Lengths : []
    -- returnType : Nothing
    -- throws : False
    -- Skip return : False

    foreign import ccall "g_rec_mutex_init" g_rec_mutex_init ::
        Ptr RecMutex ->                         -- rec_mutex : TInterface (Name {namespace = "GLib", name = "RecMutex"})
        IO ()

    {- |
    Initializes a 'GI.GLib.Structs.RecMutex.RecMutex' so that it can be used.

    This function is useful to initialize a recursive mutex
    that has been allocated on the stack, or as part of a larger
    structure.

    It is not necessary to initialise a recursive mutex that has been
    statically allocated.

    === /C code/
    >
    >  typedef struct {
    >    GRecMutex m;
    >    ...
    >  } Blob;
    >
    >Blob *b;
    >
    >b = g_new (Blob, 1);
    >g_rec_mutex_init (&b->m);

    Calling 'GI.GLib.Structs.RecMutex.recMutexInit' on an already initialized 'GI.GLib.Structs.RecMutex.RecMutex'
    leads to undefined behaviour.

    To undo the effect of 'GI.GLib.Structs.RecMutex.recMutexInit' when a recursive mutex
    is no longer needed, use 'GI.GLib.Structs.RecMutex.recMutexClear'.

    /Since: 2.32/
    -}
    recMutexInit ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        RecMutex
        {- ^ /@recMutex@/: an uninitialized 'GI.GLib.Structs.RecMutex.RecMutex' -}
        -> m ()
    recMutexInit recMutex = liftIO $ do
        recMutex' <- unsafeManagedPtrGetPtr recMutex
        g_rec_mutex_init recMutex'
        touchManagedPtr recMutex
        return ()

    #if ENABLE_OVERLOADING
    data RecMutexInitMethodInfo
    instance (signature ~ (m ()), MonadIO m) => O.MethodInfo RecMutexInitMethodInfo RecMutex signature where
        overloadedMethod _ = recMutexInit

    #endif

    -- method RecMutex::lock
    -- method type : OrdinaryMethod
    -- Args : [Arg {argCName = "rec_mutex", argType = TInterface (Name {namespace = "GLib", name = "RecMutex"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GRecMutex", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
    -- Lengths : []
    -- returnType : Nothing
    -- throws : False
    -- Skip return : False

    foreign import ccall "g_rec_mutex_lock" g_rec_mutex_lock ::
        Ptr RecMutex ->                         -- rec_mutex : TInterface (Name {namespace = "GLib", name = "RecMutex"})
        IO ()

    {- |
    Locks /@recMutex@/. If /@recMutex@/ is already locked by another
    thread, the current thread will block until /@recMutex@/ is
    unlocked by the other thread. If /@recMutex@/ is already locked
    by the current thread, the \'lock count\' of /@recMutex@/ is increased.
    The mutex will only become available again when it is unlocked
    as many times as it has been locked.

    /Since: 2.32/
    -}
    recMutexLock ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        RecMutex
        {- ^ /@recMutex@/: a 'GI.GLib.Structs.RecMutex.RecMutex' -}
        -> m ()
    recMutexLock recMutex = liftIO $ do
        recMutex' <- unsafeManagedPtrGetPtr recMutex
        g_rec_mutex_lock recMutex'
        touchManagedPtr recMutex
        return ()

    #if ENABLE_OVERLOADING
    data RecMutexLockMethodInfo
    instance (signature ~ (m ()), MonadIO m) => O.MethodInfo RecMutexLockMethodInfo RecMutex signature where
        overloadedMethod _ = recMutexLock

    #endif

    -- method RecMutex::trylock
    -- method type : OrdinaryMethod
    -- Args : [Arg {argCName = "rec_mutex", argType = TInterface (Name {namespace = "GLib", name = "RecMutex"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GRecMutex", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
    -- Lengths : []
    -- returnType : Just (TBasicType TBoolean)
    -- throws : False
    -- Skip return : False

    foreign import ccall "g_rec_mutex_trylock" g_rec_mutex_trylock ::
        Ptr RecMutex ->                         -- rec_mutex : TInterface (Name {namespace = "GLib", name = "RecMutex"})
        IO CInt

    {- |
    Tries to lock /@recMutex@/. If /@recMutex@/ is already locked
    by another thread, it immediately returns 'False'. Otherwise
    it locks /@recMutex@/ and returns 'True'.

    /Since: 2.32/
    -}
    recMutexTrylock ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        RecMutex
        {- ^ /@recMutex@/: a 'GI.GLib.Structs.RecMutex.RecMutex' -}
        -> m Bool
        {- ^ __Returns:__ 'True' if /@recMutex@/ could be locked -}
    recMutexTrylock recMutex = liftIO $ do
        recMutex' <- unsafeManagedPtrGetPtr recMutex
        result <- g_rec_mutex_trylock recMutex'
        let result' = (/= 0) result
        touchManagedPtr recMutex
        return result'

    #if ENABLE_OVERLOADING
    data RecMutexTrylockMethodInfo
    instance (signature ~ (m Bool), MonadIO m) => O.MethodInfo RecMutexTrylockMethodInfo RecMutex signature where
        overloadedMethod _ = recMutexTrylock

    #endif

    -- method RecMutex::unlock
    -- method type : OrdinaryMethod
    -- Args : [Arg {argCName = "rec_mutex", argType = TInterface (Name {namespace = "GLib", name = "RecMutex"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GRecMutex", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
    -- Lengths : []
    -- returnType : Nothing
    -- throws : False
    -- Skip return : False

    foreign import ccall "g_rec_mutex_unlock" g_rec_mutex_unlock ::
        Ptr RecMutex ->                         -- rec_mutex : TInterface (Name {namespace = "GLib", name = "RecMutex"})
        IO ()

    {- |
    Unlocks /@recMutex@/. If another thread is blocked in a
    'GI.GLib.Structs.RecMutex.recMutexLock' call for /@recMutex@/, it will become unblocked
    and can lock /@recMutex@/ itself.

    Calling 'GI.GLib.Structs.RecMutex.recMutexUnlock' on a recursive mutex that is not
    locked by the current thread leads to undefined behaviour.

    /Since: 2.32/
    -}
    recMutexUnlock ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        RecMutex
        {- ^ /@recMutex@/: a 'GI.GLib.Structs.RecMutex.RecMutex' -}
        -> m ()
    recMutexUnlock recMutex = liftIO $ do
        recMutex' <- unsafeManagedPtrGetPtr recMutex
        g_rec_mutex_unlock recMutex'
        touchManagedPtr recMutex
        return ()

    #if ENABLE_OVERLOADING
    data RecMutexUnlockMethodInfo
    instance (signature ~ (m ()), MonadIO m) => O.MethodInfo RecMutexUnlockMethodInfo RecMutex signature where
        overloadedMethod _ = recMutexUnlock

    #endif

    #if ENABLE_OVERLOADING
    type family ResolveRecMutexMethod (t :: Symbol) (o :: *) :: * where
        ResolveRecMutexMethod "clear" o = RecMutexClearMethodInfo
        ResolveRecMutexMethod "init" o = RecMutexInitMethodInfo
        ResolveRecMutexMethod "lock" o = RecMutexLockMethodInfo
        ResolveRecMutexMethod "trylock" o = RecMutexTrylockMethodInfo
        ResolveRecMutexMethod "unlock" o = RecMutexUnlockMethodInfo
        ResolveRecMutexMethod l o = O.MethodResolutionFailed l o

    instance (info ~ ResolveRecMutexMethod t RecMutex, O.MethodInfo info RecMutex p) => O.IsLabelProxy t (RecMutex -> p) where
        fromLabelProxy _ = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)

    #if MIN_VERSION_base(4,9,0)
    instance (info ~ ResolveRecMutexMethod t RecMutex, O.MethodInfo info RecMutex p) => O.IsLabel t (RecMutex -> p) where
    #if MIN_VERSION_base(4,10,0)
        fromLabel = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)
    #else
        fromLabel _ = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)
    #endif
    #endif

    #endif