    {- |
    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 'GI.GLib.Structs.Thread.Thread' struct represents a running thread. This struct
    is returned by @/g_thread_new()/@ or @/g_thread_try_new()/@. You can
    obtain the 'GI.GLib.Structs.Thread.Thread' struct representing the current thread by
    calling 'GI.GLib.Functions.threadSelf'.

    GThread is refcounted, see 'GI.GLib.Structs.Thread.threadRef' and 'GI.GLib.Structs.Thread.threadUnref'.
    The thread represented by it holds a reference while it is running,
    and 'GI.GLib.Structs.Thread.threadJoin' consumes the reference that it is given, so
    it is normally not necessary to manage GThread references
    explicitly.

    The structure is opaque -- none of its fields may be directly
    accessed.
    -}

    #define ENABLE_OVERLOADING \
           (!defined(__HADDOCK_VERSION__))

    module GI.GLib.Structs.Thread
        (

    -- * Exported types
        Thread(..)                              ,
        noThread                                ,

     -- * Methods
    -- ** errorQuark #method:errorQuark#

        threadErrorQuark                        ,

    -- ** exit #method:exit#

        threadExit                              ,

    -- ** join #method:join#

    #if ENABLE_OVERLOADING
        ThreadJoinMethodInfo                    ,
    #endif
        threadJoin                              ,

    -- ** ref #method:ref#

    #if ENABLE_OVERLOADING
        ThreadRefMethodInfo                     ,
    #endif
        threadRef                               ,

    -- ** self #method:self#

        threadSelf                              ,

    -- ** unref #method:unref#

    #if ENABLE_OVERLOADING
        ThreadUnrefMethodInfo                   ,
    #endif
        threadUnref                             ,

    -- ** yield #method:yield#

        threadYield                             ,

        ) 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 Thread = Thread (ManagedPtr Thread)
    foreign import ccall "g_thread_get_type" c_g_thread_get_type ::
        IO GType

    instance BoxedObject Thread where
        boxedType _ = c_g_thread_get_type

    -- | A convenience alias for `Nothing` :: `Maybe` `Thread`.
    noThread :: Maybe Thread
    noThread = Nothing

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

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

    foreign import ccall "g_thread_join" g_thread_join ::
        Ptr Thread ->                           -- thread : TInterface (Name {namespace = "GLib", name = "Thread"})
        IO (Ptr ())

    {- |
    Waits until /@thread@/ finishes, i.e. the function /@func@/, as
    given to @/g_thread_new()/@, returns or 'GI.GLib.Functions.threadExit' is called.
    If /@thread@/ has already terminated, then 'GI.GLib.Structs.Thread.threadJoin'
    returns immediately.

    Any thread can wait for any other thread by calling 'GI.GLib.Structs.Thread.threadJoin',
    not just its \'creator\'. Calling 'GI.GLib.Structs.Thread.threadJoin' from multiple threads
    for the same /@thread@/ leads to undefined behaviour.

    The value returned by /@func@/ or given to 'GI.GLib.Functions.threadExit' is
    returned by this function.

    'GI.GLib.Structs.Thread.threadJoin' consumes the reference to the passed-in /@thread@/.
    This will usually cause the 'GI.GLib.Structs.Thread.Thread' struct and associated resources
    to be freed. Use 'GI.GLib.Structs.Thread.threadRef' to obtain an extra reference if you
    want to keep the GThread alive beyond the 'GI.GLib.Structs.Thread.threadJoin' call.
    -}
    threadJoin ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        Thread
        {- ^ /@thread@/: a 'GI.GLib.Structs.Thread.Thread' -}
        -> m (Ptr ())
        {- ^ __Returns:__ the return value of the thread -}
    threadJoin thread = liftIO $ do
        thread' <- unsafeManagedPtrGetPtr thread
        result <- g_thread_join thread'
        touchManagedPtr thread
        return result

    #if ENABLE_OVERLOADING
    data ThreadJoinMethodInfo
    instance (signature ~ (m (Ptr ())), MonadIO m) => O.MethodInfo ThreadJoinMethodInfo Thread signature where
        overloadedMethod _ = threadJoin

    #endif

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

    foreign import ccall "g_thread_ref" g_thread_ref ::
        Ptr Thread ->                           -- thread : TInterface (Name {namespace = "GLib", name = "Thread"})
        IO (Ptr Thread)

    {- |
    Increase the reference count on /@thread@/.

    /Since: 2.32/
    -}
    threadRef ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        Thread
        {- ^ /@thread@/: a 'GI.GLib.Structs.Thread.Thread' -}
        -> m Thread
        {- ^ __Returns:__ a new reference to /@thread@/ -}
    threadRef thread = liftIO $ do
        thread' <- unsafeManagedPtrGetPtr thread
        result <- g_thread_ref thread'
        checkUnexpectedReturnNULL "threadRef" result
        result' <- (wrapBoxed Thread) result
        touchManagedPtr thread
        return result'

    #if ENABLE_OVERLOADING
    data ThreadRefMethodInfo
    instance (signature ~ (m Thread), MonadIO m) => O.MethodInfo ThreadRefMethodInfo Thread signature where
        overloadedMethod _ = threadRef

    #endif

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

    foreign import ccall "g_thread_unref" g_thread_unref ::
        Ptr Thread ->                           -- thread : TInterface (Name {namespace = "GLib", name = "Thread"})
        IO ()

    {- |
    Decrease the reference count on /@thread@/, possibly freeing all
    resources associated with it.

    Note that each thread holds a reference to its 'GI.GLib.Structs.Thread.Thread' while
    it is running, so it is safe to drop your own reference to it
    if you don\'t need it anymore.

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

    #if ENABLE_OVERLOADING
    data ThreadUnrefMethodInfo
    instance (signature ~ (m ()), MonadIO m) => O.MethodInfo ThreadUnrefMethodInfo Thread signature where
        overloadedMethod _ = threadUnref

    #endif

    -- method Thread::error_quark
    -- method type : MemberFunction
    -- Args : []
    -- Lengths : []
    -- returnType : Just (TBasicType TUInt32)
    -- throws : False
    -- Skip return : False

    foreign import ccall "g_thread_error_quark" g_thread_error_quark ::
        IO Word32

    {- |
    /No description available in the introspection data./
    -}
    threadErrorQuark ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        m Word32
    threadErrorQuark  = liftIO $ do
        result <- g_thread_error_quark
        return result

    #if ENABLE_OVERLOADING
    #endif

    -- method Thread::exit
    -- method type : MemberFunction
    -- Args : [Arg {argCName = "retval", argType = TBasicType TPtr, direction = DirectionIn, mayBeNull = True, argDoc = Documentation {rawDocText = Just "the return value of this thread", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
    -- Lengths : []
    -- returnType : Nothing
    -- throws : False
    -- Skip return : False

    foreign import ccall "g_thread_exit" g_thread_exit ::
        Ptr () ->                               -- retval : TBasicType TPtr
        IO ()

    {- |
    Terminates the current thread.

    If another thread is waiting for us using 'GI.GLib.Structs.Thread.threadJoin' then the
    waiting thread will be woken up and get /@retval@/ as the return value
    of 'GI.GLib.Structs.Thread.threadJoin'.

    Calling 'GI.GLib.Functions.threadExit' with a parameter /@retval@/ is equivalent to
    returning /@retval@/ from the function /@func@/, as given to @/g_thread_new()/@.

    You must only call 'GI.GLib.Functions.threadExit' from a thread that you created
    yourself with @/g_thread_new()/@ or related APIs. You must not call
    this function from a thread created with another threading library
    or or from within a 'GI.GLib.Structs.ThreadPool.ThreadPool'.
    -}
    threadExit ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        Ptr ()
        {- ^ /@retval@/: the return value of this thread -}
        -> m ()
    threadExit retval = liftIO $ do
        g_thread_exit retval
        return ()

    #if ENABLE_OVERLOADING
    #endif

    -- method Thread::self
    -- method type : MemberFunction
    -- Args : []
    -- Lengths : []
    -- returnType : Just (TInterface (Name {namespace = "GLib", name = "Thread"}))
    -- throws : False
    -- Skip return : False

    foreign import ccall "g_thread_self" g_thread_self ::
        IO (Ptr Thread)

    {- |
    This function returns the 'GI.GLib.Structs.Thread.Thread' corresponding to the
    current thread. Note that this function does not increase
    the reference count of the returned struct.

    This function will return a 'GI.GLib.Structs.Thread.Thread' even for threads that
    were not created by GLib (i.e. those created by other threading
    APIs). This may be useful for thread identification purposes
    (i.e. comparisons) but you must not use GLib functions (such
    as 'GI.GLib.Structs.Thread.threadJoin') on these threads.
    -}
    threadSelf ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        m Thread
        {- ^ __Returns:__ the 'GI.GLib.Structs.Thread.Thread' representing the current thread -}
    threadSelf  = liftIO $ do
        result <- g_thread_self
        checkUnexpectedReturnNULL "threadSelf" result
        result' <- (newBoxed Thread) result
        return result'

    #if ENABLE_OVERLOADING
    #endif

    -- method Thread::yield
    -- method type : MemberFunction
    -- Args : []
    -- Lengths : []
    -- returnType : Nothing
    -- throws : False
    -- Skip return : False

    foreign import ccall "g_thread_yield" g_thread_yield ::
        IO ()

    {- |
    Causes the calling thread to voluntarily relinquish the CPU, so
    that other threads can run.

    This function is often used as a method to make busy wait less evil.
    -}
    threadYield ::
        (B.CallStack.HasCallStack, MonadIO m) =>
        m ()
    threadYield  = liftIO $ do
        g_thread_yield
        return ()

    #if ENABLE_OVERLOADING
    #endif

    #if ENABLE_OVERLOADING
    type family ResolveThreadMethod (t :: Symbol) (o :: *) :: * where
        ResolveThreadMethod "join" o = ThreadJoinMethodInfo
        ResolveThreadMethod "ref" o = ThreadRefMethodInfo
        ResolveThreadMethod "unref" o = ThreadUnrefMethodInfo
        ResolveThreadMethod l o = O.MethodResolutionFailed l o

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

    #if MIN_VERSION_base(4,9,0)
    instance (info ~ ResolveThreadMethod t Thread, O.MethodInfo info Thread p) => O.IsLabel t (Thread -> 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