• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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