1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://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,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef META_API_FUTURE_H
17 #define META_API_FUTURE_H
18
19 #include <base/containers/type_traits.h>
20
21 #include <meta/interface/detail/any.h>
22 #include <meta/interface/interface_helpers.h>
23 #include <meta/interface/intf_future.h>
24
META_BEGIN_NAMESPACE()25 META_BEGIN_NAMESPACE()
26
27 /**
28 * @brief Callable implementation for continuation functions used with futures.
29 */
30 template<typename Func>
31 class ContinuationFunction : public IntroduceInterfaces<IFutureContinuation> {
32 META_INTERFACE(
33 IntroduceInterfaces<IFutureContinuation>, ContinuationFunction, "f4736552-7365-4c8f-bbe9-a065e2c30382");
34
35 public:
36 ContinuationFunction(Func func) : func_(BASE_NS::move(func)) {}
37
38 IAny::Ptr Invoke(const IAny::Ptr& value) override
39 {
40 using Result = BASE_NS::remove_reference_t<decltype(func_(value))>;
41 if constexpr (!BASE_NS::is_same_v<Result, void>) {
42 return IAny::Ptr(new Any<Result>(func_(value)));
43 } else {
44 func_(value);
45 return nullptr;
46 }
47 }
48
49 private:
50 Func func_;
51 };
52
53 /**
54 * @brief Create continuation function from callable entity (e.g. lambda).
55 * The callable entity has to take IAny::Ptr as parameter which is the value from the future.
56 */
57 template<typename Func>
CreateContinuation(Func func)58 IFutureContinuation::Ptr CreateContinuation(Func func)
59 {
60 return IFutureContinuation::Ptr(new ContinuationFunction(BASE_NS::move(func)));
61 }
62
63 template<typename Param>
64 struct ContinuationTypedFuntionTypeImpl {
65 using Type = void(Param);
66 };
67
68 template<>
69 struct ContinuationTypedFuntionTypeImpl<void> {
70 using Type = void();
71 };
72
73 template<typename Param>
74 using ContinuationTypedFuntionType = typename ContinuationTypedFuntionTypeImpl<Param>::Type;
75
76 template<typename T>
77 T VoidResultHelper()
78 {
79 if constexpr (!BASE_NS::is_same_v<T, void>) {
80 return T {};
81 }
82 }
83
84 template<typename Type>
85 class Future {
86 public:
87 using StateType = IFuture::StateType;
88
89 Future(IFuture::Ptr fut = nullptr) : fut_(BASE_NS::move(fut)) {}
90
91 StateType GetState() const
92 {
93 return fut_ ? fut_->GetState() : IFuture::ABANDONED;
94 }
95 StateType Wait() const
96 {
97 return fut_ ? fut_->Wait() : IFuture::ABANDONED;
98 }
99 StateType WaitFor(const TimeSpan& time) const
100 {
101 return fut_ ? fut_->WaitFor(time) : IFuture::ABANDONED;
102 }
103 IFuture::Ptr Then(const IFutureContinuation::Ptr& func, const BASE_NS::shared_ptr<ITaskQueue>& queue)
104 {
105 return fut_ ? fut_->Then(func, queue) : nullptr;
106 }
107 template<typename Func, typename = EnableIfCanInvokeWithArguments<Func, IFutureContinuation::FunctionType>>
108 auto Then(Func func, const BASE_NS::shared_ptr<ITaskQueue>& queue)
109 {
110 return Future<decltype(func(nullptr))>(fut_->Then(CreateContinuation(func), queue));
111 }
112 template<typename Func, typename = EnableIfCanInvokeWithArguments<Func, ContinuationTypedFuntionType<Type>>>
113 auto Then(Func func, const BASE_NS::shared_ptr<ITaskQueue>& queue, int = 0)
114 {
115 using ReturnType = decltype(func(Type {}));
116 return Future<ReturnType>(fut_->Then(CreateContinuation([f = BASE_NS::move(func)](const IAny::Ptr& v) {
117 if (v) {
118 Type value {};
119 if (v->GetValue(value)) {
120 return f(value);
121 }
122 CORE_LOG_W("Type mismatch for future then");
123 }
124 // vc2017 chokes on having the if constexpr here directly, so use helper
125 return VoidResultHelper<ReturnType>();
126 }),
127 queue));
128 }
129
130 Type GetResult() const
131 {
132 if (fut_) {
133 return fut_->GetResultOr<Type>(Type {});
134 }
135 return Type {};
136 }
137 IFuture::Ptr GetFuture() const
138 {
139 return fut_;
140 }
141
142 operator IFuture::Ptr() const
143 {
144 return fut_;
145 }
146
147 explicit operator bool() const
148 {
149 return fut_ != nullptr;
150 }
151
152 private:
153 IFuture::Ptr fut_;
154 };
155
156 template<typename Type>
157 Type GetResultOr(const Future<Type>& f, NonDeduced_t<Type> def)
158 {
159 auto fut = f.GetFuture();
160 if (fut) {
161 if (auto p = fut->GetResult()) {
162 return GetValue<Type>(*p, BASE_NS::move(def));
163 }
164 }
165 return BASE_NS::move(def);
166 }
167
168 META_END_NAMESPACE()
169
170 #endif
171