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