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_INTERFACE_OBJECT_H
17 #define META_API_INTERFACE_OBJECT_H
18
19 #include <base/containers/shared_ptr.h>
20 #include <core/plugin/intf_interface.h>
21
22 #include <meta/base/interface_macros.h>
23 #include <meta/base/interface_traits.h>
24 #include <meta/base/namespace.h>
25
META_BEGIN_NAMESPACE()26 META_BEGIN_NAMESPACE()
27
28 /**
29 * @brief Common base class for all InterfaceObjects.
30 */
31 class InterfaceObjectBase {
32 public:
33 InterfaceObjectBase() = default;
34 virtual ~InterfaceObjectBase() = default;
35 META_DEFAULT_COPY_MOVE(InterfaceObjectBase)
36 /// Returns true if InterfaceObject contains a valid shared_ptr<T>, false otherwise.
37 explicit operator bool() const noexcept
38 {
39 return GetInterfacePtr() != nullptr;
40 }
41 /// Returns true if underlying pointers are the same, false otherwise.
42 bool operator==(const InterfaceObjectBase& other) const noexcept
43 {
44 return GetInterfacePtr() == other.GetInterfacePtr();
45 }
46 /// Returns true if underlying pointers are different, false otherwise.
47 bool operator!=(const InterfaceObjectBase& other) const noexcept
48 {
49 return GetInterfacePtr() != other.GetInterfacePtr();
50 }
51 /// @see CORE_NS::IInterface::GetInterface
52 const CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) const
53 {
54 const auto p = GetInterfacePtr();
55 return p ? p->GetInterface(uid) : nullptr;
56 }
57 /// @see CORE_NS::IInterface::GetInterface
58 CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid)
59 {
60 const auto p = GetInterfacePtr();
61 return p ? p->GetInterface(uid) : nullptr;
62 }
63
64 protected:
65 virtual CORE_NS::IInterface* GetInterfacePtr() const noexcept = 0;
66 };
67
68 namespace Internal {
69 /**
70 * @brief Converts vector types
71 * @param from The vector to convert from
72 * @return Returns a vector of InterfaceObjects initialized with elements from source array.
73 */
74 template<class To, class From>
ArrayCast(BASE_NS::vector<From> && from)75 constexpr auto ArrayCast(BASE_NS::vector<From>&& from) noexcept
76 {
77 if constexpr (BASE_NS::is_same_v<To, From>) {
78 return BASE_NS::move(from);
79 } else {
80 BASE_NS::vector<To> converted;
81 if (!from.empty()) {
82 converted.reserve(from.size());
83 for (auto&& n : from) {
84 converted.emplace_back(n);
85 }
86 }
87 return converted;
88 }
89 }
90
91 } // namespace Internal
92
93 /**
94 * @brief The InterfaceObject class is the base BASE_NS::shared_ptr<T> wrapper inherited by actual interface wrapper
95 * objects.
96 */
97 template<typename T>
98 class InterfaceObject : public InterfaceObjectBase {
99 static_assert(
100 BASE_NS::is_base_of<CORE_NS::IInterface, T>(), "InterfaceObject type must be derived from CORE_NS::IInterface");
101
102 public:
103 using UnderlyingType = T;
104 using Ptr = BASE_NS::shared_ptr<UnderlyingType>;
105 using WeakPtr = BASE_NS::weak_ptr<UnderlyingType>;
106 using IInterfacePtr = BASE_NS::shared_ptr<CORE_NS::IInterface>;
107 InterfaceObject() = delete;
InterfaceObject(const Ptr & p)108 explicit InterfaceObject(const Ptr& p) noexcept : ptr_(p) {}
InterfaceObject(const IInterfacePtr & p)109 explicit InterfaceObject(const IInterfacePtr& p) : ptr_(interface_pointer_cast<UnderlyingType>(p)) {}
110 /// Assignment operator
111 auto& operator=(const IInterfacePtr& p) noexcept
112 {
113 ptr_ = interface_pointer_cast<UnderlyingType>(p);
114 return *this;
115 }
116 /// InterfaceObject<T> to BASE_NS::shared_ptr<T> operator
Ptr()117 operator Ptr() const noexcept
118 {
119 return ptr_;
120 }
121 /// InterfaceObject<T> to BASE_NS::shared_ptr<CORE_NS::IInterface> operator
IInterfacePtr()122 operator IInterfacePtr() const noexcept
123 {
124 return ptr_;
125 }
126 /// Return the underlying BASE_NS::shared_ptr<T>
GetPtr()127 Ptr GetPtr() const noexcept
128 {
129 return ptr_;
130 }
131 /// Return the underlying BASE_NS::shared_ptr<T> converted to BASE_NS::shared_ptr<Interface>
132 template<typename Interface>
GetPtr()133 BASE_NS::shared_ptr<Interface> GetPtr() const
134 {
135 return interface_pointer_cast<Interface>(ptr_);
136 }
137 /// Release the underlying object.
Release()138 void Release()
139 {
140 ptr_.reset();
141 }
142
143 protected:
144 /// Helper method for safely calling a method from the underlying interface
145 template<typename Interface, typename Fn>
CallPtr(Fn && fn)146 auto CallPtr(Fn&& fn) const
147 {
148 auto* p = interface_cast<Interface>(ptr_);
149 using Result = BASE_NS::remove_reference_t<decltype(fn(*p))>;
150 if constexpr (!BASE_NS::is_void_v<Result>) {
151 return p ? fn(*p) : Result {};
152 } else if (p) {
153 fn(*p);
154 }
155 }
156
GetInterfacePtr()157 CORE_NS::IInterface* GetInterfacePtr() const noexcept override
158 {
159 return ptr_.get();
160 }
161 Ptr ptr_;
162 };
163
164 // InterfaceObject definition
165 #define META_INTERFACE_OBJECT(Class, BaseClass, Interface) \
166 using ClassType = Class; \
167 using BaseClassType = BaseClass; \
168 using InterfaceType = Interface; \
169 Class() = delete; \
170 ~Class() override = default; \
171 explicit Class(const IInterfacePtr& p) : BaseClass(interface_pointer_cast<Interface>(p)) \
172 {} \
173 META_DEFAULT_COPY_MOVE(Class) \
174 operator InterfaceType::Ptr() const noexcept \
175 { \
176 return GetPtr<InterfaceType>(); \
177 } \
178 auto& operator=(const InterfaceType::Ptr& p) noexcept \
179 { \
180 ptr_ = interface_pointer_cast<UnderlyingType>(p); \
181 return *this; \
182 }
183
184 // InterfaceObject default interface function call wrapper
185 #define META_INTERFACE_OBJECT_CALL_PTR(Function) CallPtr<InterfaceType>([&](auto& p) { return p.Function; })
186
187 #define META_INTERFACE_OBJECT_PROPERTY_ACCESSOR(PropertyName) \
188 public: \
189 auto PropertyName() const \
190 { \
191 return META_INTERFACE_OBJECT_CALL_PTR(PropertyName()); \
192 }
193
194 // InterfaceObject default readonly property wrapper
195 #define META_INTERFACE_OBJECT_READONLY_PROPERTY(Type, PropertyName) \
196 META_INTERFACE_OBJECT_PROPERTY_ACCESSOR(PropertyName) \
197 auto Get##PropertyName() const \
198 { \
199 return Type(META_NS::GetValue(PropertyName())); \
200 }
201
202 // InterfaceObject default property wrapper
203 #define META_INTERFACE_OBJECT_PROPERTY(Type, PropertyName) \
204 META_INTERFACE_OBJECT_READONLY_PROPERTY(Type, PropertyName) \
205 auto& Set##PropertyName(const Type& value) \
206 { \
207 if (auto pr = PropertyName()) { \
208 pr->SetValue(value); \
209 } \
210 return *this; \
211 }
212
213 // InterfaceObject default readonly array property wrapper
214 #define META_INTERFACE_OBJECT_READONLY_ARRAY_PROPERTY(Type, PropertyName, AccessorName) \
215 META_INTERFACE_OBJECT_PROPERTY_ACCESSOR(PropertyName) \
216 auto Get##PropertyName() const \
217 { \
218 auto pr = PropertyName(); \
219 using ReturnType = decltype(pr->GetValue()); \
220 auto value = pr ? pr->GetValue() : ReturnType {}; \
221 return META_NS::Internal::ArrayCast<Type, typename ReturnType::value_type>(BASE_NS::move(value)); \
222 } \
223 auto Get##AccessorName##Count() const \
224 { \
225 auto pr = PropertyName(); \
226 return pr ? pr->GetSize() : 0; \
227 } \
228 auto Get##AccessorName##At(size_t index) const \
229 { \
230 auto pr = PropertyName(); \
231 return Type(pr ? pr->GetValueAt(index) : decltype(pr->GetValueAt(index)) {}); \
232 }
233
234 // InterfaceObject default array property wrapper
235 #define META_INTERFACE_OBJECT_ARRAY_PROPERTY(Type, PropertyName, AccessorName) \
236 META_INTERFACE_OBJECT_READONLY_ARRAY_PROPERTY(Type, PropertyName, AccessorName) \
237 auto& Set##PropertyName(BASE_NS::array_view<const Type> value) \
238 { \
239 if (auto pr = PropertyName()) { \
240 pr->SetValue(value); \
241 } \
242 return *this; \
243 } \
244 auto& Set##AccessorName##At(size_t index, const Type& value) \
245 { \
246 if (auto pr = PropertyName()) { \
247 pr->SetValueAt(index, value); \
248 } \
249 return *this; \
250 }
251
252 struct InitializationType {};
253
254 /**
255 * @brief Some interface wrappers support creating an instance at wrapper object initialization.
256 * Such classes can be made to automatically initialize the underlying object to a new class
257 * instance defining Instanate
258 * @code
259 * using namespace META_NS;
260 * Object o(CreateNew); // Create a new instance of the underlying object suitable for this class.
261 * @endcode
262 */
263 constexpr InitializationType CreateNew;
264
265 #define META_INTERFACE_OBJECT_INSTANTIATE(Class, ClassId) \
266 Class(const META_NS::InitializationType& t) : BaseClassType(::META_NS::CreateObjectInstance(ClassId)) \
267 {}
268
269 /// Some methods support specifying whether the call should be asynchronous or synchronous through AsyncCallType
270 /// template parameter.
271 struct AsyncCallType {
272 bool async {};
273 };
274 /// Call should be synchronous and directly return the asynchronous call return value.
275 constexpr AsyncCallType Sync { false };
276 /// Call should be asynchronous and return a Future object as its return value.
277 constexpr AsyncCallType Async { true };
278
279 #define META_API_ASYNC template<const META_NS::AsyncCallType& CallType = META_NS::Sync>
280
281 #define META_INTERFACE_OBJECT_ASYNC_CALL_PTR(SyncReturnType, Function) \
282 [&]() -> auto \
283 { \
284 auto f = META_INTERFACE_OBJECT_CALL_PTR(Function); \
285 if constexpr (CallType.async) { \
286 return f; \
287 } else { \
288 return SyncReturnType(f.GetResult()); \
289 } \
290 } \
291 ()
292
META_END_NAMESPACE()293 META_END_NAMESPACE()
294
295 // NOLINTBEGIN(readability-identifier-naming) to keep std like syntax
296
297 template<typename T, typename S>
298 BASE_NS::shared_ptr<T> interface_pointer_cast(const META_NS::InterfaceObject<S>& io)
299 {
300 static_assert(META_NS::HasGetInterfaceMethod_v<T>, "T::GetInterface not defined");
301 return interface_pointer_cast<T>(io.GetPtr());
302 }
303
304 template<typename T, typename S>
interface_cast(const META_NS::InterfaceObject<S> & io)305 T* interface_cast(const META_NS::InterfaceObject<S>& io)
306 {
307 static_assert(META_NS::HasGetInterfaceMethod_v<T>, "T::GetInterface not defined");
308 return interface_cast<T>(io.GetPtr());
309 }
310
311 // NOLINTEND(readability-identifier-naming) to keep std like syntax
312
313 #endif // META_API_INTERFACE_OBJECT_H
314