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
TypeCallArg198 operator Type() const
199 {
200 Type t;
201 any_->GetValue(t);
202 return t;
203 }
204
205 private:
206 IAny::Ptr any_;
207 };
208
209 template<typename T>
210 struct CallArg<T, true> {
211 using Type = PlainType_t<T>;
212 explicit CallArg(IAny::Ptr any) : any_(any)
213 {
214 any_->GetValue(t_);
215 }
216 ~CallArg()
217 {
218 any_->SetValue(t_);
219 }
220 META_DEFAULT_COPY_MOVE(CallArg)
221
222 operator Type&() const
223 {
224 return t_;
225 }
226
227 private:
228 IAny::Ptr any_;
229 mutable Type t_;
230 };
231
232 template<typename Ret, typename... Args>
233 struct CallFunctionImpl {
234 template<typename Func, size_t... Index>
235 static bool Call(
236 const ICallContext::Ptr& context, Func func, BASE_NS::array_view<IAny::Ptr> argView, IndexSequence<Index...>)
237 {
238 if (!(true && ... && IsGetCompatibleWith<Args>(*argView[Index]))) {
239 context->ReportError("invalid argument type for function call");
240 return false;
241 }
242 return [&](const auto&... args) {
243 if constexpr (BASE_NS::is_same_v<Ret, void>) {
244 func(args...);
245 SetResult(context);
246 return true;
247 } else {
248 auto ret = func(args...);
249 return SetResult(context, ret);
250 }
251 }(CallArg<Args>(argView[Index])...);
252 }
253
254 template<typename Func, size_t... Index>
255 static bool Call(const ICallContext::Ptr& context, Func func, IndexSequence<Index...> ind)
256 {
257 auto params = context->GetParameters();
258 if (params.size() != sizeof...(Args)) {
259 context->ReportError("invalid function call");
260 return false;
261 }
262 if constexpr (sizeof...(Args) != 0) {
263 IAny::Ptr args[] = { params[Index].value... };
264 return Call(context, func, args, ind);
265 } else {
266 return Call(context, func, BASE_NS::array_view<IAny::Ptr> {}, ind);
267 }
268 }
269
270 template<typename Func, size_t... Index>
271 static bool Call(const ICallContext::Ptr& context, Func func,
272 const BASE_NS::array_view<BASE_NS::string_view>& names, IndexSequence<Index...> ind)
273 {
274 auto params = context->GetParameters();
275 if (params.size() != sizeof...(Args)) {
276 context->ReportError("invalid function call");
277 return false;
278 }
279 if constexpr (sizeof...(Args) != 0) {
280 IAny::Ptr args[] = { context->Get(names[Index])... };
281 return Call(context, func, args, ind);
282 } else {
283 return Call(context, func, BASE_NS::array_view<IAny::Ptr> {}, ind);
284 }
285 }
286 };
287
288 /**
289 * @brief Call meta function, giving the arguments in the order they are in the context.
290 * @param context Call context for meta function (i.e. arguments and return type information).
291 * @param obj Target object to call function for.
292 * @param func Member function to call.
293 */
294 template<typename Obj, typename Ret, typename... Args>
295 bool CallFunction(const ICallContext::Ptr& context, Obj* obj, Ret (Obj::*func)(Args...))
296 {
297 return CallFunctionImpl<Ret, Args...>::Call(
298 context, [&](Args... args) { return (obj->*func)(args...); }, MakeIndexSequenceFor<Args...>());
299 }
300 template<typename Obj, typename Ret, typename... Args>
301 bool CallFunction(const ICallContext::Ptr& context, const Obj* obj, Ret (Obj::*func)(Args...) const)
302 {
303 return CallFunctionImpl<Ret, Args...>::Call(
304 context, [&](Args... args) { return (obj->*func)(args...); }, MakeIndexSequenceFor<Args...>());
305 }
306 template<typename Func>
307 bool CallFunction(const ICallContext::Ptr& context, Func func)
308 {
309 return CallFunction(context, &func, &Func::operator());
310 }
311
312 /**
313 * @brief Call meta function, giving the arguments in the order of the given parameter names.
314 * @param context Call context for meta function (i.e. arguments and return type information).
315 * @param obj Target object to call function for.
316 * @param func Member function to call.
317 */
318 template<typename Obj, typename Ret, typename... Args>
319 bool CallFunction(const ICallContext::Ptr& context, Obj* obj, Ret (Obj::*func)(Args...),
320 const BASE_NS::array_view<BASE_NS::string_view>& names)
321 {
322 return CallFunctionImpl<Ret, Args...>::Call(
323 context, [&](Args... args) { return (obj->*func)(args...); }, names, MakeIndexSequenceFor<Args...>());
324 }
325 template<typename Obj, typename Ret, typename... Args>
326 bool CallFunction(const ICallContext::Ptr& context, const Obj* obj, Ret (Obj::*func)(Args...) const,
327 const BASE_NS::array_view<BASE_NS::string_view>& names)
328 {
329 return CallFunctionImpl<Ret, Args...>::Call(
330 context, [&](Args... args) { return (obj->*func)(args...); }, names, MakeIndexSequenceFor<Args...>());
331 }
332
333 META_END_NAMESPACE()
334
335 #endif
336