Skip to content

Commit

Permalink
feat: Allow User to extend enums
Browse files Browse the repository at this point in the history
  • Loading branch information
mrousavy committed Feb 22, 2024
1 parent ba2313a commit 1e19439
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 47 deletions.
59 changes: 16 additions & 43 deletions package/cpp/jsi/EnumMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,30 @@

#pragma once

#include "test/TestEnum.h"
#include <unordered_map>
#include <stdexcept>
#include <string>

namespace margelo {

using namespace facebook;
namespace EnumMapper {
// Add these two methods in namespace "EnumMapper" to allow parsing a custom enum:
// 1. `static void convertJSUnionToEnum(const std::string& inUnion, Enum* outEnum)`
// 2. `static void convertEnumToJSUnion(Enum inEnum, std::string* outUnion)`

static std::runtime_error invalidUnion(const std::string jsUnion) {
return std::runtime_error("Cannot convert JS Value to Enum: Invalid Union value passed! (\"" + jsUnion + "\")");
}
template <typename Enum> static std::runtime_error invalidEnum(Enum passedEnum) {
return std::runtime_error("Cannot convert Enum to JS Value: Invalid Enum passed! (Value #" + std::to_string(passedEnum) +
" does not exist in " + typeid(Enum).name() + ")");
}

template <typename Enum> struct EnumMapper {
static Enum fromJSUnion(const std::string&) {
static_assert(always_false<Enum>::value, "This type is not supported by the EnumMapper!");
return Enum();
static std::runtime_error invalidUnion(const std::string& passedUnion) {
return std::runtime_error("Cannot convert JS Value to Enum: Invalid Union value passed! (\"" + std::string(passedUnion) + "\")");
}
static std::string toJSUnion(Enum) {
static_assert(always_false<Enum>::value, "This type is not supported by the EnumMapper!");
return std::string();
static std::runtime_error invalidEnum(int passedEnum) {
return std::runtime_error("Cannot convert Enum to JS Value: Invalid Enum passed! (Value #" + std::to_string(passedEnum) + ")");
}

private:
template <typename> struct always_false : std::false_type {};
};

template <> struct EnumMapper<TestEnum> {
public:
static constexpr TestEnum fromJSUnion(const std::string& jsUnion) {
if (jsUnion == "first")
return FIRST;
if (jsUnion == "second")
return SECOND;
if (jsUnion == "third")
return THIRD;
throw invalidUnion(jsUnion);
static void convertJSUnionToEnum(const std::string& inUnion, int*) {
throw invalidUnion(inUnion);
}
static std::string toJSUnion(TestEnum value) {
switch (value) {
case FIRST:
return "first";
case SECOND:
return "second";
case THIRD:
return "third";
}
throw invalidEnum(value);

static void convertEnumToJSUnion(int inEnum, std::string*) {
throw invalidEnum(inEnum);
}
};
} // namespace EnumMapper

} // namespace margelo
9 changes: 6 additions & 3 deletions package/cpp/jsi/JSIConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,14 @@ template <typename TInner> struct JSIConverter<std::optional<TInner>> {
template <typename TEnum> struct JSIConverter<TEnum, std::enable_if_t<std::is_enum<TEnum>::value>> {
static TEnum fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
std::string string = arg.asString(runtime).utf8(runtime);
return EnumMapper<TEnum>::fromJSUnion(string);
TEnum outEnum;
EnumMapper::convertJSUnionToEnum(string, &outEnum);
return outEnum;
}
static jsi::Value toJSI(jsi::Runtime& runtime, TEnum arg) {
std::string string = EnumMapper<TEnum>::toJSUnion(arg);
return jsi::String::createFromUtf8(runtime, string);
std::string outUnion;
EnumMapper::convertEnumToJSUnion(arg, &outUnion);
return jsi::String::createFromUtf8(runtime, outUnion);
}
};

Expand Down
29 changes: 28 additions & 1 deletion package/cpp/test/TestEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,31 @@ namespace margelo {

enum TestEnum { FIRST, SECOND, THIRD };

}
namespace EnumMapper {
static void convertJSUnionToEnum(const std::string& inUnion, TestEnum* outEnum) {
if (inUnion == "first")
*outEnum = FIRST;
else if (inUnion == "second")
*outEnum = SECOND;
else if (inUnion == "third")
*outEnum = THIRD;
else
throw invalidUnion(inUnion);
}
static void convertEnumToJSUnion(TestEnum inEnum, std::string* outUnion) {
switch (inEnum) {
case FIRST:
*outUnion = "first";
break;
case SECOND:
*outUnion = "second";
break;
case THIRD:
*outUnion = "third";
break;
default:
throw invalidEnum(inEnum);
}
}
} // namespace EnumMapper
} // namespace margelo

0 comments on commit 1e19439

Please sign in to comment.