1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #pragma once 4 5 #include "CppType.h" 6 7 #include <jsi/jsi.h> 8 #include <fbjni/fbjni.h> 9 10 namespace jni = facebook::jni; 11 namespace jsi = facebook::jsi; 12 13 namespace expo { 14 class JSIInteropModuleRegistry; 15 class SingleType; 16 17 /** 18 * A base interface for all frontend converter classes - converters that cast jsi values into JNI objects. 19 * Right now, we have two-step arguments conversion. Firstly, we unwrapped the JSI value into selected JNI objects (see CppType). 20 * Then, we do a more sophisticated conversion like creating records or mapping into enums. 21 * The second step lives in the Kotlin codebase. 22 */ 23 class FrontendConverter { 24 public: 25 virtual ~FrontendConverter() = default; 26 27 /** 28 * Checks if the provided value can be converted. 29 */ 30 virtual bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const = 0; 31 32 /** 33 * Converts the provided value. 34 */ 35 virtual jobject convert( 36 jsi::Runtime &rt, 37 JNIEnv *env, 38 JSIInteropModuleRegistry *moduleRegistry, 39 const jsi::Value &value 40 ) const = 0; 41 }; 42 43 /** 44 * Converter from js number to [java.lang.Integer]. 45 */ 46 class IntegerFrontendConverter : public FrontendConverter { 47 public: 48 jobject convert( 49 jsi::Runtime &rt, 50 JNIEnv *env, 51 JSIInteropModuleRegistry *moduleRegistry, 52 const jsi::Value &value 53 ) const override; 54 55 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 56 }; 57 58 /** 59 * Converter from js number to [java.lang.Long]. 60 */ 61 class LongFrontendConverter : public FrontendConverter { 62 public: 63 jobject convert( 64 jsi::Runtime &rt, 65 JNIEnv *env, 66 JSIInteropModuleRegistry *moduleRegistry, 67 const jsi::Value &value 68 ) const override; 69 70 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 71 }; 72 73 /** 74 * Converter from js number to [java.lang.Float]. 75 */ 76 class FloatFrontendConverter : public FrontendConverter { 77 public: 78 jobject convert( 79 jsi::Runtime &rt, 80 JNIEnv *env, 81 JSIInteropModuleRegistry *moduleRegistry, 82 const jsi::Value &value 83 ) const override; 84 85 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 86 }; 87 88 /** 89 * Converter from js bool to [java.lang.Boolean]. 90 */ 91 class BooleanFrontendConverter : public FrontendConverter { 92 public: 93 jobject convert( 94 jsi::Runtime &rt, 95 JNIEnv *env, 96 JSIInteropModuleRegistry *moduleRegistry, 97 const jsi::Value &value 98 ) const override; 99 100 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 101 }; 102 103 /** 104 * Converter from js number to [java.lang.Double]. 105 */ 106 class DoubleFrontendConverter : public FrontendConverter { 107 public: 108 jobject convert( 109 jsi::Runtime &rt, 110 JNIEnv *env, 111 JSIInteropModuleRegistry *moduleRegistry, 112 const jsi::Value &value 113 ) const override; 114 115 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 116 }; 117 118 /** 119 * Converter from js string to [java.lang.String]. 120 */ 121 class StringFrontendConverter : public FrontendConverter { 122 public: 123 jobject convert( 124 jsi::Runtime &rt, 125 JNIEnv *env, 126 JSIInteropModuleRegistry *moduleRegistry, 127 const jsi::Value &value 128 ) const override; 129 130 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 131 }; 132 133 /** 134 * Converter from js array to [com.facebook.react.bridge.ReadableNativeArray]. 135 */ 136 class ReadableNativeArrayFrontendConverter : public FrontendConverter { 137 public: 138 jobject convert( 139 jsi::Runtime &rt, 140 JNIEnv *env, 141 JSIInteropModuleRegistry *moduleRegistry, 142 const jsi::Value &value 143 ) const override; 144 145 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 146 }; 147 148 /** 149 * Converter from js object to [com.facebook.react.bridge.ReadableNativeMap]. 150 */ 151 class ReadableNativeMapArrayFrontendConverter : public FrontendConverter { 152 public: 153 jobject convert( 154 jsi::Runtime &rt, 155 JNIEnv *env, 156 JSIInteropModuleRegistry *moduleRegistry, 157 const jsi::Value &value 158 ) const override; 159 160 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 161 }; 162 163 /** 164 * Converter from js type array to [expo.modules.kotlin.jni.JavaScriptTypedArray]. 165 */ 166 class TypedArrayFrontendConverter : public FrontendConverter { 167 public: 168 jobject convert( 169 jsi::Runtime &rt, 170 JNIEnv *env, 171 JSIInteropModuleRegistry *moduleRegistry, 172 const jsi::Value &value 173 ) const override; 174 175 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 176 }; 177 178 /** 179 * Converter from any js value to [expo.modules.kotlin.jni.JavaScriptValue]. 180 */ 181 class JavaScriptValueFrontendConverter : public FrontendConverter { 182 public: 183 jobject convert( 184 jsi::Runtime &rt, 185 JNIEnv *env, 186 JSIInteropModuleRegistry *moduleRegistry, 187 const jsi::Value &value 188 ) const override; 189 190 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 191 }; 192 193 /** 194 * Converter from js object to [expo.modules.kotlin.jni.JavaScriptObject]. 195 */ 196 class JavaScriptObjectFrontendConverter : public FrontendConverter { 197 public: 198 jobject convert( 199 jsi::Runtime &rt, 200 JNIEnv *env, 201 JSIInteropModuleRegistry *moduleRegistry, 202 const jsi::Value &value 203 ) const override; 204 205 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 206 }; 207 208 /** 209 * Converter from js function to [expo.modules.kotlin.jni.JavaScriptFunction]. 210 */ 211 class JavaScriptFunctionFrontendConverter : public FrontendConverter { 212 public: 213 jobject convert( 214 jsi::Runtime &rt, 215 JNIEnv *env, 216 JSIInteropModuleRegistry *moduleRegistry, 217 const jsi::Value &value 218 ) const override; 219 220 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 221 }; 222 223 /** 224 * Converter from js view object to int. 225 */ 226 class ViewTagFrontendConverter : public FrontendConverter { 227 public: 228 jobject convert( 229 jsi::Runtime &rt, 230 JNIEnv *env, 231 JSIInteropModuleRegistry *moduleRegistry, 232 const jsi::Value &value 233 ) const override; 234 235 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 236 }; 237 238 /** 239 * Converter from js shared object to int. 240 */ 241 class SharedObjectIdConverter : public FrontendConverter { 242 public: 243 jobject convert( 244 jsi::Runtime &rt, 245 JNIEnv *env, 246 JSIInteropModuleRegistry *moduleRegistry, 247 const jsi::Value &value 248 ) const override; 249 250 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 251 }; 252 253 /** 254 * Converter that always fails. 255 * Used to not fail when the function is created. 256 * TODO(@lukmccall): remove 257 */ 258 class UnknownFrontendConverter : public FrontendConverter { 259 public: 260 jobject convert( 261 jsi::Runtime &rt, 262 JNIEnv *env, 263 JSIInteropModuleRegistry *moduleRegistry, 264 const jsi::Value &value 265 ) const override; 266 267 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 268 }; 269 270 /** 271 * Same types like enums can be represented by multiply js types. 272 * That's why we have a converter that can combine multiple converters into one. 273 * 274 * For instance, enum classes will be represented as a PolyFrontendConverter({StringFrontendConverter, IntegerFrontendConverter}) 275 */ 276 class PolyFrontendConverter : public FrontendConverter { 277 public: 278 PolyFrontendConverter(std::vector<std::shared_ptr<FrontendConverter>> converters); 279 280 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 281 282 jobject convert( 283 jsi::Runtime &rt, 284 JNIEnv *env, 285 JSIInteropModuleRegistry *moduleRegistry, 286 const jsi::Value &value 287 ) const override; 288 289 private: 290 std::vector<std::shared_ptr<FrontendConverter>> converters; 291 }; 292 293 /** 294 * Converter from js array object to Java primitive array. 295 */ 296 class PrimitiveArrayFrontendConverter : public FrontendConverter { 297 public: 298 PrimitiveArrayFrontendConverter( 299 jni::local_ref<jni::JavaClass<SingleType>::javaobject> expectedType 300 ); 301 302 jobject convert( 303 jsi::Runtime &rt, 304 JNIEnv *env, 305 JSIInteropModuleRegistry *moduleRegistry, 306 const jsi::Value &value 307 ) const override; 308 309 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 310 311 private: 312 /** 313 * A string representation of desired Java type. 314 */ 315 std::string javaType; 316 /** 317 * Bare parameter type. 318 */ 319 CppType parameterType; 320 /** 321 * Converter used to convert array elements. 322 */ 323 std::shared_ptr<FrontendConverter> parameterConverter; 324 }; 325 326 /** 327 * Converter from js array object to [java.utils.ArrayList]. 328 */ 329 class ListFrontendConverter : public FrontendConverter { 330 public: 331 ListFrontendConverter( 332 jni::local_ref<jni::JavaClass<SingleType>::javaobject> expectedType 333 ); 334 335 jobject convert( 336 jsi::Runtime &rt, 337 JNIEnv *env, 338 JSIInteropModuleRegistry *moduleRegistry, 339 const jsi::Value &value 340 ) const override; 341 342 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 343 private: 344 /** 345 * Converter used to convert array elements. 346 */ 347 std::shared_ptr<FrontendConverter> parameterConverter; 348 }; 349 350 /** 351 * Converter from js object to [java.utils.LinkedHashMap]. 352 */ 353 class MapFrontendConverter : public FrontendConverter { 354 public: 355 MapFrontendConverter( 356 jni::local_ref<jni::JavaClass<SingleType>::javaobject> expectedType 357 ); 358 359 jobject convert( 360 jsi::Runtime &rt, 361 JNIEnv *env, 362 JSIInteropModuleRegistry *moduleRegistry, 363 const jsi::Value &value 364 ) const override; 365 366 bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override; 367 private: 368 /** 369 * Converter used to convert values. 370 */ 371 std::shared_ptr<FrontendConverter> valueConverter; 372 }; 373 } // namespace expo 374