text: // Copyright (c) Microsoft Corporation.
  // Licensed under the MIT License.
  
  #pragma once
  
  #include "unknwn.h"
  
  namespace react {
  namespace uwp {
  
  /// <summary>
  /// Represents callback method for for work items processed by the
  /// AsyncWorkQueue.  Callers queuing work items must provide a an IAsyncCallback
  /// implementation to process the work item along with optional user data.  When
  /// the AsyncWorkQueue wishes to have the work item processed it will call this
  /// interface and provide the user data.
  ///
  /// Calls to ProcessWorkItem() will come on a thread that is owned by the work
  /// queue, and it is the implementer's job to ensure its own thread safety.
  /// </summary>
  interface DECLSPEC_UUID("75E41B6E-935D-49b6-A8C7-71FC123EE91D") IAsyncCallback : IUnknown {
    /// <summary>
    /// Invoked from AsyncWorkQueue to ask the client to process the work item.
    /// </summary>
    /// <param name="pUserData">[in] Reference to the user data</param>
    /// <returns>
    /// If ProcessWorkItem returns an error code it will be logged but execution
    /// will continue.
    /// </returns>
    STDMETHOD(ProcessWorkItem)(_In_opt_ IUnknown * pUserData) PURE;
  
    /// <summary>
    /// Invoked from AsyncWorkQueue to ask the client to cancel a processing work
    /// item. This can be called on any thread at any time. Implementers should
    /// strive to do minimal work in this function, just enough to signal the
    /// thread that's actually running the work item if possible. It is also
    /// possible for a work item to be canceled multiple times while it is running
    /// and implementers must handle this. If there is no way to cancel a specific
    /// work item while it is running then this function should do nothing but
    /// return S_OK.
    /// </summary>
    /// <param name="pUserData">[in] Reference to the user data</param>
    /// <returns>
    /// This should return S_OK if the work item was successfully canceled or if
    /// there is no way to interrupt its work. It should return an error only if
    /// something unexpectedly failed. The result of the error return will depend
    /// on the caller. If this function was invoked because of an external call to
    /// IAsyncWorkQueue::CancelAll*() then the error will be returned to the
    /// caller. But if it was invoked as the work queue is shutting down then the
    /// failure will be logged but execution will continue.
    /// </returns>
    STDMETHOD(CancelWorkItem)(_In_opt_ IUnknown * pUserData) PURE;
  };
  
  /// <summary>
  /// Interface that can be exposed by callbacks to get notified if they are
  /// canceled without ever being executed. Note that CancelWorkItem will be
  /// called for a work item that was canceled during execution. If a work item
  /// implements this interface, this call will be made if that work item gets
  /// canceled before it executes. Implementations should strive to do minimal
  /// work in this callback - preferably just signaling or making note of the fact
  /// that the work item was never run.
  /// </summary>
  interface DECLSPEC_UUID("16f7789f-46bb-4124-aba3-266a56d464c2") IAsyncCallbackCancelExtension : public IUnknown {
    /// <summary>
    /// Called by the work queue if a work item is canceled without every being
    /// executed.
    /// </summary>
    /// <param name="pUserData">User context passed to the work item</param>
    virtual void OnWorkItemCanceled(_In_opt_ IUnknown * pUserData) = 0;
  };
  
  /// <summary>
  /// Represents a work queue that processes its work items serially on a thread
  /// other than the one from which the items are queued. Individual work items
  /// consist of a callback object that implements IAsyncCallback and user data
  /// typed as IUnknown since only the client will understand its details.
  /// </summary>
  interface DECLSPEC_UUID("51AB52B1-F754-44bb-8F84-368313D9500F") IAsyncWorkQueue : IUnknown {
    /// <summary>
    /// Cancel all work items. This function returns after clearing the list of
    /// work items and requesting any processing work item to cancel. It does not
    /// wait for that item to finish.
    /// </summary>
    virtual void CancelAllAsync() = 0;
  
    /// <summary>
    /// Cancels all work items and then waits for any running work item to
    /// complete before returning. When this method returns, subsequent attempts
    /// to queue work items will still succeed. Use ShutDown instead to cancel all
    /// items and permanently disable the work queue.
    /// </summary>
    /// <remarks>
    /// Caller should pay attention to the thread on which this function is
    /// called. If it is called on any worker thread for IAsyncWorkQueue's
    /// processing it could lead to deadlock. Here is some guidance:
    ///  a) Never call this function in IAsyncCallback::ProcessWorkItem.
    ///  b) If call this function in an object's destructor, you need to fully
    ///  understand the
    ///     lifetime of the object to make sure it is never destroyed on any
    ///     worker thread. For example, if a client object holds a reference to
    ///     IAsyncWorkQueue and is implemented as a IAsyncCallback as well,
    ///     calling this function in client object's destructor may cause
    ///     deadlock.
    /// </remarks>
    virtual void CancelAllAndWait() = 0;
  
    /// <summary>
    /// Cancels all work items and then waits for any running work item to
    /// complete before returning. When this method returns, subsequent attempts
    /// to queue work items fail.
    /// </summary>
    /// <remarks>
    /// 1. It is required to call Shutdown before destroy the IAsyncWorkQueue
    /// object.
    /// 2. Caller should pay attention to the thread on which this function is
    /// called. If it is
    ///    called on any worker thread for IAsyncWorkQueue's processing it could
    ///    lead to deadlock. Here is some guidance: a) Never call this function in
    ///    IAsyncCallback::ProcessWorkItem. b) If call this function in an
    ///    object's destructor, you need to fully understand the
    ///       lifetime of the object to make sure it is never destroyed on any
    ///       worker thread. For example, if a client object holds a reference to
    ///       IAsyncWorkQueue and is implemented as a IAsyncCallback as well,
    ///       calling this function in client object's destructor may cause
    ///       deadlock.
    /// </remarks>
    virtual void ShutDown() = 0;
  
    /// <summary>
    /// Waits for queued callbacks to be completed
    /// </summary>
    /// <remarks>
    /// Waits for the dispatching of callbacks to complete. If new items are added
    /// to the queue while waiting, those items will also be included in the wait.
    /// </remarks>
    virtual void WaitForCallbacksToComplete() = 0;
  
    /// <summary>
    /// Adds a work item to the back of the queue.  These items are dequeued one
    /// by one and processed in a serial fashion.  Processing is done by invoking
    /// the callback with the associated userData.
    /// </summary>
    /// <param name="pCallback">[in] The object to call for processing the work
    /// item</param> <param name="pUserData">[in] Data to pass to the callback
    /// when processing the work item</param> <returns> HRESULT.
    /// </returns>
    virtual HRESULT QueueWorkItem(_In_ IAsyncCallback * pCallback, _In_opt_ IUnknown * pUserData) = 0;
  };
  
  /// <summary>
  /// Creates an instance of IAsyncWorkQueue.
  /// </summary>
  /// <param name="ppAsyncWorkQueue">[out] The created instance.</param>
  /// <returns>
  /// HRESULT.
  /// </returns>
  HRESULT CreateAsyncWorkQueue(_Outptr_ IAsyncWorkQueue **ppAsyncWorkQueue);
  
  } // namespace uwp
  } // namespace react
  