C/C++ API Reference
Loading...
Searching...
No Matches
transform.h
1// Copyright 2026 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#pragma once
15
16// __ ___ ___ _ _ ___ _ _ ___
17// \ \ / /_\ | _ \ \| |_ _| \| |/ __|
18// \ \/\/ / _ \| / .` || || .` | (_ |
19// \_/\_/_/ \_\_|_\_|\_|___|_|\_|\___|
20// _____ _____ ___ ___ ___ __ __ ___ _ _ _____ _ _
21// | __\ \/ / _ \ __| _ \_ _| \/ | __| \| |_ _/_\ | |
22// | _| > <| _/ _|| /| || |\/| | _|| .` | | |/ _ \| |__
23// |___/_/\_\_| |___|_|_\___|_| |_|___|_|\_| |_/_/ \_\____|
24//
25// These interfaces are in an early, experimental state. The APIs are in flux
26// and may change without notice. Additionally, the code size is not optimized
27// and may be larger than expected.
28
29#include <optional>
30#include <variant>
31
32#include "pw_async2/future.h"
33#include "pw_async2/poll.h"
34#include "pw_async2/try.h"
35
36namespace pw::async2::experimental {
37namespace internal {
38
39template <typename Func>
40struct MapOp {
41 Func func;
42};
43
44template <typename Func>
45struct ThenOp {
46 Func func;
47};
48
49} // namespace internal
50
51template <typename Func>
52constexpr internal::MapOp<Func> Map(Func&& f) {
53 return internal::MapOp<Func>{std::forward<Func>(f)};
54}
55
56template <typename InnerFuture, typename Func>
57class MapFuture {
58 public:
59 using value_type =
60 std::invoke_result_t<Func, typename InnerFuture::value_type>;
61
62 MapFuture() = default;
63 MapFuture(MapFuture&&) = default;
64 MapFuture& operator=(MapFuture&& other) {
65 inner_ = std::move(other.inner_);
66 func_.reset();
67 if (other.func_) {
68 func_.emplace(std::move(*other.func_));
69 }
70 return *this;
71 }
72
73 MapFuture(InnerFuture&& inner, Func&& func)
74 : inner_(std::move(inner)), func_(std::forward<Func>(func)) {}
75
76 Poll<value_type> Pend(Context& cx) {
77 PW_TRY_READY_ASSIGN(auto result, inner_.Pend(cx));
78 return Poll<value_type>((*func_)(result));
79 }
80
81 bool is_pendable() const { return inner_.is_pendable(); }
82 bool is_complete() const { return inner_.is_complete(); }
83
84 private:
85 InnerFuture inner_;
86 std::optional<Func> func_;
87};
88
89template <typename Func>
90constexpr internal::ThenOp<Func> Then(Func&& f) {
91 return internal::ThenOp<Func>{std::forward<Func>(f)};
92}
93
94template <typename FirstFuture, typename Func>
96 public:
97 using SecondFuture =
98 std::invoke_result_t<Func, typename FirstFuture::value_type>;
99 using value_type = typename SecondFuture::value_type;
100
101 ThenFuture() = default;
102 ThenFuture(ThenFuture&&) = default;
103 ThenFuture& operator=(ThenFuture&& other) {
104 func_.reset();
105 if (other.func_) {
106 func_.emplace(std::move(*other.func_));
107 }
108 state_ = std::move(other.state_);
109 return *this;
110 }
111
112 ThenFuture(FirstFuture&& first, Func&& func)
113 : func_(std::move(func)),
114 state_(std::in_place_index<0>, std::move(first)) {}
115
116 Poll<value_type> Pend(Context& cx) {
117 if (state_.index() == 0) {
118 auto& first = std::get<0>(state_);
119 PW_TRY_READY_ASSIGN(auto result, first.Pend(cx));
120
121 state_.template emplace<1>((*func_)(result));
122 }
123
124 if (state_.index() == 1) {
125 auto& second = std::get<1>(state_);
126 PW_TRY_READY_ASSIGN(auto result, second.Pend(cx));
127 state_.template emplace<2>();
128 return result;
129 }
130
131 return Pending();
132 }
133
134 bool is_pendable() const { return state_.index() != 2; }
135 bool is_complete() const { return state_.index() == 2; }
136
137 private:
138 std::optional<Func> func_;
139 std::variant<FirstFuture, SecondFuture, std::monostate> state_;
140};
141
142namespace internal {
143
144template <typename InnerFuture,
145 typename Func,
146 typename = std::enable_if_t<Future<std::decay_t<InnerFuture>>>>
147auto operator|(InnerFuture&& future, MapOp<Func>&& op) {
148 return MapFuture<std::decay_t<InnerFuture>, std::decay_t<Func>>(
149 std::forward<InnerFuture>(future), std::move(op.func));
150}
151
152template <typename FirstFuture,
153 typename Func,
154 typename = std::enable_if_t<Future<std::decay_t<FirstFuture>>>>
155auto operator|(FirstFuture&& future, ThenOp<Func>&& op) {
156 return ThenFuture<std::decay_t<FirstFuture>, std::decay_t<Func>>(
157 std::forward<FirstFuture>(future), std::move(op.func));
158}
159
160} // namespace internal
161} // namespace pw::async2::experimental
Definition: task.h:45
Definition: poll.h:138
Definition: transform.h:57
Definition: transform.h:95
#define PW_TRY_READY_ASSIGN(lhs, expression)
Definition: try.h:28
constexpr PendingType Pending()
Returns a value indicating that an operation was not yet able to complete.
Definition: poll.h:353