1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 #include <pw_async/dispatcher.h>
17 #include <pw_async/task.h>
18 
19 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
20 
21 namespace bt {
22 
23 // SmartTask is a utility that wraps a pw::async::Task and adds features like
24 // cancelation upon destruction and state tracking. It is not thread safe, and
25 // should only be used on the same thread that the dispatcher is running on.
26 class SmartTask {
27  public:
28   explicit SmartTask(pw::async::Dispatcher& dispatcher,
29                      pw::async::TaskFunction&& func = nullptr)
dispatcher_(dispatcher)30       : dispatcher_(dispatcher), func_(std::move(func)) {}
31 
~SmartTask()32   ~SmartTask() {
33     if (pending_) {
34       PW_CHECK(Cancel());
35     }
36   }
37 
PostAt(pw::chrono::SystemClock::time_point time)38   void PostAt(pw::chrono::SystemClock::time_point time) {
39     pending_ = true;
40     dispatcher_.PostAt(task_, time);
41   }
42 
PostAfter(pw::chrono::SystemClock::duration delay)43   void PostAfter(pw::chrono::SystemClock::duration delay) {
44     pending_ = true;
45     dispatcher_.PostAfter(task_, delay);
46   }
47 
Post()48   void Post() {
49     pending_ = true;
50     dispatcher_.Post(task_);
51   }
52 
Cancel()53   bool Cancel() {
54     pending_ = false;
55     return dispatcher_.Cancel(task_);
56   }
57 
set_function(pw::async::TaskFunction && func)58   void set_function(pw::async::TaskFunction&& func) { func_ = std::move(func); }
59 
is_pending()60   bool is_pending() const { return pending_; }
61 
dispatcher()62   pw::async::Dispatcher& dispatcher() const { return dispatcher_; }
63 
64  private:
65   pw::async::Dispatcher& dispatcher_;
66   pw::async::Task task_{[this](pw::async::Context& ctx, pw::Status status) {
67     pending_ = false;
68     if (func_) {
69       func_(ctx, status);
70     }
71   }};
72   pw::async::TaskFunction func_ = nullptr;
73   bool pending_ = false;
74 };
75 
76 }  // namespace bt
77