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