{-# LANGUAGE TypeApplications #-}


-- | Copyright  : Will Thompson and Iñaki García Etxebarria
-- License    : LGPL-2.1
-- Maintainer : Iñaki García Etxebarria
-- 
-- A t'GI.GLib.Structs.Once.Once' struct controls a one-time initialization function. Any
-- one-time initialization function must have its own unique t'GI.GLib.Structs.Once.Once'
-- struct.
-- 
-- /Since: 2.4/

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

module GI.GLib.Structs.Once
    ( 

-- * Exported types
    Once(..)                                ,
    newZeroOnce                             ,


 -- * Methods

#if defined(ENABLE_OVERLOADING)
    ResolveOnceMethod                       ,
#endif

-- ** initEnter #method:initEnter#

    onceInitEnter                           ,


-- ** initEnterImpl #method:initEnterImpl#

    onceInitEnterImpl                       ,


-- ** initEnterPointer #method:initEnterPointer#

    onceInitEnterPointer                    ,


-- ** initLeave #method:initLeave#

    onceInitLeave                           ,


-- ** initLeavePointer #method:initLeavePointer#

    onceInitLeavePointer                    ,




 -- * Properties


-- ** retval #attr:retval#
-- | the value returned by the call to the function, if /@status@/
--          is 'GI.GLib.Enums.OnceStatusReady'

    clearOnceRetval                         ,
    getOnceRetval                           ,
#if defined(ENABLE_OVERLOADING)
    once_retval                             ,
#endif
    setOnceRetval                           ,


-- ** status #attr:status#
-- | the status of the t'GI.GLib.Structs.Once.Once'

    getOnceStatus                           ,
#if defined(ENABLE_OVERLOADING)
    once_status                             ,
#endif
    setOnceStatus                           ,




    ) 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.BasicTypes as B.Types
import qualified Data.GI.Base.ManagedPtr as B.ManagedPtr
import qualified Data.GI.Base.GArray as B.GArray
import qualified Data.GI.Base.GClosure as B.GClosure
import qualified Data.GI.Base.GError as B.GError
import qualified Data.GI.Base.GHashTable as B.GHT
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.GI.Base.Signals as B.Signals
import qualified Control.Monad.IO.Class as MIO
import qualified Data.Coerce as Coerce
import qualified Data.Text as T
import qualified Data.Kind as DK
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 GHC.Records as R
import qualified Data.Word as DW
import qualified Data.Int as DI
import qualified System.Posix.Types as SPT
import qualified Foreign.C.Types as FCT

-- Workaround for https://gitlab.haskell.org/ghc/ghc/-/issues/23392
#if MIN_VERSION_base(4,18,0)
import {-# SOURCE #-} qualified GI.GLib.Enums as GLib.Enums

#else
import {-# SOURCE #-} qualified GI.GLib.Enums as GLib.Enums

#endif

-- | Memory-managed wrapper type.
newtype Once = Once (SP.ManagedPtr Once)
    deriving (Eq)

instance SP.ManagedPtrNewtype Once where
    toManagedPtr (Once p) = p

instance BoxedPtr Once where
    boxedPtrCopy = \p -> B.ManagedPtr.withManagedPtr p (copyBytes 16 >=> B.ManagedPtr.wrapPtr Once)
    boxedPtrFree = \x -> SP.withManagedPtr x SP.freeMem
instance CallocPtr Once where
    boxedPtrCalloc = callocBytes 16


-- | Construct a t'Once' struct initialized to zero.
newZeroOnce :: MonadIO m => m Once
newZeroOnce = liftIO $ boxedPtrCalloc >>= wrapPtr Once

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


-- | Get the value of the “@status@” field.
-- When <https://github.com/haskell-gi/haskell-gi/wiki/Overloading overloading> is enabled, this is equivalent to
-- 
-- @
-- 'Data.GI.Base.Attributes.get' once #status
-- @
getOnceStatus :: MonadIO m => Once -> m GLib.Enums.OnceStatus
getOnceStatus s = liftIO $ withManagedPtr s $ \ptr -> do
    val <- peek (ptr `plusPtr` 0) :: IO CUInt
    let val' = (toEnum . fromIntegral) val
    return val'

-- | Set the value of the “@status@” field.
-- When <https://github.com/haskell-gi/haskell-gi/wiki/Overloading overloading> is enabled, this is equivalent to
-- 
-- @
-- 'Data.GI.Base.Attributes.set' once [ #status 'Data.GI.Base.Attributes.:=' value ]
-- @
setOnceStatus :: MonadIO m => Once -> GLib.Enums.OnceStatus -> m ()
setOnceStatus s val = liftIO $ withManagedPtr s $ \ptr -> do
    let val' = (fromIntegral . fromEnum) val
    poke (ptr `plusPtr` 0) (val' :: CUInt)

#if defined(ENABLE_OVERLOADING)
data OnceStatusFieldInfo
instance AttrInfo OnceStatusFieldInfo where
    type AttrBaseTypeConstraint OnceStatusFieldInfo = (~) Once
    type AttrAllowedOps OnceStatusFieldInfo = '[ 'AttrSet, 'AttrGet]
    type AttrSetTypeConstraint OnceStatusFieldInfo = (~) GLib.Enums.OnceStatus
    type AttrTransferTypeConstraint OnceStatusFieldInfo = (~)GLib.Enums.OnceStatus
    type AttrTransferType OnceStatusFieldInfo = GLib.Enums.OnceStatus
    type AttrGetType OnceStatusFieldInfo = GLib.Enums.OnceStatus
    type AttrLabel OnceStatusFieldInfo = "status"
    type AttrOrigin OnceStatusFieldInfo = Once
    attrGet = getOnceStatus
    attrSet = setOnceStatus
    attrConstruct = undefined
    attrClear = undefined
    attrTransfer _ v = do
        return v
    dbgAttrInfo = P.Just (O.ResolvedSymbolInfo {
        O.resolvedSymbolName = "GI.GLib.Structs.Once.status"
        , O.resolvedSymbolURL = "https://hackage.haskell.org/package/gi-glib-2.0.30/docs/GI-GLib-Structs-Once.html#g:attr:status"
        })

once_status :: AttrLabelProxy "status"
once_status = AttrLabelProxy

#endif


-- | Get the value of the “@retval@” field.
-- When <https://github.com/haskell-gi/haskell-gi/wiki/Overloading overloading> is enabled, this is equivalent to
-- 
-- @
-- 'Data.GI.Base.Attributes.get' once #retval
-- @
getOnceRetval :: MonadIO m => Once -> m (Ptr ())
getOnceRetval s = liftIO $ withManagedPtr s $ \ptr -> do
    val <- peek (ptr `plusPtr` 8) :: IO (Ptr ())
    return val

-- | Set the value of the “@retval@” field.
-- When <https://github.com/haskell-gi/haskell-gi/wiki/Overloading overloading> is enabled, this is equivalent to
-- 
-- @
-- 'Data.GI.Base.Attributes.set' once [ #retval 'Data.GI.Base.Attributes.:=' value ]
-- @
setOnceRetval :: MonadIO m => Once -> Ptr () -> m ()
setOnceRetval s val = liftIO $ withManagedPtr s $ \ptr -> do
    poke (ptr `plusPtr` 8) (val :: Ptr ())

-- | Set the value of the “@retval@” field to `Nothing`.
-- When <https://github.com/haskell-gi/haskell-gi/wiki/Overloading overloading> is enabled, this is equivalent to
-- 
-- @
-- 'Data.GI.Base.Attributes.clear' #retval
-- @
clearOnceRetval :: MonadIO m => Once -> m ()
clearOnceRetval s = liftIO $ withManagedPtr s $ \ptr -> do
    poke (ptr `plusPtr` 8) (FP.nullPtr :: Ptr ())

#if defined(ENABLE_OVERLOADING)
data OnceRetvalFieldInfo
instance AttrInfo OnceRetvalFieldInfo where
    type AttrBaseTypeConstraint OnceRetvalFieldInfo = (~) Once
    type AttrAllowedOps OnceRetvalFieldInfo = '[ 'AttrSet, 'AttrGet, 'AttrClear]
    type AttrSetTypeConstraint OnceRetvalFieldInfo = (~) (Ptr ())
    type AttrTransferTypeConstraint OnceRetvalFieldInfo = (~)(Ptr ())
    type AttrTransferType OnceRetvalFieldInfo = (Ptr ())
    type AttrGetType OnceRetvalFieldInfo = Ptr ()
    type AttrLabel OnceRetvalFieldInfo = "retval"
    type AttrOrigin OnceRetvalFieldInfo = Once
    attrGet = getOnceRetval
    attrSet = setOnceRetval
    attrConstruct = undefined
    attrClear = clearOnceRetval
    attrTransfer _ v = do
        return v
    dbgAttrInfo = P.Just (O.ResolvedSymbolInfo {
        O.resolvedSymbolName = "GI.GLib.Structs.Once.retval"
        , O.resolvedSymbolURL = "https://hackage.haskell.org/package/gi-glib-2.0.30/docs/GI-GLib-Structs-Once.html#g:attr:retval"
        })

once_retval :: AttrLabelProxy "retval"
once_retval = AttrLabelProxy

#endif



#if defined(ENABLE_OVERLOADING)
instance O.HasAttributeList Once
type instance O.AttributeList Once = OnceAttributeList
type OnceAttributeList = ('[ '("status", OnceStatusFieldInfo), '("retval", OnceRetvalFieldInfo)] :: [(Symbol, DK.Type)])
#endif

-- method Once::init_enter
-- method type : MemberFunction
-- Args: [ Arg
--           { argCName = "location"
--           , argType = TBasicType TPtr
--           , argCType = Just "void*"
--           , direction = DirectionInout
--           , mayBeNull = False
--           , argDoc =
--               Documentation
--                 { rawDocText =
--                     Just "location of a static initializable variable\n   containing 0"
--                 , sinceVersion = Nothing
--                 }
--           , argScope = ScopeTypeInvalid
--           , argClosure = -1
--           , argDestroy = -1
--           , argCallerAllocates = False
--           , argCallbackUserData = False
--           , transfer = TransferEverything
--           }
--       ]
-- Lengths: []
-- returnType: Just (TBasicType TBoolean)
-- throws : False
-- Skip return : False

foreign import ccall "g_once_init_enter" g_once_init_enter :: 
    Ptr (Ptr ()) ->                         -- location : TBasicType TPtr
    IO CInt

-- | Function to be called when starting a critical initialization
-- section. The argument /@location@/ must point to a static
-- 0-initialized variable that will be set to a value other than 0 at
-- the end of the initialization section. In combination with
-- 'GI.GLib.Functions.onceInitLeave' and the unique address /@valueLocation@/, it can
-- be ensured that an initialization section will be executed only once
-- during a program\'s life time, and that concurrent threads are
-- blocked until initialization completed. To be used in constructs
-- like this:
-- 
-- 
-- === /C code/
-- >
-- >  static gsize initialization_value = 0;
-- >
-- >  if (g_once_init_enter (&initialization_value))
-- >    {
-- >      gsize setup_value = 42; // initialization code here
-- >
-- >      g_once_init_leave (&initialization_value, setup_value);
-- >    }
-- >
-- >  // use initialization_value here
-- 
-- 
-- While /@location@/ has a @volatile@ qualifier, this is a historical artifact and
-- the pointer passed to it should not be @volatile@.
-- 
-- /Since: 2.14/
onceInitEnter ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Ptr ()
    -- ^ /@location@/: location of a static initializable variable
    --    containing 0
    -> m ((Bool, Ptr ()))
    -- ^ __Returns:__ 'P.True' if the initialization section should be entered,
    --     'P.False' and blocks otherwise
onceInitEnter location = liftIO $ do
    location' <- allocMem :: IO (Ptr (Ptr ()))
    poke location' location
    result <- g_once_init_enter location'
    let result' = (/= 0) result
    location'' <- peek location'
    freeMem location'
    return (result', location'')

#if defined(ENABLE_OVERLOADING)
#endif

-- method Once::init_enter_impl
-- method type : MemberFunction
-- Args: [ Arg
--           { argCName = "location"
--           , argType = TBasicType TSize
--           , argCType = Just "volatile gsize*"
--           , direction = DirectionIn
--           , mayBeNull = False
--           , argDoc =
--               Documentation { rawDocText = Nothing , sinceVersion = Nothing }
--           , argScope = ScopeTypeInvalid
--           , argClosure = -1
--           , argDestroy = -1
--           , argCallerAllocates = False
--           , argCallbackUserData = False
--           , transfer = TransferNothing
--           }
--       ]
-- Lengths: []
-- returnType: Just (TBasicType TBoolean)
-- throws : False
-- Skip return : False

foreign import ccall "g_once_init_enter_impl" g_once_init_enter_impl :: 
    FCT.CSize ->                            -- location : TBasicType TSize
    IO CInt

-- | /No description available in the introspection data./
onceInitEnterImpl ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    FCT.CSize
    -> m Bool
onceInitEnterImpl location = liftIO $ do
    result <- g_once_init_enter_impl location
    let result' = (/= 0) result
    return result'

#if defined(ENABLE_OVERLOADING)
#endif

-- method Once::init_enter_pointer
-- method type : MemberFunction
-- Args: [ Arg
--           { argCName = "location"
--           , argType = TBasicType TPtr
--           , argCType = Just "void*"
--           , direction = DirectionIn
--           , mayBeNull = False
--           , argDoc =
--               Documentation
--                 { rawDocText =
--                     Just
--                       "location of a static initializable variable\n   containing `NULL`"
--                 , sinceVersion = Nothing
--                 }
--           , argScope = ScopeTypeInvalid
--           , argClosure = -1
--           , argDestroy = -1
--           , argCallerAllocates = False
--           , argCallbackUserData = False
--           , transfer = TransferNothing
--           }
--       ]
-- Lengths: []
-- returnType: Just (TBasicType TBoolean)
-- throws : False
-- Skip return : False

foreign import ccall "g_once_init_enter_pointer" g_once_init_enter_pointer :: 
    Ptr () ->                               -- location : TBasicType TPtr
    IO CInt

-- | This functions behaves in the same way as 'GI.GLib.Functions.onceInitEnter', but can
-- can be used to initialize pointers (or @/guintptr/@) instead of @/gsize/@.
-- 
-- 
-- === /C code/
-- >
-- >  static MyStruct *interesting_struct = NULL;
-- >
-- >  if (g_once_init_enter_pointer (&interesting_struct))
-- >    {
-- >      MyStruct *setup_value = allocate_my_struct (); // initialization code here
-- >
-- >      g_once_init_leave_pointer (&interesting_struct, g_steal_pointer (&setup_value));
-- >    }
-- >
-- >  // use interesting_struct here
-- 
-- 
-- /Since: 2.80/
onceInitEnterPointer ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Ptr ()
    -- ^ /@location@/: location of a static initializable variable
    --    containing @NULL@
    -> m Bool
    -- ^ __Returns:__ 'P.True' if the initialization section should be entered,
    --     'P.False' and blocks otherwise
onceInitEnterPointer location = liftIO $ do
    result <- g_once_init_enter_pointer location
    let result' = (/= 0) result
    return result'

#if defined(ENABLE_OVERLOADING)
#endif

-- method Once::init_leave
-- method type : MemberFunction
-- Args: [ Arg
--           { argCName = "location"
--           , argType = TBasicType TPtr
--           , argCType = Just "void*"
--           , direction = DirectionInout
--           , mayBeNull = False
--           , argDoc =
--               Documentation
--                 { rawDocText =
--                     Just "location of a static initializable variable\n   containing 0"
--                 , sinceVersion = Nothing
--                 }
--           , argScope = ScopeTypeInvalid
--           , argClosure = -1
--           , argDestroy = -1
--           , argCallerAllocates = False
--           , argCallbackUserData = False
--           , transfer = TransferEverything
--           }
--       , Arg
--           { argCName = "result"
--           , argType = TBasicType TSize
--           , argCType = Just "gsize"
--           , direction = DirectionIn
--           , mayBeNull = False
--           , argDoc =
--               Documentation
--                 { rawDocText = Just "new non-0 value for `*value_location`"
--                 , sinceVersion = Nothing
--                 }
--           , argScope = ScopeTypeInvalid
--           , argClosure = -1
--           , argDestroy = -1
--           , argCallerAllocates = False
--           , argCallbackUserData = False
--           , transfer = TransferNothing
--           }
--       ]
-- Lengths: []
-- returnType: Nothing
-- throws : False
-- Skip return : False

foreign import ccall "g_once_init_leave" g_once_init_leave :: 
    Ptr (Ptr ()) ->                         -- location : TBasicType TPtr
    FCT.CSize ->                            -- result : TBasicType TSize
    IO ()

-- | Counterpart to 'GI.GLib.Functions.onceInitEnter'. Expects a location of a static
-- 0-initialized initialization variable, and an initialization value
-- other than 0. Sets the variable to the initialization value, and
-- releases concurrent threads blocking in 'GI.GLib.Functions.onceInitEnter' on this
-- initialization variable.
-- 
-- While /@location@/ has a @volatile@ qualifier, this is a historical artifact and
-- the pointer passed to it should not be @volatile@.
-- 
-- /Since: 2.14/
onceInitLeave ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Ptr ()
    -- ^ /@location@/: location of a static initializable variable
    --    containing 0
    -> FCT.CSize
    -- ^ /@result@/: new non-0 value for @*value_location@
    -> m ((Ptr ()))
onceInitLeave location result_ = liftIO $ do
    location' <- allocMem :: IO (Ptr (Ptr ()))
    poke location' location
    g_once_init_leave location' result_
    location'' <- peek location'
    freeMem location'
    return location''

#if defined(ENABLE_OVERLOADING)
#endif

-- method Once::init_leave_pointer
-- method type : MemberFunction
-- Args: [ Arg
--           { argCName = "location"
--           , argType = TBasicType TPtr
--           , argCType = Just "void*"
--           , direction = DirectionIn
--           , mayBeNull = False
--           , argDoc =
--               Documentation
--                 { rawDocText =
--                     Just
--                       "location of a static initializable variable\n   containing `NULL`"
--                 , sinceVersion = Nothing
--                 }
--           , argScope = ScopeTypeInvalid
--           , argClosure = -1
--           , argDestroy = -1
--           , argCallerAllocates = False
--           , argCallbackUserData = False
--           , transfer = TransferNothing
--           }
--       , Arg
--           { argCName = "result"
--           , argType = TBasicType TPtr
--           , argCType = Just "gpointer"
--           , direction = DirectionIn
--           , mayBeNull = True
--           , argDoc =
--               Documentation
--                 { rawDocText = Just "new non-`NULL` value for `*location`"
--                 , sinceVersion = Nothing
--                 }
--           , argScope = ScopeTypeInvalid
--           , argClosure = -1
--           , argDestroy = -1
--           , argCallerAllocates = False
--           , argCallbackUserData = False
--           , transfer = TransferNothing
--           }
--       ]
-- Lengths: []
-- returnType: Nothing
-- throws : False
-- Skip return : False

foreign import ccall "g_once_init_leave_pointer" g_once_init_leave_pointer :: 
    Ptr () ->                               -- location : TBasicType TPtr
    Ptr () ->                               -- result : TBasicType TPtr
    IO ()

-- | Counterpart to 'GI.GLib.Functions.onceInitEnterPointer'. Expects a location of a static
-- @NULL@-initialized initialization variable, and an initialization value
-- other than @NULL@. Sets the variable to the initialization value, and
-- releases concurrent threads blocking in 'GI.GLib.Functions.onceInitEnterPointer' on this
-- initialization variable.
-- 
-- This functions behaves in the same way as 'GI.GLib.Functions.onceInitLeave', but
-- can be used to initialize pointers (or @/guintptr/@) instead of @/gsize/@.
-- 
-- /Since: 2.80/
onceInitLeavePointer ::
    (B.CallStack.HasCallStack, MonadIO m) =>
    Ptr ()
    -- ^ /@location@/: location of a static initializable variable
    --    containing @NULL@
    -> Ptr ()
    -- ^ /@result@/: new non-@NULL@ value for @*location@
    -> m ()
onceInitLeavePointer location result_ = liftIO $ do
    g_once_init_leave_pointer location result_
    return ()

#if defined(ENABLE_OVERLOADING)
#endif

#if defined(ENABLE_OVERLOADING)
type family ResolveOnceMethod (t :: Symbol) (o :: DK.Type) :: DK.Type where
    ResolveOnceMethod l o = O.MethodResolutionFailed l o

instance (info ~ ResolveOnceMethod t Once, O.OverloadedMethod info Once p) => OL.IsLabel t (Once -> p) where
#if MIN_VERSION_base(4,10,0)
    fromLabel = O.overloadedMethod @info
#else
    fromLabel _ = O.overloadedMethod @info
#endif

#if MIN_VERSION_base(4,13,0)
instance (info ~ ResolveOnceMethod t Once, O.OverloadedMethod info Once p, R.HasField t Once p) => R.HasField t Once p where
    getField = O.overloadedMethod @info

#endif

instance (info ~ ResolveOnceMethod t Once, O.OverloadedMethodInfo info Once) => OL.IsLabel t (O.MethodProxy info Once) where
#if MIN_VERSION_base(4,10,0)
    fromLabel = O.MethodProxy
#else
    fromLabel _ = O.MethodProxy
#endif

#endif


