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 #ifndef META_API_CALL_CONTEXT_H
16 #define META_API_CALL_CONTEXT_H
17
18 #include <meta/base/expected.h>
19 #include <meta/interface/detail/any.h>
20 #include <meta/interface/intf_call_context.h>
21 #include <meta/interface/intf_object_registry.h>
22
META_BEGIN_NAMESPACE()23 META_BEGIN_NAMESPACE()
24
25 /**
26 * @brief Set argument value for parameter
27 * @param context Call context where the argument is set
28 * @param name Name of the defined parameter
29 * @param value to set, type must match with the defined parameter type.
30 * @return True on success.
31 */
32 template<typename Type>
33 bool Set(const ICallContext::Ptr& context, BASE_NS::string_view name, const Type& value)
34 {
35 return context->Set(name, Any<Type>(value));
36 }
37
38 /**
39 * @brief Set result value
40 * @param context Call context where the result is set
41 * @param value to set, type must match with the defined result type.
42 */
43 template<typename Type>
SetResult(const ICallContext::Ptr & context,const Type & value)44 bool SetResult(const ICallContext::Ptr& context, const Type& value)
45 {
46 return context->SetResult(Any<Type>(value));
47 }
48
49 /**
50 * @brief Set void result value
51 * @param context Call context where the result is set
52 */
53 template<typename Type = void, typename = BASE_NS::enable_if_t<BASE_NS::is_same_v<Type, void>>>
SetResult(const ICallContext::Ptr & context)54 bool SetResult(const ICallContext::Ptr& context)
55 {
56 return context->SetResult();
57 }
58
59 /**
60 * @brief Get argument value if set, otherwise parameter default value.
61 * @param context Call context to get from.
62 * @param Name of the defined parameter, the type must match.
63 * @return Pointer to contained value if successful, otherwise null.
64 */
65 template<typename Type>
Get(const ICallContext::Ptr & context,BASE_NS::string_view name)66 Expected<Type, GenericError> Get(const ICallContext::Ptr& context, BASE_NS::string_view name)
67 {
68 if (auto any = context->Get(name)) {
69 Type t;
70 if (any->GetValue(t)) {
71 return t;
72 }
73 }
74 return GenericError::FAIL;
75 }
76
77 /**
78 * @brief Get result value/type
79 * @param context Call context to get from.
80 * @return Pointer to contained result if type matches, otherwise null.
81 * Note: One should first use ICallContext Success function to see if the call was
82 * successful before querying for value.
83 */
84 template<typename Type>
GetResult(const ICallContext::Ptr & context)85 Expected<Type, GenericError> GetResult(const ICallContext::Ptr& context)
86 {
87 if (auto any = context->GetResult()) {
88 Type t;
89 if (any->GetValue(t)) {
90 return t;
91 }
92 }
93 return GenericError::FAIL;
94 }
95
96 /**
97 * @brief Define parameter name, type and default value in call context
98 * @param context Call context to define parameter.
99 * @param name Name of the parameter.
100 * @param value Type and default value of the parameter.
101 */
102 template<typename Type>
103 bool DefineParameter(const ICallContext::Ptr& context, BASE_NS::string_view name, const Type& value = {})
104 {
105 return context->DefineParameter(name, IAny::Ptr(new Any<Type>(value)));
106 }
107
108 /**
109 * @brief Define result type in call context
110 * @param context Call context for define result type
111 * @value Type of the result, the value is ignored if SetResult is used.
112 */
113 template<typename Type>
DefineResult(const ICallContext::Ptr & context,const Type & value)114 bool DefineResult(const ICallContext::Ptr& context, const Type& value)
115 {
116 return context->DefineResult(IAny::Ptr(new Any<Type>(value)));
117 }
118
119 /**
120 * @brief Define result type in call context
121 */
122 template<typename Type>
DefineResult(const ICallContext::Ptr & context)123 bool DefineResult(const ICallContext::Ptr& context)
124 {
125 if constexpr (BASE_NS::is_same_v<Type, void>) {
126 return context->DefineResult(nullptr);
127 }
128 if constexpr (!BASE_NS::is_same_v<Type, void>) {
129 return DefineResult(context, Type {});
130 }
131 }
132
133 /**
134 * @brief Set values for call context, used for setting parameters for meta function calls.
135 */
136 template<typename... Args, size_t... Index>
SetContextValues(const ICallContext::Ptr & context,IndexSequence<Index...>,const BASE_NS::array_view<BASE_NS::string_view> & names)137 bool SetContextValues(
138 const ICallContext::Ptr& context, IndexSequence<Index...>, const BASE_NS::array_view<BASE_NS::string_view>& names)
139 {
140 return (true && ... && DefineParameter<Args>(context, names[Index]));
141 }
142
143 /**
144 * @brief Create call context for meta function calls with parameter names.
145 * @param Ret Return type of the meta function.
146 * @param Args Types of the meta function parameters.
147 * @param names Names of the meta function parameters.
148 */
149 template<typename Ret, typename... Args>
CreateCallContextImpl(const BASE_NS::array_view<BASE_NS::string_view> & names)150 ICallContext::Ptr CreateCallContextImpl(const BASE_NS::array_view<BASE_NS::string_view>& names)
151 {
152 if (sizeof...(Args) != names.size()) {
153 CORE_LOG_E("Invalid amount of parameter names");
154 return nullptr;
155 }
156 auto context = GetObjectRegistry().ConstructDefaultCallContext();
157 if (!SetContextValues<PlainType_t<Args>...>(context, MakeIndexSequenceFor<Args...>(), names)) {
158 CORE_LOG_E("Failed setting parameters");
159 return nullptr;
160 }
161 if (!DefineResult<PlainType_t<Ret>>(context)) {
162 CORE_LOG_E("Failed setting return type");
163 return nullptr;
164 }
165 return context;
166 }
167
168 /**
169 * @brief Create call context for meta function calls by deducing types from member function.
170 */
171 template<typename Obj, typename Ret, typename... Args>
CreateCallContext(Ret (Obj::*)(Args...),const BASE_NS::array_view<BASE_NS::string_view> & names)172 ICallContext::Ptr CreateCallContext(Ret (Obj::*)(Args...), const BASE_NS::array_view<BASE_NS::string_view>& names)
173 {
174 return CreateCallContextImpl<Ret, Args...>(names);
175 }
176
177 /**
178 * @brief Create call context for meta function calls by deducing types from member function.
179 */
180 template<typename Obj, typename Ret, typename... Args>
CreateCallContext(Ret (Obj::*)(Args...)const,const BASE_NS::array_view<BASE_NS::string_view> & names)181 ICallContext::Ptr CreateCallContext(Ret (Obj::*)(Args...) const, const BASE_NS::array_view<BASE_NS::string_view>& names)
182 {
183 return CreateCallContextImpl<Ret, Args...>(names);
184 }
185
186 // convert array of string views to array view and ignore the first one (workaround for empty arrays)
187 template<size_t S>
ParamNameToView(BASE_NS::string_view (& arr)[S])188 BASE_NS::array_view<BASE_NS::string_view> ParamNameToView(BASE_NS::string_view (&arr)[S])
189 {
190 return BASE_NS::array_view<BASE_NS::string_view>(arr + 1, arr + S);
191 }
192
193 template<typename T, bool Ref = BASE_NS::is_same_v<T, PlainType_t<T>&>>
194 struct CallArg {
195 using Type = PlainType_t<T>;
CallArgCallArg196 explicit CallArg(IAny::Ptr any) : any_(any) {}
197
198 /* NOLINTNEXTLINE(google-explicit-constructor) */
TypeCallArg199 operator Type() const
200 {
201 Type t;
202 any_->GetValue(t);
203 return t;
204 }
205
206 private:
207 IAny::Ptr any_;
208 };
209
210 template<typename T>
211 struct CallArg<T, true> {
212 using Type = PlainType_t<T>;
213 explicit CallArg(IAny::Ptr any) : any_(any)
214 {
215 any_->GetValue(t_);
216 }
217 ~CallArg()
218 {
219 any_->SetValue(t_);
220 }
221 META_DEFAULT_COPY_MOVE(CallArg)
222
223 /* NOLINTNEXTLINE(google-explicit-constructor) */
224 operator Type&() const
225 {
226 return t_;
227 }
228
229 private:
230 IAny::Ptr any_;
231 mutable Type t_;
232 };
233
234 template<typename Ret, typename... Args>
235 struct CallFunctionImpl {
236 template<typename Func, size_t... Index>
237 static bool Call(
238 const ICallContext::Ptr& context, Func func, BASE_NS::array_view<IAny::Ptr> argView, IndexSequence<Index...>)
239 {
240 if (!(true && ... && IsGetCompatibleWith<Args>(*argView[Index]))) {
241 context->ReportError("invalid argument type for function call");
242 return false;
243 }
244 return [&](const auto&... args) {
245 if constexpr (BASE_NS::is_same_v<Ret, void>) {
246 func(args...);
247 SetResult(context);
248 return true;
249 } else {
250 auto ret = func(args...);
251 return SetResult(context, ret);
252 }
253 }(CallArg<Args>(argView[Index])...);
254 }
255
256 template<typename Func, size_t... Index>
257 static bool Call(const ICallContext::Ptr& context, Func func, IndexSequence<Index...> ind)
258 {
259 auto params = context->GetParameters();
260 if (params.size() != sizeof...(Args)) {
261 context->ReportError("invalid function call");
262 return false;
263 }
264 if constexpr (sizeof...(Args) != 0) {
265 IAny::Ptr args[] = { params[Index].value... };
266 return Call(context, func, args, ind);
267 } else {
268 return Call(context, func, BASE_NS::array_view<IAny::Ptr> {}, ind);
269 }
270 }
271
272 template<typename Func, size_t... Index>
273 static bool Call(const ICallContext::Ptr& context, Func func,
274 const BASE_NS::array_view<BASE_NS::string_view>& names, IndexSequence<Index...> ind)
275 {
276 auto params = context->GetParameters();
277 if (params.size() != sizeof...(Args)) {
278 context->ReportError("invalid function call");
279 return false;
280 }
281 if constexpr (sizeof...(Args) != 0) {
282 IAny::Ptr args[] = { context->Get(names[Index])... };
283 return Call(context, func, args, ind);
284 } else {
285 return Call(context, func, BASE_NS::array_view<IAny::Ptr> {}, ind);
286 }
287 }
288 };
289
290 /**
291 * @brief Call meta function, giving the arguments in the order they are in the context.
292 * @param context Call context for meta function (i.e. arguments and return type information).
293 * @param obj Target object to call function for.
294 * @param func Member function to call.
295 */
296 template<typename Obj, typename Ret, typename... Args>
297 bool CallFunction(const ICallContext::Ptr& context, Obj* obj, Ret (Obj::*func)(Args...))
298 {
299 return CallFunctionImpl<Ret, Args...>::Call(
300 context, [&](Args... args) { return (obj->*func)(args...); }, MakeIndexSequenceFor<Args...>());
301 }
302 template<typename Obj, typename Ret, typename... Args>
303 bool CallFunction(const ICallContext::Ptr& context, const Obj* obj, Ret (Obj::*func)(Args...) const)
304 {
305 return CallFunctionImpl<Ret, Args...>::Call(
306 context, [&](Args... args) { return (obj->*func)(args...); }, MakeIndexSequenceFor<Args...>());
307 }
308 template<typename Func>
309 bool CallFunction(const ICallContext::Ptr& context, Func func)
310 {
311 return CallFunction(context, &func, &Func::operator());
312 }
313
314 /**
315 * @brief Call meta function, giving the arguments in the order of the given parameter names.
316 * @param context Call context for meta function (i.e. arguments and return type information).
317 * @param obj Target object to call function for.
318 * @param func Member function to call.
319 */
320 template<typename Obj, typename Ret, typename... Args>
321 bool CallFunction(const ICallContext::Ptr& context, Obj* obj, Ret (Obj::*func)(Args...),
322 const BASE_NS::array_view<BASE_NS::string_view>& names)
323 {
324 return CallFunctionImpl<Ret, Args...>::Call(
325 context, [&](Args... args) { return (obj->*func)(args...); }, names, MakeIndexSequenceFor<Args...>());
326 }
327 template<typename Obj, typename Ret, typename... Args>
328 bool CallFunction(const ICallContext::Ptr& context, const Obj* obj, Ret (Obj::*func)(Args...) const,
329 const BASE_NS::array_view<BASE_NS::string_view>& names)
330 {
331 return CallFunctionImpl<Ret, Args...>::Call(
332 context, [&](Args... args) { return (obj->*func)(args...); }, names, MakeIndexSequenceFor<Args...>());
333 }
334
335 META_END_NAMESPACE()
336
337 #endif
338