winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

AsyncTokens.h (7374B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #pragma once
      4 #include <AppInstallerLogging.h>
      5 #include <winrt/Windows.Foundation.h>
      6 #include <memory>
      7 
      8 namespace AppInstaller::WinRT
      9 {
     10     namespace details
     11     {
     12         // Type erasing interface for winrt cancellation token.
     13         struct AsyncCancellationTypeErasure
     14         {
     15             virtual ~AsyncCancellationTypeErasure() = default;
     16 
     17             virtual bool IsCancelled() const noexcept = 0;
     18             virtual void Callback(winrt::delegate<>&& callback) const noexcept = 0;
     19             virtual void Cancel() noexcept = 0;
     20         };
     21 
     22         // Type containing winrt cancellation token wrapper.
     23         template <typename Promise>
     24         struct AsyncCancellationT : public AsyncCancellationTypeErasure
     25         {
     26             using Token = winrt::impl::cancellation_token<Promise>;
     27 
     28             AsyncCancellationT(Token&& token) : m_token(std::move(token)) {}
     29 
     30             bool IsCancelled() const noexcept override
     31             {
     32                 return m_token();
     33             }
     34 
     35             void Callback(winrt::delegate<>&& callback) const noexcept override
     36             {
     37                 m_token.callback(std::move(callback));
     38             }
     39 
     40             void Cancel() noexcept override
     41             {
     42                 // This is a bit of a hack, but the cancellation_token provides no access to the underlying promise for the purpose of cancellation.
     43                 static_assert(sizeof(Token) == sizeof(Promise*), "We expect that the cancellation_token has only 1 member and it is a Promise*");
     44                 (*reinterpret_cast<Promise**>(&m_token))->Cancel();
     45             }
     46 
     47         private:
     48             Token m_token;
     49         };
     50     }
     51 
     52     // May hold a cancellation token and provide the ability to check its status.
     53     // If empty, it will act as if it is never cancelled.
     54     struct AsyncCancellation
     55     {
     56         // Create an empty cancellation object, which will never be cancelled.
     57         AsyncCancellation() = default;
     58 
     59         // Create a cancellation object from the winrt token.
     60         template <typename Promise>
     61         AsyncCancellation(winrt::impl::cancellation_token<Promise>&& token)
     62         {
     63             m_token = std::make_shared<details::AsyncCancellationT<Promise>>(std::move(token));
     64         }
     65 
     66         // Returns true if the operation has been cancelled, false if not.
     67         bool IsCancelled() const noexcept
     68         {
     69             return m_token ? m_token->IsCancelled() : false;
     70         }
     71 
     72         // Throws the appropriate exception if the operation has been cancelled.
     73         void ThrowIfCancelled() const
     74         {
     75             if (IsCancelled())
     76             {
     77                 AICLI_LOG(Core, Warning, << "Operation cancelled");
     78                 throw winrt::hresult_canceled();
     79             }
     80         }
     81 
     82         // Sets a callback that will be invoked on cancellation.
     83         void Callback(winrt::delegate<>&& callback) const noexcept
     84         {
     85             if (m_token)
     86             {
     87                 m_token->Callback(std::move(callback));
     88             }
     89         }
     90 
     91         std::weak_ptr<details::AsyncCancellationTypeErasure> GetWeak()
     92         {
     93             return m_token;
     94         }
     95 
     96     private:
     97         std::shared_ptr<details::AsyncCancellationTypeErasure> m_token;
     98     };
     99 
    100     namespace details
    101     {
    102         // Type erasing interface for winrt progress token.
    103         template <typename ResultT, typename ProgressT>
    104         struct AsyncProgressTypeErasure
    105         {
    106             virtual ~AsyncProgressTypeErasure() = default;
    107 
    108             virtual void Progress(ProgressT const& progress) const = 0;
    109 
    110             virtual void Result(ResultT const& result) const = 0;
    111         };
    112 
    113         // Type containing winrt progress token wrapper.
    114         template <typename Promise, typename ResultT, typename ProgressT>
    115         struct AsyncProgressT : public AsyncProgressTypeErasure<ResultT, ProgressT>
    116         {
    117             using Token = winrt::impl::progress_token<Promise, ProgressT>;
    118 
    119             AsyncProgressT(Token&& token) : m_token(std::move(token)) {}
    120 
    121             void Progress(ProgressT const& progress) const override
    122             {
    123                 m_token(progress);
    124             }
    125 
    126             void Result(ResultT const& result) const override
    127             {
    128                 m_token.set_result(result);
    129             }
    130 
    131         private:
    132             Token m_token;
    133         };
    134 
    135         // Type containing winrt EventHandler.
    136         template <typename ResultT, typename ProgressT>
    137         struct AsyncProgressEventHandlerT : public AsyncProgressTypeErasure<ResultT, ProgressT>
    138         {
    139             using Token = winrt::Windows::Foundation::EventHandler<ProgressT>;
    140 
    141             AsyncProgressEventHandlerT(Token&& token) : m_token(std::move(token)) {}
    142 
    143             void Progress(ProgressT const& progress) const override
    144             {
    145                 m_token(m_result, progress);
    146             }
    147 
    148             void Result(ResultT const& result) const override
    149             {
    150                 m_result = result;
    151             }
    152 
    153         private:
    154             mutable ResultT m_result = nullptr;
    155             Token m_token;
    156         };
    157     }
    158 
    159     // May hold a progress token and provide the ability to send progress updates.
    160     // If empty, progress will be dropped on calls here.
    161     template <typename ResultT, typename ProgressT>
    162     struct AsyncProgress : public AsyncCancellation
    163     {
    164         // Create an empty progress object.
    165         AsyncProgress() = default;
    166 
    167         // Create a progress object from the winrt token.
    168         template <typename Promise>
    169         AsyncProgress(winrt::impl::progress_token<Promise, ProgressT>&& progress, winrt::impl::cancellation_token<Promise>&& cancellation) :
    170             AsyncCancellation(std::move(cancellation))
    171         {
    172             m_token = std::make_unique<details::AsyncProgressT<Promise, ResultT, ProgressT>>(std::move(progress));
    173         }
    174 
    175         // Create a progress object from an EventHandler.
    176         template <typename Promise>
    177         AsyncProgress(winrt::Windows::Foundation::EventHandler<ProgressT>&& progress, winrt::impl::cancellation_token<Promise>&& cancellation) :
    178             AsyncCancellation(std::move(cancellation))
    179         {
    180             m_token = std::make_unique<details::AsyncProgressEventHandlerT<ResultT, ProgressT>>(std::move(progress));
    181         }
    182 
    183         // Create a cancellation only object.
    184         template <typename Promise>
    185         AsyncProgress(winrt::impl::cancellation_token<Promise>&& cancellation) :
    186             AsyncCancellation(std::move(cancellation))
    187         {
    188         }
    189 
    190         // Sends progress if this object is not empty.
    191         void Progress(ProgressT const& progress) const
    192         {
    193             if (m_token)
    194             {
    195                 m_token->Progress(progress);
    196             }
    197         }
    198 
    199         // Sets the result onto the progress object if it is not empty.
    200         void Result(ResultT const& result) const
    201         {
    202             if (m_token)
    203             {
    204                 m_token->Result(result);
    205             }
    206         }
    207 
    208     private:
    209         std::unique_ptr<details::AsyncProgressTypeErasure<ResultT, ProgressT>> m_token;
    210     };
    211 }