1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 */ 7 8 #pragma once 9 #ifdef __cplusplus 10 11 #include <cassert> 12 #include <string> 13 #include <memory> 14 #include <mutex> 15 #include <unordered_set> 16 17 #import <ABI48_0_0jsi/ABI48_0_0jsi.h> 18 #import <ABI48_0_0ReactCommon/ABI48_0_0CallInvoker.h> 19 20 using namespace ABI48_0_0facebook; 21 using CallInvoker = ABI48_0_0facebook::ABI48_0_0React::CallInvoker; 22 23 /** 24 * NOTE: This file is a mix of ReactCommon/TurboModuleUtils.h and ReactCommon/LongLivedObject.h 25 * Copying it here is needed until we upgrade RN to 0.66 that includes this commit: 26 * https://github.com/facebook/react-native/commit/32bfd7a857c23dd417f940d0c09843de257f6c61 27 * After that we can just use <ReactCommon/TurboModuleUtils.h> 28 * 29 * We need to wrap it in another napespace, because it would conflict with existing RN implementation 30 */ 31 namespace ABI48_0_0expo { 32 33 /** 34 * A simple wrapper class that can be registered to a collection that keep it 35 * alive for extended period of time. This object can be removed from the 36 * collection when needed. 37 * 38 * The subclass of this class must be created using std::make_shared<T>(). 39 * After creation, add it to the `LongLivedObjectCollection`. 40 * When done with the object, call `allowRelease()` to allow the OS to release 41 * it. 42 */ 43 class LongLivedObject { 44 public: 45 virtual void allowRelease(); 46 47 protected: 48 LongLivedObject() {} 49 virtual ~LongLivedObject() {} 50 }; 51 52 /** 53 * A singleton, thread-safe, write-only collection for the `LongLivedObject`s. 54 */ 55 class LongLivedObjectCollection { 56 public: 57 static LongLivedObjectCollection &get(); 58 59 LongLivedObjectCollection() {} 60 LongLivedObjectCollection(LongLivedObjectCollection const &) = delete; 61 void operator=(LongLivedObjectCollection const &) = delete; 62 63 void add(std::shared_ptr<LongLivedObject> o) const; 64 void remove(const LongLivedObject *o) const; 65 void clear() const; 66 67 private: 68 mutable std::unordered_set<std::shared_ptr<LongLivedObject>> collection_; 69 mutable std::mutex collectionMutex_; 70 }; 71 72 // Helper for passing jsi::Function arg to other methods. 73 class CallbackWrapper : public LongLivedObject { 74 private: 75 CallbackWrapper( 76 jsi::Function &&callback, 77 jsi::Runtime &runtime, 78 std::shared_ptr<CallInvoker> jsInvoker) 79 : longLivedObjectCollection_(), 80 callback_(std::move(callback)), 81 runtime_(runtime), 82 jsInvoker_(std::move(jsInvoker)) {} 83 84 CallbackWrapper( 85 std::shared_ptr<LongLivedObjectCollection> longLivedObjectCollection, 86 jsi::Function &&callback, 87 jsi::Runtime &runtime, 88 std::shared_ptr<CallInvoker> jsInvoker) 89 : longLivedObjectCollection_(longLivedObjectCollection), 90 callback_(std::move(callback)), 91 runtime_(runtime), 92 jsInvoker_(std::move(jsInvoker)) {} 93 94 // Use a weak_ptr to avoid a retain cycle: LongLivedObjectCollection owns all 95 // CallbackWrappers. So, CallbackWrapper cannot own its 96 // LongLivedObjectCollection. 97 std::weak_ptr<LongLivedObjectCollection> longLivedObjectCollection_; 98 jsi::Function callback_; 99 jsi::Runtime &runtime_; 100 std::shared_ptr<CallInvoker> jsInvoker_; 101 102 public: 103 static std::weak_ptr<CallbackWrapper> createWeak( 104 jsi::Function &&callback, 105 jsi::Runtime &runtime, 106 std::shared_ptr<CallInvoker> jsInvoker) { 107 auto wrapper = std::shared_ptr<CallbackWrapper>( 108 new CallbackWrapper(std::move(callback), runtime, jsInvoker)); 109 LongLivedObjectCollection::get().add(wrapper); 110 return wrapper; 111 } 112 113 static std::weak_ptr<CallbackWrapper> createWeak( 114 std::shared_ptr<LongLivedObjectCollection> longLivedObjectCollection, 115 jsi::Function &&callback, 116 jsi::Runtime &runtime, 117 std::shared_ptr<CallInvoker> jsInvoker) { 118 auto wrapper = std::shared_ptr<CallbackWrapper>(new CallbackWrapper( 119 longLivedObjectCollection, std::move(callback), runtime, jsInvoker)); 120 longLivedObjectCollection->add(wrapper); 121 return wrapper; 122 } 123 124 // Delete the enclosed jsi::Function 125 void destroy() { 126 allowRelease(); 127 } 128 129 jsi::Function &callback() { 130 return callback_; 131 } 132 133 jsi::Runtime &runtime() { 134 return runtime_; 135 } 136 137 CallInvoker &jsInvoker() { 138 return *(jsInvoker_); 139 } 140 141 void allowRelease() override { 142 if (auto longLivedObjectCollection = longLivedObjectCollection_.lock()) { 143 if (longLivedObjectCollection != nullptr) { 144 longLivedObjectCollection->remove(this); 145 return; 146 } 147 } 148 LongLivedObject::allowRelease(); 149 } 150 }; 151 152 } 153 154 #endif // __cplusplus 155