• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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 #include "pw_allocator/allocator.h"
16 #include "pw_async2/dispatcher.h"
17 #include "pw_status/status.h"
18 
19 namespace {
20 
21 using ::pw::OkStatus;
22 using ::pw::Result;
23 using ::pw::Status;
24 using ::pw::allocator::Allocator;
25 using ::pw::async2::Context;
26 using ::pw::async2::Poll;
27 
28 class MyData {
29  public:
30 };
31 
32 class ReceiveFuture {
33  public:
Pend(Context &)34   Poll<Result<MyData>> Pend(Context&) { return MyData(); }
35 };
36 
37 class MyReceiver {
38  public:
Receive()39   ReceiveFuture Receive() { return ReceiveFuture(); }
40 };
41 
42 class SendFuture {
43  public:
Pend(Context &)44   Poll<Status> Pend(Context&) { return OkStatus(); }
45 };
46 
47 class MySender {
48  public:
Send(MyData &&)49   SendFuture Send(MyData&&) { return SendFuture(); }
50 };
51 
52 }  // namespace
53 
54 // NOTE: we double-include so that the example shows the `#includes`, but we
55 // can still define types beforehand.
56 
57 // DOCSTAG: [pw_async2-examples-coro-injection]
58 #include "pw_allocator/allocator.h"
59 #include "pw_async2/coro.h"
60 #include "pw_result/result.h"
61 
62 namespace {
63 
64 using ::pw::OkStatus;
65 using ::pw::Result;
66 using ::pw::Status;
67 using ::pw::allocator::Allocator;
68 using ::pw::async2::Coro;
69 using ::pw::async2::CoroContext;
70 
71 class MyReceiver;
72 class MySender;
73 
74 /// Create a coroutine which asynchronously receives a value from
75 /// ``receiver`` and forwards it to ``sender``.
76 ///
77 /// Note: the ``Allocator`` argument is used by the ``Coro<T>`` internals to
78 /// allocate the coroutine state. If this allocation fails, ``Coro<Status>``
79 /// will return ``Status::Internal()``.
ReceiveAndSend(CoroContext &,MyReceiver receiver,MySender sender)80 Coro<Status> ReceiveAndSend(CoroContext&,
81                             MyReceiver receiver,
82                             MySender sender) {
83   pw::Result<MyData> data = co_await receiver.Receive();
84   if (!data.ok()) {
85     PW_LOG_ERROR("Receiving failed: %s", data.status().str());
86     co_return Status::Unavailable();
87   }
88   pw::Status sent = co_await sender.Send(std::move(*data));
89   if (!sent.ok()) {
90     PW_LOG_ERROR("Sending failed: %s", sent.str());
91     co_return Status::Unavailable();
92   }
93   co_return OkStatus();
94 }
95 
96 }  // namespace
97 // DOCSTAG: [pw_async2-examples-coro-injection]
98 
99 #include "pw_allocator/testing.h"
100 
101 namespace {
102 
103 using ::pw::OkStatus;
104 using ::pw::allocator::test::AllocatorForTest;
105 using ::pw::async2::Context;
106 using ::pw::async2::Coro;
107 using ::pw::async2::CoroContext;
108 using ::pw::async2::Dispatcher;
109 using ::pw::async2::Pending;
110 using ::pw::async2::Poll;
111 using ::pw::async2::Ready;
112 using ::pw::async2::Task;
113 
114 class ExpectCoroTask final : public Task {
115  public:
ExpectCoroTask(Coro<pw::Status> && coro)116   ExpectCoroTask(Coro<pw::Status>&& coro) : coro_(std::move(coro)) {}
117 
118  private:
DoPend(Context & cx)119   Poll<> DoPend(Context& cx) final {
120     Poll<Status> result = coro_.Pend(cx);
121     if (result.IsPending()) {
122       return Pending();
123     }
124     EXPECT_EQ(*result, OkStatus());
125     return Ready();
126   }
127   Coro<pw::Status> coro_;
128 };
129 
TEST(CoroExample,ReturnsOk)130 TEST(CoroExample, ReturnsOk) {
131   AllocatorForTest<256> alloc;
132   CoroContext coro_cx(alloc);
133   ExpectCoroTask task = ReceiveAndSend(coro_cx, MyReceiver(), MySender());
134   Dispatcher dispatcher;
135   dispatcher.Post(task);
136   EXPECT_TRUE(dispatcher.RunUntilStalled().IsReady());
137 }
138 
139 }  // namespace
140