-
Notifications
You must be signed in to change notification settings - Fork 22
/
HybridObject.hpp
142 lines (128 loc) · 4.31 KB
/
HybridObject.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//
// Created by Marc Rousavy on 21.02.24.
//
#pragma once
#include "HybridObjectPrototype.hpp"
#include <jsi/jsi.h>
#include <memory>
#include <type_traits>
namespace margelo::nitro {
using namespace facebook;
/**
* Represents a C++ object that is exposed to JS.
* `HybridObject`s can have native getters and setters, and normal methods.
*
* To implement a `HybridObject`, simply inherit from this class and override `loadHybridMethods`
* to register the given getters, setters or methods.
*
* The new class can then be passed to JS using the `JSIConverter<HybridObject>`.
*/
class HybridObject : public virtual jsi::NativeState, public HybridObjectPrototype, public std::enable_shared_from_this<HybridObject> {
public:
/**
* Create a new instance of a `HybridObject`.
* The given `name` will be used for logging and stringifying.
*/
explicit HybridObject(const char* name);
/**
* Called when no more references to the given `HybridObject` exist in both C++ and JS.
* JS might keep references for longer, as it is a garbage collected language.
*/
virtual ~HybridObject();
/**
* HybridObjects cannot be copied.
*/
HybridObject(const HybridObject& copy) = default;
/**
* HybridObjects cannot be moved.
*/
HybridObject(HybridObject&& move) = default;
/**
* HybridObjects cannot be default-constructed!
*/
HybridObject() {
throw std::runtime_error("Cannot default-construct HybridObject!");
}
public:
/**
* Return the `jsi::Object` that holds this `HybridObject`. (boxed in a `jsi::Value`)
* This properly assigns (or creates) the base prototype for this type,
* and assigns it's NativeState.
* Additionally, this sets the external memory pressure for proper GC memory management.
*/
jsi::Value toObject(jsi::Runtime& runtime);
public:
/**
* Get the `std::shared_ptr` instance of this HybridObject.
* The HybridObject must be managed inside a `shared_ptr` already, otherwise this will fail.
*/
template <typename Derived>
std::shared_ptr<Derived> shared() {
return std::dynamic_pointer_cast<Derived>(shared_from_this());
}
public:
/**
* Get the HybridObject's name
*/
std::string getName();
/**
* Compare this HybridObject for reference equality to the other HybridObject.
*
* While two `jsi::Object`s of the same `HybridObject` might not be equal when compared with `==`,
* they might still be the same `HybridObject` - in this case `equals(other)` will return true.
*/
bool equals(std::shared_ptr<HybridObject> other);
/**
* Get a string representation of this `HybridObject` - useful for logging or debugging.
*/
virtual std::string toString();
/**
* Eagerly- (and manually-) dispose all native resources this `HybridObject` holds.
* This method can only be manually called from JS using `dispose()`.
*
* If this method is never manually called, a `HybridObject` is expected to disposes it's
* resources as usual via the object's destructor (`~HybridObject()`, `deinit` or `finalize()`).
*
* By default, this method does nothing. It can be overridden to perform actual disposing/cleanup
* if required.
*/
virtual void dispose() {}
private:
/**
* The actual `dispose()` function from JS.
* This needs to be a raw JSI function as we remove the NativeState here.
*/
jsi::Value disposeRaw(jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count);
protected:
/**
* Get the size of any external (heap) allocations this `HybridObject` has made, in bytes.
* This will be used to notify the JS GC about memory pressure.
*/
virtual inline size_t getExternalMemorySize() noexcept {
return 0;
}
protected:
/**
* Loads all native methods of this `HybridObject` to be exposed to JavaScript.
* The base implementation registers a `toString()` method and `name` property.
*
* Example:
*
* ```cpp
* int User::getAge() {
* return 23;
* }
*
* void User::loadHybridMethods() {
* HybridObject::loadHybridMethods();
* registerHybridMethod("getAge", &User::getAge);
* }
* ```
*/
virtual void loadHybridMethods() override;
private:
static constexpr auto TAG = "HybridObject";
const char* _name = TAG;
std::unordered_map<jsi::Runtime*, OwningReference<jsi::WeakObject>> _objectCache;
};
} // namespace margelo::nitro