-
Notifications
You must be signed in to change notification settings - Fork 24.5k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
react-native code-gen > C++ TurboModules struct support #35265
Conversation
This pull request was exported from Phabricator. Differential Revision: D41133761 |
Base commit: cf37479 |
Base commit: cf37479 |
This pull request was exported from Phabricator. Differential Revision: D41133761 |
Summary: Pull Request resolved: facebook#35265 This adds a templating layer for C++ TurboModules to automatically generate struct templates from TurboModule specs. You have to define concrete types for those templates to use them in your C++ TurboModule. E.g. for the JS flow type: ``` export type ObjectStruct = {| a: number, b: string, c?: ?string, |}; ``` code-gen will now generate the following template code: ``` #pragma mark - NativeCxxModuleExampleCxxBaseObjectStruct template <typename P0, typename P1, typename P2> struct NativeCxxModuleExampleCxxBaseObjectStruct { P0 a; P1 b; P2 c; bool operator==(const NativeCxxModuleExampleCxxBaseObjectStruct &other) const { return a == other.a && b == other.b && c == other.c; } }; template <typename P0, typename P1, typename P2> struct NativeCxxModuleExampleCxxBaseObjectStructBridging { static NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr<CallInvoker> &jsInvoker) { NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> result{ bridging::fromJs<P0>(rt, value.getProperty(rt, "a"), jsInvoker), bridging::fromJs<P1>(rt, value.getProperty(rt, "b"), jsInvoker), bridging::fromJs<P2>(rt, value.getProperty(rt, "c"), jsInvoker)}; return result; } static jsi::Object toJs( jsi::Runtime &rt, const NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> &value) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, "a", bridging::toJs(rt, value.a)); result.setProperty(rt, "b", bridging::toJs(rt, value.b)); if (value.c) { result.setProperty(rt, "c", bridging::toJs(rt, value.c.value())); } return result; } }; ``` and you can use it in our C++ TurboModule for example as: ``` using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct< int32_t, std::string, std::optional<std::string>>; template <> struct Bridging<ObjectStruct> : NativeCxxModuleExampleCxxBaseObjectStructBridging< int32_t, std::string, std::optional<std::string>> {}; ``` or as ``` using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct< float, folly::StringPiece, std::optional<std::string>>; template <> struct Bridging<ObjectStruct> : NativeCxxModuleExampleCxxBaseObjectStructBridging< float, folly::StringPiece, std::optional<std::string>> {}; ``` Or as ... Changelog: [Internal] Differential Revision: D41133761 fbshipit-source-id: ec4e944fed6304b3b6a59dad3952abc9b98644ac
cf611d2
to
6b120b5
Compare
PR build artifact for 6b120b5 is ready. |
…id/iOS/macOS/Windows) Summary: Changelog: [General][Added] - Add a C++ only TurboModule example (for Android/iOS/macOS/Windows) react-native@0.69 introduced a new bridging layer to ease integration for pure C++ TurboModules using C++ std:: types directly instead of the lower level jsi:: types: https://github.com/facebook/react-native/tree/v0.69.0/ReactCommon/react/bridging This bridging layer can be used in JSI functions or more conveniently in C++ TurboModules. Here is a example of an C++ only TurboModule which will work on Android and iOS and macOS/Windows (using microsoft/react-native-macos|windows) only using flow/TypeScript and standard C++ types. C++ only TurboModules are very handy as they do not require to work with JSI APIs - instead std:: or custom C++ can by used. Differential Revision: https://internalfb.com/D39011736 fbshipit-source-id: f4dadd46bdd65e45193dd6ddffee503bd473a110
Summary: Pull Request resolved: facebook#35265 This adds a templating layer for C++ TurboModules to automatically generate struct templates from TurboModule specs. You have to define concrete types for those templates to use them in your C++ TurboModule. E.g. for the JS flow type: ``` export type ObjectStruct = {| a: number, b: string, c?: ?string, |}; ``` code-gen will now generate the following template code: ``` #pragma mark - NativeCxxModuleExampleCxxBaseObjectStruct template <typename P0, typename P1, typename P2> struct NativeCxxModuleExampleCxxBaseObjectStruct { P0 a; P1 b; P2 c; bool operator==(const NativeCxxModuleExampleCxxBaseObjectStruct &other) const { return a == other.a && b == other.b && c == other.c; } }; template <typename P0, typename P1, typename P2> struct NativeCxxModuleExampleCxxBaseObjectStructBridging { static NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr<CallInvoker> &jsInvoker) { NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> result{ bridging::fromJs<P0>(rt, value.getProperty(rt, "a"), jsInvoker), bridging::fromJs<P1>(rt, value.getProperty(rt, "b"), jsInvoker), bridging::fromJs<P2>(rt, value.getProperty(rt, "c"), jsInvoker)}; return result; } static jsi::Object toJs( jsi::Runtime &rt, const NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> &value) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, "a", bridging::toJs(rt, value.a)); result.setProperty(rt, "b", bridging::toJs(rt, value.b)); if (value.c) { result.setProperty(rt, "c", bridging::toJs(rt, value.c.value())); } return result; } }; ``` and you can use it in our C++ TurboModule for example as: ``` using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct< int32_t, std::string, std::optional<std::string>>; template <> struct Bridging<ObjectStruct> : NativeCxxModuleExampleCxxBaseObjectStructBridging< int32_t, std::string, std::optional<std::string>> {}; ``` or as ``` using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct< float, folly::StringPiece, std::optional<std::string>>; template <> struct Bridging<ObjectStruct> : NativeCxxModuleExampleCxxBaseObjectStructBridging< float, folly::StringPiece, std::optional<std::string>> {}; ``` Or as ... Changelog: [Internal] Differential Revision: D41133761 fbshipit-source-id: 9ed5a118834e067951b5b45d2551188dff38219f
This pull request was exported from Phabricator. Differential Revision: D41133761 |
6b120b5
to
7ffab16
Compare
PR build artifact for 7ffab16 is ready. |
Summary: Pull Request resolved: #35265 This adds a templating layer for C++ TurboModules to automatically generate struct templates from TurboModule specs. You have to define concrete types for those templates to use them in your C++ TurboModule. E.g. for the JS flow type: ``` export type ObjectStruct = {| a: number, b: string, c?: ?string, |}; ``` code-gen will now generate the following template code: ``` #pragma mark - NativeCxxModuleExampleCxxBaseObjectStruct template <typename P0, typename P1, typename P2> struct NativeCxxModuleExampleCxxBaseObjectStruct { P0 a; P1 b; P2 c; bool operator==(const NativeCxxModuleExampleCxxBaseObjectStruct &other) const { return a == other.a && b == other.b && c == other.c; } }; template <typename P0, typename P1, typename P2> struct NativeCxxModuleExampleCxxBaseObjectStructBridging { static NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr<CallInvoker> &jsInvoker) { NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> result{ bridging::fromJs<P0>(rt, value.getProperty(rt, "a"), jsInvoker), bridging::fromJs<P1>(rt, value.getProperty(rt, "b"), jsInvoker), bridging::fromJs<P2>(rt, value.getProperty(rt, "c"), jsInvoker)}; return result; } static jsi::Object toJs( jsi::Runtime &rt, const NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> &value) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, "a", bridging::toJs(rt, value.a)); result.setProperty(rt, "b", bridging::toJs(rt, value.b)); if (value.c) { result.setProperty(rt, "c", bridging::toJs(rt, value.c.value())); } return result; } }; ``` and you can use it in our C++ TurboModule for example as: ``` using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct< int32_t, std::string, std::optional<std::string>>; template <> struct Bridging<ObjectStruct> : NativeCxxModuleExampleCxxBaseObjectStructBridging< int32_t, std::string, std::optional<std::string>> {}; ``` or as ``` using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct< float, folly::StringPiece, std::optional<std::string>>; template <> struct Bridging<ObjectStruct> : NativeCxxModuleExampleCxxBaseObjectStructBridging< float, folly::StringPiece, std::optional<std::string>> {}; ``` Or as ... Changelog: [Internal] Reviewed By: rshest Differential Revision: D41133761 fbshipit-source-id: fdf36e51073cb46c5234f6121842c79a884899c7
Summary: Changelog: [Internal] ## Change: facebook#35265 added a struct generator - but it is not type safe :-( E.g. you can write a TM Spec type as: ``` export type CustomType = { key: string; enabled: boolean; time?: number; } ``` And a C++ type as: ``` using CustomType = NativeSampleModuleBaseCustomType<float, bool, std::optional<int32_t>>; template <> struct Bridging<CustomType> : NativeSampleModuleBaseCustomTypeBridging<float, bool, std::optional<int32_t>> {}; ``` and it will still compile :-( - which should not. The reason is that the generated structs don't validate the members type :-( ``` template <typename P0, typename P1, typename P2> struct NativeSampleModuleBaseCustomType { P0 key; P1 enabled; P2 time; bool operator==(const NativeSampleModuleBaseCustomType &other) const { return key == other.key && enabled == other.enabled && time == other.time; } }; template <typename P0, typename P1, typename P2> struct NativeSampleModuleBaseCustomTypeBridging { static NativeSampleModuleBaseCustomType<P0, P1, P2> fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr<CallInvoker> &jsInvoker) { NativeSampleModuleBaseCustomType<P0, P1, P2> result{ bridging::fromJs<P0>(rt, value.getProperty(rt, "key"), jsInvoker), bridging::fromJs<P1>(rt, value.getProperty(rt, "enabled"), jsInvoker), bridging::fromJs<P2>(rt, value.getProperty(rt, "time"), jsInvoker)}; return result; } static jsi::Object toJs( jsi::Runtime &rt, const NativeSampleModuleBaseCustomType<P0, P1, P2> &value) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, "key", bridging::toJs(rt, value.key)); result.setProperty(rt, "enabled", bridging::toJs(rt, value.enabled)); if (value.time) { result.setProperty(rt, "time", bridging::toJs(rt, value.time.value())); } keyToJs(rt, value.key); return result; } }; ``` This fixes that, by simply emitting conversion functions for each member such as ``` #ifdef DEBUG static bool keyToJs(jsi::Runtime &rt, P0 value) { return bridging::toJs(rt, value); } static double enabledToJs(jsi::Runtime &rt, P1 value) { return bridging::toJs(rt, value); } static jsi::String timeToJs(jsi::Runtime &rt, P2 value) { return bridging::toJs(rt, value); } #endif ``` Differential Revision: D42082423 fbshipit-source-id: 0022bcc3ce292c38dffc051c25959b2e3d5b17cb
Summary: Pull Request resolved: facebook#35656 Changelog: [Internal] ## Change: facebook#35265 added a struct generator - but it is not type safe :-( E.g. you can write a TM Spec type as: ``` export type CustomType = { key: string; enabled: boolean; time?: number; } ``` And a C++ type as: ``` using CustomType = NativeSampleModuleBaseCustomType<float, bool, std::optional<int32_t>>; template <> struct Bridging<CustomType> : NativeSampleModuleBaseCustomTypeBridging<float, bool, std::optional<int32_t>> {}; ``` and it will still compile :-( - which should not. The reason is that the generated structs don't validate the members type :-( ``` template <typename P0, typename P1, typename P2> struct NativeSampleModuleBaseCustomType { P0 key; P1 enabled; P2 time; bool operator==(const NativeSampleModuleBaseCustomType &other) const { return key == other.key && enabled == other.enabled && time == other.time; } }; template <typename P0, typename P1, typename P2> struct NativeSampleModuleBaseCustomTypeBridging { static NativeSampleModuleBaseCustomType<P0, P1, P2> fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr<CallInvoker> &jsInvoker) { NativeSampleModuleBaseCustomType<P0, P1, P2> result{ bridging::fromJs<P0>(rt, value.getProperty(rt, "key"), jsInvoker), bridging::fromJs<P1>(rt, value.getProperty(rt, "enabled"), jsInvoker), bridging::fromJs<P2>(rt, value.getProperty(rt, "time"), jsInvoker)}; return result; } static jsi::Object toJs( jsi::Runtime &rt, const NativeSampleModuleBaseCustomType<P0, P1, P2> &value) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, "key", bridging::toJs(rt, value.key)); result.setProperty(rt, "enabled", bridging::toJs(rt, value.enabled)); if (value.time) { result.setProperty(rt, "time", bridging::toJs(rt, value.time.value())); } keyToJs(rt, value.key); return result; } }; ``` This fixes that, by simply emitting conversion functions for each member such as ``` #ifdef DEBUG static bool keyToJs(jsi::Runtime &rt, P0 value) { return bridging::toJs(rt, value); } static double enabledToJs(jsi::Runtime &rt, P1 value) { return bridging::toJs(rt, value); } static jsi::String timeToJs(jsi::Runtime &rt, P2 value) { return bridging::toJs(rt, value); } #endif ``` Differential Revision: D42082423 fbshipit-source-id: c7857944ba5d5a57623fc627df4d885867b025cf
Summary: Pull Request resolved: #35656 Changelog: [Internal] ## Change: #35265 added a struct generator - but it is not type safe :-( E.g. you can write a TM Spec type as: ``` export type CustomType = { key: string; enabled: boolean; time?: number; } ``` And a C++ type as: ``` using CustomType = NativeSampleModuleBaseCustomType<float, bool, std::optional<int32_t>>; template <> struct Bridging<CustomType> : NativeSampleModuleBaseCustomTypeBridging<float, bool, std::optional<int32_t>> {}; ``` and it will still compile :-( - which should not. The reason is that the generated structs don't validate the members type :-( ``` template <typename P0, typename P1, typename P2> struct NativeSampleModuleBaseCustomType { P0 key; P1 enabled; P2 time; bool operator==(const NativeSampleModuleBaseCustomType &other) const { return key == other.key && enabled == other.enabled && time == other.time; } }; template <typename P0, typename P1, typename P2> struct NativeSampleModuleBaseCustomTypeBridging { static NativeSampleModuleBaseCustomType<P0, P1, P2> fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr<CallInvoker> &jsInvoker) { NativeSampleModuleBaseCustomType<P0, P1, P2> result{ bridging::fromJs<P0>(rt, value.getProperty(rt, "key"), jsInvoker), bridging::fromJs<P1>(rt, value.getProperty(rt, "enabled"), jsInvoker), bridging::fromJs<P2>(rt, value.getProperty(rt, "time"), jsInvoker)}; return result; } static jsi::Object toJs( jsi::Runtime &rt, const NativeSampleModuleBaseCustomType<P0, P1, P2> &value) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, "key", bridging::toJs(rt, value.key)); result.setProperty(rt, "enabled", bridging::toJs(rt, value.enabled)); if (value.time) { result.setProperty(rt, "time", bridging::toJs(rt, value.time.value())); } keyToJs(rt, value.key); return result; } }; ``` This fixes that, by simply emitting conversion functions for each member such as ``` #ifdef DEBUG static bool keyToJs(jsi::Runtime &rt, P0 value) { return bridging::toJs(rt, value); } static double enabledToJs(jsi::Runtime &rt, P1 value) { return bridging::toJs(rt, value); } static jsi::String timeToJs(jsi::Runtime &rt, P2 value) { return bridging::toJs(rt, value); } #endif ``` Reviewed By: cipolleschi Differential Revision: D42082423 fbshipit-source-id: 5133f14e2aa8351e9bbbf614117a3d5894b17fa6
Summary: Pull Request resolved: facebook#35265 This adds a templating layer for C++ TurboModules to automatically generate struct templates from TurboModule specs. You have to define concrete types for those templates to use them in your C++ TurboModule. E.g. for the JS flow type: ``` export type ObjectStruct = {| a: number, b: string, c?: ?string, |}; ``` code-gen will now generate the following template code: ``` #pragma mark - NativeCxxModuleExampleCxxBaseObjectStruct template <typename P0, typename P1, typename P2> struct NativeCxxModuleExampleCxxBaseObjectStruct { P0 a; P1 b; P2 c; bool operator==(const NativeCxxModuleExampleCxxBaseObjectStruct &other) const { return a == other.a && b == other.b && c == other.c; } }; template <typename P0, typename P1, typename P2> struct NativeCxxModuleExampleCxxBaseObjectStructBridging { static NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr<CallInvoker> &jsInvoker) { NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> result{ bridging::fromJs<P0>(rt, value.getProperty(rt, "a"), jsInvoker), bridging::fromJs<P1>(rt, value.getProperty(rt, "b"), jsInvoker), bridging::fromJs<P2>(rt, value.getProperty(rt, "c"), jsInvoker)}; return result; } static jsi::Object toJs( jsi::Runtime &rt, const NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> &value) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, "a", bridging::toJs(rt, value.a)); result.setProperty(rt, "b", bridging::toJs(rt, value.b)); if (value.c) { result.setProperty(rt, "c", bridging::toJs(rt, value.c.value())); } return result; } }; ``` and you can use it in our C++ TurboModule for example as: ``` using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct< int32_t, std::string, std::optional<std::string>>; template <> struct Bridging<ObjectStruct> : NativeCxxModuleExampleCxxBaseObjectStructBridging< int32_t, std::string, std::optional<std::string>> {}; ``` or as ``` using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct< float, folly::StringPiece, std::optional<std::string>>; template <> struct Bridging<ObjectStruct> : NativeCxxModuleExampleCxxBaseObjectStructBridging< float, folly::StringPiece, std::optional<std::string>> {}; ``` Or as ... Changelog: [Internal] Reviewed By: rshest Differential Revision: D41133761 fbshipit-source-id: fdf36e51073cb46c5234f6121842c79a884899c7
Summary: Pull Request resolved: facebook#35656 Changelog: [Internal] ## Change: facebook#35265 added a struct generator - but it is not type safe :-( E.g. you can write a TM Spec type as: ``` export type CustomType = { key: string; enabled: boolean; time?: number; } ``` And a C++ type as: ``` using CustomType = NativeSampleModuleBaseCustomType<float, bool, std::optional<int32_t>>; template <> struct Bridging<CustomType> : NativeSampleModuleBaseCustomTypeBridging<float, bool, std::optional<int32_t>> {}; ``` and it will still compile :-( - which should not. The reason is that the generated structs don't validate the members type :-( ``` template <typename P0, typename P1, typename P2> struct NativeSampleModuleBaseCustomType { P0 key; P1 enabled; P2 time; bool operator==(const NativeSampleModuleBaseCustomType &other) const { return key == other.key && enabled == other.enabled && time == other.time; } }; template <typename P0, typename P1, typename P2> struct NativeSampleModuleBaseCustomTypeBridging { static NativeSampleModuleBaseCustomType<P0, P1, P2> fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr<CallInvoker> &jsInvoker) { NativeSampleModuleBaseCustomType<P0, P1, P2> result{ bridging::fromJs<P0>(rt, value.getProperty(rt, "key"), jsInvoker), bridging::fromJs<P1>(rt, value.getProperty(rt, "enabled"), jsInvoker), bridging::fromJs<P2>(rt, value.getProperty(rt, "time"), jsInvoker)}; return result; } static jsi::Object toJs( jsi::Runtime &rt, const NativeSampleModuleBaseCustomType<P0, P1, P2> &value) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, "key", bridging::toJs(rt, value.key)); result.setProperty(rt, "enabled", bridging::toJs(rt, value.enabled)); if (value.time) { result.setProperty(rt, "time", bridging::toJs(rt, value.time.value())); } keyToJs(rt, value.key); return result; } }; ``` This fixes that, by simply emitting conversion functions for each member such as ``` #ifdef DEBUG static bool keyToJs(jsi::Runtime &rt, P0 value) { return bridging::toJs(rt, value); } static double enabledToJs(jsi::Runtime &rt, P1 value) { return bridging::toJs(rt, value); } static jsi::String timeToJs(jsi::Runtime &rt, P2 value) { return bridging::toJs(rt, value); } #endif ``` Reviewed By: cipolleschi Differential Revision: D42082423 fbshipit-source-id: 5133f14e2aa8351e9bbbf614117a3d5894b17fa6
Summary:
This adds a templating layer for C++ TurboModules to automatically generate struct templates from TurboModule specs.
You have to define concrete types for those templates to use them in your C++ TurboModule.
E.g. for the JS flow type:
code-gen will now generate the following template code:
and you can use it in our C++ TurboModule for example as:
or as
Or as
...
Changelog: [Internal]
Differential Revision: D41133761