mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Generate enum types that would be allowed to be used as well as string/number in c++ turbo modules generators (#36030)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/36030 Generate enum types in c++ turbo modules. For enums in the ts schema file such as: ``` export enum NumEnum { ONE = 1, TWO = 2, } ``` This would export enums and the relevant Bridging to js and from js code to the spec H files such as: ``` #pragma mark - SampleTurboModuleCxxNumEnum enum SampleTurboModuleCxxNumEnum { ONE, TWO }; template <> struct Bridging<SampleTurboModuleCxxNumEnum> { static SampleTurboModuleCxxNumEnum fromJs(jsi::Runtime &rt, int32_t value) { if (value == 1) { return SampleTurboModuleCxxNumEnum::ONE; } else if (value == 2) { return SampleTurboModuleCxxNumEnum::TWO; } else { throw jsi::JSError(rt, "No appropriate enum member found for value"); } } static jsi::Value toJs(jsi::Runtime &rt, SampleTurboModuleCxxNumEnum value) { if (value == SampleTurboModuleCxxNumEnum::ONE) { return bridging::toJs(rt, 1); } else if (value == SampleTurboModuleCxxNumEnum::TWO) { return bridging::toJs(rt, 2); } else { throw jsi::JSError(rt, "No appropriate enum member found for enum value"); } } }; ``` That code would allow us to use these enums in the cxx files like this: ``` NativeCxxModuleExampleCxxEnumInt getNumEnum( jsi::Runtime &rt, NativeCxxModuleExampleCxxEnumInt arg); ``` Changelog: [General] [Added] Generate enum types that would be allowed to be used as well as string/number in c++ turbo modules generators Reviewed By: christophpurrer Differential Revision: D42884147 fbshipit-source-id: d34d1fc7ba268b570821dc108444196f69a431b2
This commit is contained in:
committed by
Facebook GitHub Bot
parent
bf3656b758
commit
ceb1d0dea6
@@ -17,10 +17,20 @@ import type {
|
||||
NativeModuleFunctionTypeAnnotation,
|
||||
NativeModulePropertyShape,
|
||||
NativeModuleAliasMap,
|
||||
NativeModuleEnumMap,
|
||||
NativeModuleEnumMembers,
|
||||
NativeModuleEnumMemberType,
|
||||
} from '../../CodegenSchema';
|
||||
|
||||
import type {AliasResolver} from './Utils';
|
||||
const {createAliasResolver, getModules} = require('./Utils');
|
||||
|
||||
const {getEnumName, toSafeCppString} = require('../Utils');
|
||||
|
||||
const {
|
||||
createAliasResolver,
|
||||
getModules,
|
||||
getAreEnumMembersInteger,
|
||||
} = require('./Utils');
|
||||
const {indent} = require('../Utils');
|
||||
const {unwrapNullable} = require('../../parsers/parsers-commons');
|
||||
|
||||
@@ -30,12 +40,15 @@ const ModuleClassDeclarationTemplate = ({
|
||||
hasteModuleName,
|
||||
moduleProperties,
|
||||
structs,
|
||||
enums,
|
||||
}: $ReadOnly<{
|
||||
hasteModuleName: string,
|
||||
moduleProperties: string[],
|
||||
structs: string,
|
||||
enums: string,
|
||||
}>) => {
|
||||
return `${structs}class JSI_EXPORT ${hasteModuleName}CxxSpecJSI : public TurboModule {
|
||||
return `${enums}
|
||||
${structs}class JSI_EXPORT ${hasteModuleName}CxxSpecJSI : public TurboModule {
|
||||
protected:
|
||||
${hasteModuleName}CxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker);
|
||||
|
||||
@@ -112,10 +125,12 @@ ${modules.join('\n\n')}
|
||||
};
|
||||
|
||||
function translatePrimitiveJSTypeToCpp(
|
||||
moduleName: string,
|
||||
nullableTypeAnnotation: Nullable<NativeModuleTypeAnnotation>,
|
||||
optional: boolean,
|
||||
createErrorMessage: (typeName: string) => string,
|
||||
resolveAlias: AliasResolver,
|
||||
enumMap: NativeModuleEnumMap,
|
||||
) {
|
||||
const [typeAnnotation, nullable] = unwrapNullable<NativeModuleTypeAnnotation>(
|
||||
nullableTypeAnnotation,
|
||||
@@ -157,7 +172,11 @@ function translatePrimitiveJSTypeToCpp(
|
||||
case 'EnumDeclaration':
|
||||
switch (realTypeAnnotation.memberType) {
|
||||
case 'NumberTypeAnnotation':
|
||||
return wrap('double');
|
||||
return getAreEnumMembersInteger(
|
||||
enumMap[realTypeAnnotation.name].members,
|
||||
)
|
||||
? wrap('int')
|
||||
: wrap('double');
|
||||
case 'StringTypeAnnotation':
|
||||
return wrap('jsi::String');
|
||||
default:
|
||||
@@ -192,10 +211,11 @@ function translatePrimitiveJSTypeToCpp(
|
||||
}
|
||||
}
|
||||
|
||||
function createStructs(
|
||||
function createStructsString(
|
||||
moduleName: string,
|
||||
aliasMap: NativeModuleAliasMap,
|
||||
resolveAlias: AliasResolver,
|
||||
enumMap: NativeModuleEnumMap,
|
||||
): string {
|
||||
return Object.keys(aliasMap)
|
||||
.map(alias => {
|
||||
@@ -213,11 +233,13 @@ function createStructs(
|
||||
const paramemterConversion = value.properties
|
||||
.map((v, i) => {
|
||||
const translatedParam = translatePrimitiveJSTypeToCpp(
|
||||
moduleName,
|
||||
v.typeAnnotation,
|
||||
false,
|
||||
typeName =>
|
||||
`Unsupported type for param "${v.name}". Found: ${typeName}`,
|
||||
resolveAlias,
|
||||
enumMap,
|
||||
);
|
||||
return ` static ${translatedParam} ${v.name}ToJs(jsi::Runtime &rt, P${i} value) {
|
||||
return bridging::toJs(rt, value);
|
||||
@@ -281,9 +303,128 @@ ${paramemterConversion}
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
type NativeEnumMemberValueType = 'std::string' | 'int32_t' | 'float';
|
||||
|
||||
const EnumTemplate = ({
|
||||
enumName,
|
||||
values,
|
||||
fromCases,
|
||||
toCases,
|
||||
nativeEnumMemberType,
|
||||
}: {
|
||||
enumName: string,
|
||||
values: string,
|
||||
fromCases: string,
|
||||
toCases: string,
|
||||
nativeEnumMemberType: NativeEnumMemberValueType,
|
||||
}) => {
|
||||
const fromValue =
|
||||
nativeEnumMemberType === 'std::string'
|
||||
? 'const jsi::String &rawValue'
|
||||
: `${nativeEnumMemberType} value`;
|
||||
|
||||
const fromValueConvertion =
|
||||
nativeEnumMemberType === 'std::string'
|
||||
? 'std::string value = rawValue.utf8(rt);'
|
||||
: '';
|
||||
|
||||
const toValue =
|
||||
nativeEnumMemberType === 'std::string' ? 'jsi::String' : 'jsi::Value';
|
||||
|
||||
return `
|
||||
#pragma mark - ${enumName}
|
||||
|
||||
enum ${enumName} { ${values} };
|
||||
|
||||
template <>
|
||||
struct Bridging<${enumName}> {
|
||||
static ${enumName} fromJs(jsi::Runtime &rt, ${fromValue}) {
|
||||
${fromValueConvertion}
|
||||
${fromCases}
|
||||
}
|
||||
|
||||
static ${toValue} toJs(jsi::Runtime &rt, ${enumName} value) {
|
||||
${toCases}
|
||||
}
|
||||
};`;
|
||||
};
|
||||
|
||||
function generateEnum(
|
||||
moduleName: string,
|
||||
origEnumName: string,
|
||||
members: NativeModuleEnumMembers,
|
||||
memberType: NativeModuleEnumMemberType,
|
||||
): string {
|
||||
const enumName = getEnumName(moduleName, origEnumName);
|
||||
|
||||
const nativeEnumMemberType: NativeEnumMemberValueType =
|
||||
memberType === 'StringTypeAnnotation'
|
||||
? 'std::string'
|
||||
: getAreEnumMembersInteger(members)
|
||||
? 'int32_t'
|
||||
: 'float';
|
||||
|
||||
const getMemberValueAppearance = (value: string) =>
|
||||
memberType === 'StringTypeAnnotation'
|
||||
? `"${value}"`
|
||||
: `${value}${nativeEnumMemberType === 'float' ? 'f' : ''}`;
|
||||
|
||||
const fromCases =
|
||||
members
|
||||
.map(
|
||||
member => `if (value == ${getMemberValueAppearance(member.value)}) {
|
||||
return ${enumName}::${toSafeCppString(member.name)};
|
||||
}`,
|
||||
)
|
||||
.join(' else ') +
|
||||
` else {
|
||||
throw jsi::JSError(rt, "No appropriate enum member found for value");
|
||||
}`;
|
||||
|
||||
const toCases =
|
||||
members
|
||||
.map(
|
||||
member => `if (value == ${enumName}::${toSafeCppString(member.name)}) {
|
||||
return bridging::toJs(rt, ${getMemberValueAppearance(member.value)});
|
||||
}`,
|
||||
)
|
||||
.join(' else ') +
|
||||
` else {
|
||||
throw jsi::JSError(rt, "No appropriate enum member found for enum value");
|
||||
}`;
|
||||
|
||||
return EnumTemplate({
|
||||
enumName,
|
||||
values: members.map(member => member.name).join(', '),
|
||||
fromCases,
|
||||
toCases,
|
||||
nativeEnumMemberType,
|
||||
});
|
||||
}
|
||||
|
||||
function createEnums(
|
||||
moduleName: string,
|
||||
enumMap: NativeModuleEnumMap,
|
||||
resolveAlias: AliasResolver,
|
||||
): string {
|
||||
return Object.entries(enumMap)
|
||||
.map(([enumName, enumNode]) => {
|
||||
return generateEnum(
|
||||
moduleName,
|
||||
enumName,
|
||||
enumNode.members,
|
||||
enumNode.memberType,
|
||||
);
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function translatePropertyToCpp(
|
||||
moduleName: string,
|
||||
prop: NativeModulePropertyShape,
|
||||
resolveAlias: AliasResolver,
|
||||
enumMap: NativeModuleEnumMap,
|
||||
abstract: boolean = false,
|
||||
) {
|
||||
const [propTypeAnnotation] =
|
||||
@@ -295,20 +436,24 @@ function translatePropertyToCpp(
|
||||
|
||||
const paramTypes = propTypeAnnotation.params.map(param => {
|
||||
const translatedParam = translatePrimitiveJSTypeToCpp(
|
||||
moduleName,
|
||||
param.typeAnnotation,
|
||||
param.optional,
|
||||
typeName =>
|
||||
`Unsupported type for param "${param.name}" in ${prop.name}. Found: ${typeName}`,
|
||||
resolveAlias,
|
||||
enumMap,
|
||||
);
|
||||
return `${translatedParam} ${param.name}`;
|
||||
});
|
||||
|
||||
const returnType = translatePrimitiveJSTypeToCpp(
|
||||
moduleName,
|
||||
propTypeAnnotation.returnTypeAnnotation,
|
||||
false,
|
||||
typeName => `Unsupported return type for ${prop.name}. Found: ${typeName}`,
|
||||
resolveAlias,
|
||||
enumMap,
|
||||
);
|
||||
|
||||
// The first param will always be the runtime reference.
|
||||
@@ -342,25 +487,39 @@ module.exports = {
|
||||
const modules = Object.keys(nativeModules).flatMap(hasteModuleName => {
|
||||
const {
|
||||
aliasMap,
|
||||
enumMap,
|
||||
spec: {properties},
|
||||
moduleName,
|
||||
} = nativeModules[hasteModuleName];
|
||||
const resolveAlias = createAliasResolver(aliasMap);
|
||||
const structs = createStructs(moduleName, aliasMap, resolveAlias);
|
||||
const structs = createStructsString(
|
||||
moduleName,
|
||||
aliasMap,
|
||||
resolveAlias,
|
||||
enumMap,
|
||||
);
|
||||
const enums = createEnums(moduleName, enumMap, resolveAlias);
|
||||
|
||||
return [
|
||||
ModuleClassDeclarationTemplate({
|
||||
hasteModuleName,
|
||||
moduleProperties: properties.map(prop =>
|
||||
translatePropertyToCpp(prop, resolveAlias, true),
|
||||
translatePropertyToCpp(
|
||||
moduleName,
|
||||
prop,
|
||||
resolveAlias,
|
||||
enumMap,
|
||||
true,
|
||||
),
|
||||
),
|
||||
structs,
|
||||
enums,
|
||||
}),
|
||||
ModuleSpecClassDeclarationTemplate({
|
||||
hasteModuleName,
|
||||
moduleName,
|
||||
moduleProperties: properties.map(prop =>
|
||||
translatePropertyToCpp(prop, resolveAlias),
|
||||
translatePropertyToCpp(moduleName, prop, resolveAlias, enumMap),
|
||||
),
|
||||
}),
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user