-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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