objc-js 0.0.15 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -288
- package/binding.gyp +2 -1
- package/dist/native.js +2 -1
- package/package.json +12 -6
- package/prebuilds/darwin-arm64/objc-js.node +0 -0
- package/prebuilds/darwin-x64/objc-js.node +0 -0
- package/src/native/ObjcObject.mm +2 -14
- package/src/native/constants.h +42 -0
- package/src/native/ffi-utils.h +103 -1
- package/src/native/forwarding-common.h +87 -0
- package/src/native/forwarding-common.mm +155 -0
- package/src/native/memory-utils.h +197 -0
- package/src/native/method-forwarding.mm +137 -208
- package/src/native/nobjc.mm +7 -31
- package/src/native/pointer-utils.h +63 -0
- package/src/native/protocol-impl.mm +7 -27
- package/src/native/protocol-manager.h +145 -0
- package/src/native/protocol-storage.h +12 -33
- package/src/native/runtime-detection.h +54 -0
- package/src/native/subclass-impl.mm +232 -566
- package/src/native/subclass-manager.h +170 -0
- package/src/native/super-call-helpers.h +361 -0
- package/src/native/type-conversion.h +200 -246
- package/src/native/type-dispatch.h +241 -0
- package/build/Release/nobjc_native.node +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#ifndef PROTOCOL_MANAGER_H
|
|
2
|
+
#define PROTOCOL_MANAGER_H
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file protocol-manager.h
|
|
6
|
+
* @brief Singleton manager for protocol implementations.
|
|
7
|
+
*
|
|
8
|
+
* ProtocolManager provides thread-safe access to protocol implementation storage.
|
|
9
|
+
* It replaces the global g_implementations map and g_implementations_mutex with
|
|
10
|
+
* an encapsulated singleton pattern.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* // Register a protocol implementation
|
|
14
|
+
* ProtocolManager::Instance().Register(instancePtr, std::move(impl));
|
|
15
|
+
*
|
|
16
|
+
* // Find an implementation
|
|
17
|
+
* auto* impl = ProtocolManager::Instance().Find(instancePtr);
|
|
18
|
+
*
|
|
19
|
+
* // Execute a callback with lock held
|
|
20
|
+
* ProtocolManager::Instance().WithLock([](auto& map) {
|
|
21
|
+
* // ... work with map ...
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
#include "protocol-storage.h"
|
|
26
|
+
#include <functional>
|
|
27
|
+
#include <mutex>
|
|
28
|
+
#include <optional>
|
|
29
|
+
#include <unordered_map>
|
|
30
|
+
|
|
31
|
+
namespace nobjc {
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @brief Thread-safe singleton manager for protocol implementations.
|
|
35
|
+
*
|
|
36
|
+
* Encapsulates storage and synchronization for protocol implementations,
|
|
37
|
+
* providing a clean API for registration, lookup, and unregistration.
|
|
38
|
+
*/
|
|
39
|
+
class ProtocolManager {
|
|
40
|
+
public:
|
|
41
|
+
/**
|
|
42
|
+
* @brief Get the singleton instance.
|
|
43
|
+
* @return Reference to the singleton ProtocolManager.
|
|
44
|
+
*/
|
|
45
|
+
static ProtocolManager& Instance() {
|
|
46
|
+
static ProtocolManager instance;
|
|
47
|
+
return instance;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Delete copy/move operations for singleton
|
|
51
|
+
ProtocolManager(const ProtocolManager&) = delete;
|
|
52
|
+
ProtocolManager& operator=(const ProtocolManager&) = delete;
|
|
53
|
+
ProtocolManager(ProtocolManager&&) = delete;
|
|
54
|
+
ProtocolManager& operator=(ProtocolManager&&) = delete;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @brief Find an implementation by instance pointer.
|
|
58
|
+
* @param instancePtr The Objective-C instance pointer (bridged from id).
|
|
59
|
+
* @return Pointer to implementation if found, nullptr otherwise.
|
|
60
|
+
* @note Caller must NOT hold the lock. This method acquires the lock.
|
|
61
|
+
*/
|
|
62
|
+
ProtocolImplementation* Find(void* instancePtr) {
|
|
63
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
64
|
+
auto it = implementations_.find(instancePtr);
|
|
65
|
+
if (it != implementations_.end()) {
|
|
66
|
+
return &it->second;
|
|
67
|
+
}
|
|
68
|
+
return nullptr;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @brief Register a new protocol implementation.
|
|
73
|
+
* @param instancePtr The Objective-C instance pointer.
|
|
74
|
+
* @param impl The implementation to register (moved).
|
|
75
|
+
*/
|
|
76
|
+
void Register(void* instancePtr, ProtocolImplementation&& impl) {
|
|
77
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
78
|
+
implementations_.emplace(instancePtr, std::move(impl));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @brief Unregister a protocol implementation.
|
|
83
|
+
* @param instancePtr The Objective-C instance pointer.
|
|
84
|
+
* @return true if the implementation was found and removed, false otherwise.
|
|
85
|
+
*/
|
|
86
|
+
bool Unregister(void* instancePtr) {
|
|
87
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
88
|
+
return implementations_.erase(instancePtr) > 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @brief Execute a callback with the lock held.
|
|
93
|
+
* @param callback Function to call with the map reference.
|
|
94
|
+
*
|
|
95
|
+
* Use this for complex operations that need to access multiple map entries
|
|
96
|
+
* or perform conditional logic while holding the lock.
|
|
97
|
+
*/
|
|
98
|
+
template <typename Callback>
|
|
99
|
+
auto WithLock(Callback&& callback)
|
|
100
|
+
-> decltype(callback(std::declval<std::unordered_map<void*, ProtocolImplementation>&>())) {
|
|
101
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
102
|
+
return callback(implementations_);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @brief Execute a read-only callback with the lock held.
|
|
107
|
+
* @param callback Function to call with const map reference.
|
|
108
|
+
*/
|
|
109
|
+
template <typename Callback>
|
|
110
|
+
auto WithLockConst(Callback&& callback) const
|
|
111
|
+
-> decltype(callback(std::declval<const std::unordered_map<void*, ProtocolImplementation>&>())) {
|
|
112
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
113
|
+
return callback(implementations_);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @brief Get the number of registered implementations.
|
|
118
|
+
* @return Count of implementations.
|
|
119
|
+
*/
|
|
120
|
+
size_t Size() const {
|
|
121
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
122
|
+
return implementations_.size();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @brief Check if an implementation exists for the given pointer.
|
|
127
|
+
* @param instancePtr The Objective-C instance pointer.
|
|
128
|
+
* @return true if registered, false otherwise.
|
|
129
|
+
*/
|
|
130
|
+
bool Contains(void* instancePtr) const {
|
|
131
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
132
|
+
return implementations_.find(instancePtr) != implementations_.end();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private:
|
|
136
|
+
ProtocolManager() = default;
|
|
137
|
+
~ProtocolManager() = default;
|
|
138
|
+
|
|
139
|
+
mutable std::mutex mutex_;
|
|
140
|
+
std::unordered_map<void*, ProtocolImplementation> implementations_;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
} // namespace nobjc
|
|
144
|
+
|
|
145
|
+
#endif // PROTOCOL_MANAGER_H
|
|
@@ -89,18 +89,15 @@ struct SubclassImplementation {
|
|
|
89
89
|
bool isElectron;
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
// MARK: - Global Storage
|
|
92
|
+
// MARK: - Global Storage (DEPRECATED - use ProtocolManager/SubclassManager instead)
|
|
93
|
+
// These declarations are kept for backward compatibility during migration.
|
|
94
|
+
// New code should use:
|
|
95
|
+
// - nobjc::ProtocolManager::Instance() for protocol implementations
|
|
96
|
+
// - nobjc::SubclassManager::Instance() for subclass implementations
|
|
93
97
|
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
extern std::unordered_map<void *, ProtocolImplementation> g_implementations;
|
|
98
|
-
extern std::mutex g_implementations_mutex;
|
|
99
|
-
|
|
100
|
-
// Global map: Class pointer -> subclass implementation details
|
|
101
|
-
// This stores information about JS-defined subclasses
|
|
102
|
-
extern std::unordered_map<void *, SubclassImplementation> g_subclasses;
|
|
103
|
-
extern std::mutex g_subclasses_mutex;
|
|
98
|
+
// Note: These extern declarations are removed as storage is now in the manager singletons.
|
|
99
|
+
// If you need to access the storage, use the manager classes directly.
|
|
100
|
+
// See protocol-manager.h and subclass-manager.h for the new APIs.
|
|
104
101
|
|
|
105
102
|
// MARK: - Storage Access Helpers
|
|
106
103
|
|
|
@@ -113,29 +110,11 @@ inline void SignalInvocationComplete(InvocationData *data) {
|
|
|
113
110
|
}
|
|
114
111
|
}
|
|
115
112
|
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
// Caller must hold g_implementations_mutex
|
|
119
|
-
inline ProtocolImplementation *
|
|
120
|
-
FindImplementation(void *instancePtr) {
|
|
121
|
-
auto it = g_implementations.find(instancePtr);
|
|
122
|
-
if (it != g_implementations.end()) {
|
|
123
|
-
return &it->second;
|
|
124
|
-
}
|
|
125
|
-
return nullptr;
|
|
126
|
-
}
|
|
113
|
+
// DEPRECATED: Use nobjc::ProtocolManager::Instance().Find(instancePtr) instead
|
|
114
|
+
// This function is no longer available as global storage has been moved to manager classes.
|
|
127
115
|
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
// Caller must hold g_subclasses_mutex
|
|
131
|
-
inline SubclassImplementation *
|
|
132
|
-
FindSubclassImplementation(void *classPtr) {
|
|
133
|
-
auto it = g_subclasses.find(classPtr);
|
|
134
|
-
if (it != g_subclasses.end()) {
|
|
135
|
-
return &it->second;
|
|
136
|
-
}
|
|
137
|
-
return nullptr;
|
|
138
|
-
}
|
|
116
|
+
// DEPRECATED: Use nobjc::SubclassManager::Instance().Find(classPtr) instead
|
|
117
|
+
// This function is no longer available as global storage has been moved to manager classes.
|
|
139
118
|
|
|
140
119
|
#endif // PROTOCOL_STORAGE_H
|
|
141
120
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#ifndef RUNTIME_DETECTION_H
|
|
2
|
+
#define RUNTIME_DETECTION_H
|
|
3
|
+
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Detects if the code is running in an Electron environment.
|
|
8
|
+
*
|
|
9
|
+
* This is detected by checking for process.versions.electron.
|
|
10
|
+
* In Electron, direct JS callback invocation may fail due to V8 context
|
|
11
|
+
* issues, so we need to use ThreadSafeFunction for all callbacks.
|
|
12
|
+
*
|
|
13
|
+
* @param env The N-API environment
|
|
14
|
+
* @return true if running in Electron, false otherwise
|
|
15
|
+
*/
|
|
16
|
+
inline bool IsElectronRuntime(Napi::Env env) {
|
|
17
|
+
try {
|
|
18
|
+
Napi::Object global = env.Global();
|
|
19
|
+
if (global.Has("process")) {
|
|
20
|
+
Napi::Object process = global.Get("process").As<Napi::Object>();
|
|
21
|
+
if (process.Has("versions")) {
|
|
22
|
+
Napi::Object versions = process.Get("versions").As<Napi::Object>();
|
|
23
|
+
return versions.Has("electron");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
} catch (...) {
|
|
27
|
+
// If detection fails, assume not Electron
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Detects if the code is running in Bun.
|
|
34
|
+
*
|
|
35
|
+
* @param env The N-API environment
|
|
36
|
+
* @return true if running in Bun, false otherwise
|
|
37
|
+
*/
|
|
38
|
+
inline bool IsBunRuntime(Napi::Env env) {
|
|
39
|
+
try {
|
|
40
|
+
Napi::Object global = env.Global();
|
|
41
|
+
if (global.Has("process")) {
|
|
42
|
+
Napi::Object process = global.Get("process").As<Napi::Object>();
|
|
43
|
+
if (process.Has("versions")) {
|
|
44
|
+
Napi::Object versions = process.Get("versions").As<Napi::Object>();
|
|
45
|
+
return versions.Has("bun");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} catch (...) {
|
|
49
|
+
// If detection fails, assume not Bun
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#endif // RUNTIME_DETECTION_H
|