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

The 'GI.Gst.Structs.Promise.Promise' object implements the container for values that may
be available later. i.e. a Future or a Promise in
\<ulink url=\"https:\/\/en.wikipedia.org\/wiki\/Futures_and_promises\">https:\/\/en.wikipedia.org\/wiki\/Futures_and_promises\<\/ulink>
As with all Future\/Promise-like functionality, there is the concept of the
producer of the value and the consumer of the value.

A 'GI.Gst.Structs.Promise.Promise' is created with 'GI.Gst.Structs.Promise.promiseNew' by the consumer and passed
to the producer to avoid thread safety issues with the change callback.
A 'GI.Gst.Structs.Promise.Promise' can be replied to with a value (or an error) by the producer
with 'GI.Gst.Structs.Promise.promiseReply'. 'GI.Gst.Structs.Promise.promiseInterrupt' is for the consumer to
indicate to the producer that the value is not needed anymore and producing
that value can stop.  The /@gSTPROMISERESULTEXPIRED@/ state set by a call
to 'GI.Gst.Structs.Promise.promiseExpire' indicates to the consumer that a value will never
be produced and is intended to be called by a third party that implements
some notion of message handling such as 'GI.Gst.Objects.Bus.Bus'.
A callback can also be installed at 'GI.Gst.Structs.Promise.Promise' creation for
result changes with 'GI.Gst.Structs.Promise.promiseNewWithChangeFunc'.
The change callback can be used to chain @/GstPromises/@\'s together as in the
following example.

=== /C code/
>
>const GstStructure *reply;
>GstPromise *p;
>if (gst_promise_wait (promise) != GST_PROMISE_RESULT_REPLIED)
>  return; // interrupted or expired value
>reply = gst_promise_get_reply (promise);
>if (error in reply)
>  return; // propagate error
>p = gst_promise_new_with_change_func (another_promise_change_func, user_data, notify);
>pass p to promise-using API


Each 'GI.Gst.Structs.Promise.Promise' starts out with a 'GI.Gst.Enums.PromiseResult' of
'GI.Gst.Enums.PromiseResultPending' and only ever transitions once
into one of the other 'GI.Gst.Enums.PromiseResult'\'s.

In order to support multi-threaded code, 'GI.Gst.Structs.Promise.promiseReply',
'GI.Gst.Structs.Promise.promiseInterrupt' and 'GI.Gst.Structs.Promise.promiseExpire' may all be from
different threads with some restrictions and the final result of the promise
is whichever call is made first.  There are two restrictions on ordering:

1. That 'GI.Gst.Structs.Promise.promiseReply' and 'GI.Gst.Structs.Promise.promiseInterrupt' cannot be called
after 'GI.Gst.Structs.Promise.promiseExpire'
2. That 'GI.Gst.Structs.Promise.promiseReply' and 'GI.Gst.Structs.Promise.promiseInterrupt'
cannot be called twice.

The change function set with 'GI.Gst.Structs.Promise.promiseNewWithChangeFunc' is
called directly from either the 'GI.Gst.Structs.Promise.promiseReply',
'GI.Gst.Structs.Promise.promiseInterrupt' or 'GI.Gst.Structs.Promise.promiseExpire' and can be called
from an arbitrary thread.  'GI.Gst.Structs.Promise.Promise' using APIs can restrict this to
a single thread or a subset of threads but that is entirely up to the API
that uses 'GI.Gst.Structs.Promise.Promise'.

/Since: 1.14/
-}

#define ENABLE_OVERLOADING (MIN_VERSION_haskell_gi_overloading(1,0,0) \
       && !defined(__HADDOCK_VERSION__))

module GI.Gst.Structs.Promise
    (

-- * Exported types
    Promise(..)                             ,
    newZeroPromise                          ,
    noPromise                               ,


 -- * Methods
-- ** expire #method:expire#

#if ENABLE_OVERLOADING
    PromiseExpireMethodInfo                 ,
#endif
    promiseExpire                           ,


-- ** getReply #method:getReply#

#if ENABLE_OVERLOADING
    PromiseGetReplyMethodInfo               ,
#endif
    promiseGetReply                         ,


-- ** interrupt #method:interrupt#

#if ENABLE_OVERLOADING
    PromiseInterruptMethodInfo              ,
#endif
    promiseInterrupt                        ,


-- ** new #method:new#

    promiseNew                              ,


-- ** newWithChangeFunc #method:newWithChangeFunc#

    promiseNewWithChangeFunc                ,


-- ** reply #method:reply#

#if ENABLE_OVERLOADING
    PromiseReplyMethodInfo                  ,
#endif
    promiseReply                            ,


-- ** wait #method:wait#

#if ENABLE_OVERLOADING
    PromiseWaitMethodInfo                   ,
#endif
    promiseWait                             ,




 -- * Properties
-- ** parent #attr:parent#
{- | parent 'GI.Gst.Structs.MiniObject.MiniObject'
-}
    getPromiseParent                        ,
#if ENABLE_OVERLOADING
    promise_parent                          ,
#endif




    ) 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.GClosure as B.GClosure
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.GI.Base.Properties as B.Properties
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
import qualified GHC.OverloadedLabels as OL

import qualified GI.GLib.Callbacks as GLib.Callbacks
import qualified GI.Gst.Callbacks as Gst.Callbacks
import {-# SOURCE #-} qualified GI.Gst.Enums as Gst.Enums
import {-# SOURCE #-} qualified GI.Gst.Structs.MiniObject as Gst.MiniObject
import {-# SOURCE #-} qualified GI.Gst.Structs.Structure as Gst.Structure

-- | Memory-managed wrapper type.
newtype Promise = Promise (ManagedPtr Promise)
foreign import ccall "gst_promise_get_type" c_gst_promise_get_type ::
    IO GType

instance BoxedObject Promise where
    boxedType _ = c_gst_promise_get_type

-- | Construct a `Promise` struct initialized to zero.
newZeroPromise :: MonadIO m => m Promise
newZeroPromise = liftIO $ callocBoxedBytes 64 >>= wrapBoxed Promise

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


-- | A convenience alias for `Nothing` :: `Maybe` `Promise`.
noPromise :: Maybe Promise
noPromise = Nothing

{- |
Get the value of the “@parent@” field.
When <https://github.com/haskell-gi/haskell-gi/wiki/Overloading overloading> is enabled, this is equivalent to

@
'Data.GI.Base.Attributes.get' promise #parent
@
-}
getPromiseParent :: MonadIO m => Promise -> m Gst.MiniObject.MiniObject
getPromiseParent s = liftIO $ withManagedPtr s $ \ptr -> do
    let val = ptr `plusPtr` 0 :: (Ptr Gst.MiniObject.MiniObject)
    val' <- (newPtr Gst.MiniObject.MiniObject) val
    return val'

#if ENABLE_OVERLOADING
data PromiseParentFieldInfo
instance AttrInfo PromiseParentFieldInfo where
    type AttrAllowedOps PromiseParentFieldInfo = '[ 'AttrGet]
    type AttrSetTypeConstraint PromiseParentFieldInfo = (~) (Ptr Gst.MiniObject.MiniObject)
    type AttrBaseTypeConstraint PromiseParentFieldInfo = (~) Promise
    type AttrGetType PromiseParentFieldInfo = Gst.MiniObject.MiniObject
    type AttrLabel PromiseParentFieldInfo = "parent"
    type AttrOrigin PromiseParentFieldInfo = Promise
    attrGet _ = getPromiseParent
    attrSet _ = undefined
    attrConstruct = undefined
    attrClear _ = undefined

promise_parent :: AttrLabelProxy "parent"
promise_parent = AttrLabelProxy

#endif



#if ENABLE_OVERLOADING
instance O.HasAttributeList Promise
type instance O.AttributeList Promise = PromiseAttributeList
type PromiseAttributeList = ('[ '("parent", PromiseParentFieldInfo)] :: [(Symbol, *)])
#endif

-- method Promise::new
-- method type : Constructor
-- Args : []
-- Lengths : []
-- returnType : Just (TInterface (Name {namespace = "Gst", name = "Promise"}))
-- throws : False
-- Skip return : False

foreign import ccall "gst_promise_new" gst_promise_new ::
    IO (Ptr Promise)

{- |
/No description available in the introspection data./

/Since: 1.14/
-}
promiseNew ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    m Promise
    {- ^ __Returns:__ a new 'GI.Gst.Structs.Promise.Promise' -}
promiseNew  = liftIO $ do
    result <- gst_promise_new
    checkUnexpectedReturnNULL "promiseNew" result
    result' <- (wrapBoxed Promise) result
    return result'

#if ENABLE_OVERLOADING
#endif

-- method Promise::new_with_change_func
-- method type : Constructor
-- Args : [Arg {argCName = "func", argType = TInterface (Name {namespace = "Gst", name = "PromiseChangeFunc"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GstPromiseChangeFunc to call", sinceVersion = Nothing}, argScope = ScopeTypeNotified, argClosure = 1, argDestroy = 2, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "user_data", argType = TBasicType TPtr, direction = DirectionIn, mayBeNull = True, argDoc = Documentation {rawDocText = Just "argument to call @func with", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "notify", argType = TInterface (Name {namespace = "GLib", name = "DestroyNotify"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "notification function that @user_data is no longer needed", sinceVersion = Nothing}, argScope = ScopeTypeAsync, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing}]
-- Lengths : []
-- returnType : Just (TInterface (Name {namespace = "Gst", name = "Promise"}))
-- throws : False
-- Skip return : False

foreign import ccall "gst_promise_new_with_change_func" gst_promise_new_with_change_func ::
    FunPtr Gst.Callbacks.C_PromiseChangeFunc -> -- func : TInterface (Name {namespace = "Gst", name = "PromiseChangeFunc"})
    Ptr () ->                               -- user_data : TBasicType TPtr
    FunPtr GLib.Callbacks.C_DestroyNotify -> -- notify : TInterface (Name {namespace = "GLib", name = "DestroyNotify"})
    IO (Ptr Promise)

{- |
/@func@/ will be called exactly once when transitioning out of
'GI.Gst.Enums.PromiseResultPending' into any of the other 'GI.Gst.Enums.PromiseResult'
states.

/Since: 1.14/
-}
promiseNewWithChangeFunc ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Gst.Callbacks.PromiseChangeFunc
    {- ^ /@func@/: a 'GI.Gst.Callbacks.PromiseChangeFunc' to call -}
    -> m Promise
    {- ^ __Returns:__ a new 'GI.Gst.Structs.Promise.Promise' -}
promiseNewWithChangeFunc func = liftIO $ do
    func' <- Gst.Callbacks.mk_PromiseChangeFunc (Gst.Callbacks.wrap_PromiseChangeFunc Nothing (Gst.Callbacks.drop_closures_PromiseChangeFunc func))
    let userData = castFunPtrToPtr func'
    let notify = safeFreeFunPtrPtr
    result <- gst_promise_new_with_change_func func' userData notify
    checkUnexpectedReturnNULL "promiseNewWithChangeFunc" result
    result' <- (wrapBoxed Promise) result
    return result'

#if ENABLE_OVERLOADING
#endif

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

foreign import ccall "gst_promise_expire" gst_promise_expire ::
    Ptr Promise ->                          -- promise : TInterface (Name {namespace = "Gst", name = "Promise"})
    IO ()

{- |
Expire a /@promise@/.  This will wake up any waiters with
'GI.Gst.Enums.PromiseResultExpired'.  Called by a message loop when the parent
message is handled and\/or destroyed (possibly unanswered).

/Since: 1.14/
-}
promiseExpire ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Promise
    {- ^ /@promise@/: a 'GI.Gst.Structs.Promise.Promise' -}
    -> m ()
promiseExpire promise = liftIO $ do
    promise' <- unsafeManagedPtrGetPtr promise
    gst_promise_expire promise'
    touchManagedPtr promise
    return ()

#if ENABLE_OVERLOADING
data PromiseExpireMethodInfo
instance (signature ~ (m ()), MonadIO m) => O.MethodInfo PromiseExpireMethodInfo Promise signature where
    overloadedMethod _ = promiseExpire

#endif

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

foreign import ccall "gst_promise_get_reply" gst_promise_get_reply ::
    Ptr Promise ->                          -- promise : TInterface (Name {namespace = "Gst", name = "Promise"})
    IO (Ptr Gst.Structure.Structure)

{- |
Retrieve the reply set on /@promise@/.  /@promise@/ must be in
'GI.Gst.Enums.PromiseResultReplied' and the returned structure is owned by /@promise@/

/Since: 1.14/
-}
promiseGetReply ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Promise
    {- ^ /@promise@/: a 'GI.Gst.Structs.Promise.Promise' -}
    -> m Gst.Structure.Structure
    {- ^ __Returns:__ The reply set on /@promise@/ -}
promiseGetReply promise = liftIO $ do
    promise' <- unsafeManagedPtrGetPtr promise
    result <- gst_promise_get_reply promise'
    checkUnexpectedReturnNULL "promiseGetReply" result
    result' <- (newBoxed Gst.Structure.Structure) result
    touchManagedPtr promise
    return result'

#if ENABLE_OVERLOADING
data PromiseGetReplyMethodInfo
instance (signature ~ (m Gst.Structure.Structure), MonadIO m) => O.MethodInfo PromiseGetReplyMethodInfo Promise signature where
    overloadedMethod _ = promiseGetReply

#endif

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

foreign import ccall "gst_promise_interrupt" gst_promise_interrupt ::
    Ptr Promise ->                          -- promise : TInterface (Name {namespace = "Gst", name = "Promise"})
    IO ()

{- |
Interrupt waiting for a /@promise@/.  This will wake up any waiters with
'GI.Gst.Enums.PromiseResultInterrupted'.  Called when the consumer does not want
the value produced anymore.

/Since: 1.14/
-}
promiseInterrupt ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Promise
    {- ^ /@promise@/: a 'GI.Gst.Structs.Promise.Promise' -}
    -> m ()
promiseInterrupt promise = liftIO $ do
    promise' <- unsafeManagedPtrGetPtr promise
    gst_promise_interrupt promise'
    touchManagedPtr promise
    return ()

#if ENABLE_OVERLOADING
data PromiseInterruptMethodInfo
instance (signature ~ (m ()), MonadIO m) => O.MethodInfo PromiseInterruptMethodInfo Promise signature where
    overloadedMethod _ = promiseInterrupt

#endif

-- method Promise::reply
-- method type : OrdinaryMethod
-- Args : [Arg {argCName = "promise", argType = TInterface (Name {namespace = "Gst", name = "Promise"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GstPromise", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferNothing},Arg {argCName = "s", argType = TInterface (Name {namespace = "Gst", name = "Structure"}), direction = DirectionIn, mayBeNull = False, argDoc = Documentation {rawDocText = Just "a #GstStructure with the the reply contents", sinceVersion = Nothing}, argScope = ScopeTypeInvalid, argClosure = -1, argDestroy = -1, argCallerAllocates = False, transfer = TransferEverything}]
-- Lengths : []
-- returnType : Nothing
-- throws : False
-- Skip return : False

foreign import ccall "gst_promise_reply" gst_promise_reply ::
    Ptr Promise ->                          -- promise : TInterface (Name {namespace = "Gst", name = "Promise"})
    Ptr Gst.Structure.Structure ->          -- s : TInterface (Name {namespace = "Gst", name = "Structure"})
    IO ()

{- |
Set a reply on /@promise@/.  This will wake up any waiters with
'GI.Gst.Enums.PromiseResultReplied'.  Called by the producer of the value to
indicate success (or failure).

If /@promise@/ has already been interrupted by the consumer, then this reply
is not visible to the consumer.

/Since: 1.14/
-}
promiseReply ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Promise
    {- ^ /@promise@/: a 'GI.Gst.Structs.Promise.Promise' -}
    -> Gst.Structure.Structure
    {- ^ /@s@/: a 'GI.Gst.Structs.Structure.Structure' with the the reply contents -}
    -> m ()
promiseReply promise s = liftIO $ do
    promise' <- unsafeManagedPtrGetPtr promise
    s' <- B.ManagedPtr.disownBoxed s
    gst_promise_reply promise' s'
    touchManagedPtr promise
    touchManagedPtr s
    return ()

#if ENABLE_OVERLOADING
data PromiseReplyMethodInfo
instance (signature ~ (Gst.Structure.Structure -> m ()), MonadIO m) => O.MethodInfo PromiseReplyMethodInfo Promise signature where
    overloadedMethod _ = promiseReply

#endif

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

foreign import ccall "gst_promise_wait" gst_promise_wait ::
    Ptr Promise ->                          -- promise : TInterface (Name {namespace = "Gst", name = "Promise"})
    IO CUInt

{- |
Wait for /@promise@/ to move out of the 'GI.Gst.Enums.PromiseResultPending' state.
If /@promise@/ is not in 'GI.Gst.Enums.PromiseResultPending' then it will return
immediately with the current result.

/Since: 1.14/
-}
promiseWait ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Promise
    {- ^ /@promise@/: a 'GI.Gst.Structs.Promise.Promise' -}
    -> m Gst.Enums.PromiseResult
    {- ^ __Returns:__ the result of the promise -}
promiseWait promise = liftIO $ do
    promise' <- unsafeManagedPtrGetPtr promise
    result <- gst_promise_wait promise'
    let result' = (toEnum . fromIntegral) result
    touchManagedPtr promise
    return result'

#if ENABLE_OVERLOADING
data PromiseWaitMethodInfo
instance (signature ~ (m Gst.Enums.PromiseResult), MonadIO m) => O.MethodInfo PromiseWaitMethodInfo Promise signature where
    overloadedMethod _ = promiseWait

#endif

#if ENABLE_OVERLOADING
type family ResolvePromiseMethod (t :: Symbol) (o :: *) :: * where
    ResolvePromiseMethod "expire" o = PromiseExpireMethodInfo
    ResolvePromiseMethod "interrupt" o = PromiseInterruptMethodInfo
    ResolvePromiseMethod "reply" o = PromiseReplyMethodInfo
    ResolvePromiseMethod "wait" o = PromiseWaitMethodInfo
    ResolvePromiseMethod "getReply" o = PromiseGetReplyMethodInfo
    ResolvePromiseMethod l o = O.MethodResolutionFailed l o

instance (info ~ ResolvePromiseMethod t Promise, O.MethodInfo info Promise p) => OL.IsLabel t (Promise -> 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