react-native code-gen > C++ TurboModules struct support (#35265)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/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
This commit is contained in:
Christoph Purrer
2022-11-22 11:15:24 +00:00
committed by Lorenzo Sciandra
parent adcdb366da
commit 08430bf214
9 changed files with 493 additions and 223 deletions
@@ -13,10 +13,34 @@
#include <optional>
#include <string>
#include <vector>
#include "NativePerformanceObserver_RawPerformanceEntry.h"
namespace facebook::react {
#pragma mark - Structs
using RawPerformanceEntry = NativePerformanceObserverCxxBaseRawPerformanceEntry<
std::string,
int32_t,
double,
double,
// For "event" entries only:
std::optional<double>,
std::optional<double>,
std::optional<double>>;
template <>
struct Bridging<RawPerformanceEntry>
: NativePerformanceObserverCxxBaseRawPerformanceEntryBridging<
std::string,
int32_t,
double,
double,
std::optional<double>,
std::optional<double>,
std::optional<double>> {};
#pragma mark - implementation
class NativePerformanceObserver
: public NativePerformanceObserverCxxSpec<NativePerformanceObserver>,
std::enable_shared_from_this<NativePerformanceObserver> {
@@ -18,7 +18,7 @@ export const RawPerformanceEntryTypeValues = {
export type RawPerformanceEntryType = number;
export type RawPerformanceEntry = $ReadOnly<{
export type RawPerformanceEntry = {|
name: string,
entryType: RawPerformanceEntryType,
startTime: number,
@@ -27,7 +27,7 @@ export type RawPerformanceEntry = $ReadOnly<{
processingStart?: number,
processingEnd?: number,
interactionId?: number,
}>;
|};
export interface Spec extends TurboModule {
+startReporting: (entryType: string) => void;
@@ -1,76 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/bridging/Bridging.h>
#include <optional>
#include <string>
namespace facebook::react {
struct RawPerformanceEntry {
std::string name;
int32_t entryType;
double startTime;
double duration;
// For "event" entries only:
std::optional<double> processingStart;
std::optional<double> processingEnd;
std::optional<double> interactionId;
};
template <>
struct Bridging<RawPerformanceEntry> {
static RawPerformanceEntry fromJs(
jsi::Runtime &rt,
const jsi::Object &value,
const std::shared_ptr<CallInvoker> &jsInvoker) {
RawPerformanceEntry result{
bridging::fromJs<std::string>(
rt, value.getProperty(rt, "name"), jsInvoker),
bridging::fromJs<int32_t>(
rt, value.getProperty(rt, "entryType"), jsInvoker),
bridging::fromJs<double>(
rt, value.getProperty(rt, "startTime"), jsInvoker),
bridging::fromJs<double>(
rt, value.getProperty(rt, "duration"), jsInvoker),
bridging::fromJs<std::optional<double>>(
rt, value.getProperty(rt, "processingStart"), jsInvoker),
bridging::fromJs<std::optional<double>>(
rt, value.getProperty(rt, "processingEnd"), jsInvoker),
bridging::fromJs<std::optional<double>>(
rt, value.getProperty(rt, "interactionId"), jsInvoker),
};
return result;
}
static jsi::Object toJs(jsi::Runtime &rt, const RawPerformanceEntry &value) {
auto result = facebook::jsi::Object(rt);
result.setProperty(rt, "name", bridging::toJs(rt, value.name));
result.setProperty(rt, "entryType", bridging::toJs(rt, value.entryType));
result.setProperty(rt, "startTime", bridging::toJs(rt, value.startTime));
result.setProperty(rt, "duration", bridging::toJs(rt, value.duration));
if (value.processingStart) {
result.setProperty(
rt,
"processingStart",
bridging::toJs(rt, value.processingStart.value()));
}
if (value.processingEnd) {
result.setProperty(
rt, "processingEnd", bridging::toJs(rt, value.processingEnd.value()));
}
if (value.interactionId) {
result.setProperty(
rt, "interactionId", bridging::toJs(rt, value.interactionId.value()));
}
return result;
}
};
} // namespace facebook::react