Molybden API
Loading...
Searching...
No Matches
js_proxy_object_detail.hpp
1// Copyright (c) 2000-2024 TeamDev. All rights reserved.
2// TeamDev PROPRIETARY and CONFIDENTIAL.
3// Use is subject to license terms.
4
5#ifndef MOLYBDEN_JS_PROXY_OBJECT_DETAIL_HPP
6#define MOLYBDEN_JS_PROXY_OBJECT_DETAIL_HPP
7
8#include "molybden/js/js_proxy_object.hpp"
9
10#include <memory>
11#include <type_traits>
12
13#include "molybden/base/rtti.hpp"
14
15namespace molybden {
16namespace internal {
17
25template <class>
26struct sfinae_true : std::true_type {};
27
32template <class C, class T>
33class CustomDowncastDefined {
34 // This overloaded method will only compile if the downcast method exists.
35 template <typename U>
36 static sfinae_true<decltype(U::downcast(std::shared_ptr<C>{}))> test(int);
37
38 // This overloaded method has lower priority because `0` is best-matched as
39 // `int` and that's why it is compiled only if the first alternative won't.
40 template <typename U>
41 static std::false_type test(long);
42
43 // The compile-time bool parameter is required to allow conditional
44 // compilation of this method. If compiled when the downcast method does not
45 // exist, compilation of the type trait would cause error instead of having
46 // the value equal to `false`.
47 static constexpr bool isReturnTypeCorrect(std::true_type type) {
48 using bool_type = std::integral_constant<
49 bool,
50 std::is_same<std::shared_ptr<T>,
51 decltype(T::downcast(std::shared_ptr<C>{}))>::value>;
52 static_assert(bool_type::value,
53 "The return value of the downcast method of the class T must "
54 "be of type std::shared_ptr<T>");
55 return bool_type::value;
56 }
57
58 static constexpr bool isReturnTypeCorrect(std::false_type) { return false; }
59
60 public:
64 static constexpr bool value() {
65 using bool_type = decltype(test<T>(0));
66
67 return bool_type::value && isReturnTypeCorrect(bool_type());
68 }
69
74 using BoolType = std::integral_constant<bool, value()>;
75};
76
84template <class C, bool rtti = RTTI::Enabled()>
85class ProxyDowncaster;
86
87template <class C>
88class ProxyDowncaster<C, true> {
89 template <class T>
90 static std::shared_ptr<T> downcastImpl(std::shared_ptr<C> object,
91 std::false_type) {
92 return std::dynamic_pointer_cast<T>(std::move(object));
93 }
94
95 template <class T>
96 static std::shared_ptr<T> downcastImpl(std::shared_ptr<C> object,
97 std::true_type) {
98 return T::downcast(std::move(object));
99 }
100
101 public:
102 template <class T>
103 static std::shared_ptr<T> downcast(std::shared_ptr<C> object) {
104 auto return_value = downcastImpl<T>(
105 object,
106 typename CustomDowncastDefined<C, T>::BoolType());
107 assert(!return_value || return_value == object);
108 return return_value;
109 }
110
111 static std::shared_ptr<C> downcast(std::shared_ptr<C> object) {
112 return object;
113 }
114};
115
116template <class C>
117class ProxyDowncaster<C, false> {
118 public:
119 template <class T>
120 static std::shared_ptr<T> downcast(std::shared_ptr<C> object) {
121 static_assert(
122 CustomDowncastDefined<C, T>::value(),
123 "RTTI is disabled. Cast from proxy object base class must be\n"
124 "explicitly defined as the static function in the class to downcast "
125 "to.\n"
126 "In terms of C and T:\n"
127 "class T {\n"
128 " ...\n"
129 " static std::shared_ptr<T> downcast(std::shared_ptr<T>);\n"
130 " ...\n"
131 "};");
132 return T::downcast(object);
133 }
134};
135
140class ProxyObjectType {};
141
142template <class T>
143class ProxyObjectTypeImpl : public ProxyObjectType {
144 public:
145 static ProxyObjectTypeImpl* instance() {
146 static ProxyObjectTypeImpl impl;
147 return &impl;
148 }
149};
150
155template <class T>
156class JsProxyObjectRoot {
157 template <class C>
158 static constexpr C* pass(JsProxyObjectImpl<C>*) {
159 return nullptr;
160 }
161
162 static constexpr void* pass(void*) { return nullptr; }
163
164 public:
165 using Type =
166 typename std::remove_pointer<decltype(pass(&std::declval<T&>()))>::type;
167 static constexpr bool Exists = !std::is_same<Type, void>::value;
168};
169
170} // namespace internal
171
172template <class T>
173std::shared_ptr<T> JsProxyObject::as() {
174 static_assert(internal::JsProxyObjectRoot<T>::Exists,
175 "The object is not a custom proxy object.");
176 using RootProxyType = typename internal::JsProxyObjectRoot<T>::Type;
177 if (proxyType() == internal::ProxyObjectTypeImpl<RootProxyType>::instance()) {
178 return internal::ProxyDowncaster<RootProxyType>::template downcast<T>(
179 std::static_pointer_cast<RootProxyType>(shared_from_this()));
180 }
181 return nullptr;
182}
183
184template <>
185std::shared_ptr<JsProxyObject> JsProxyObject::as();
186
187template <class C>
188internal::ProxyObjectType* JsProxyObjectImpl<C>::proxyType() {
189 return internal::ProxyObjectTypeImpl<C>::instance();
190}
191
192} // namespace molybden
193
194#endif // MOLYBDEN_JS_PROXY_OBJECT_DETAIL_HPP
std::shared_ptr< T > as()
Downcasts the object to the appropriate proxy type.
Definition js_proxy_object_detail.hpp:173
Derive C from JsProxyObjectImpl<C> via CRTP pattern and implement the interface of JsProxyObject.
Definition js_proxy_object.hpp:171