Skip to content
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

feat: Add enums to the HybridObject #7

Merged
merged 3 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions package/cpp/jsi/EnumMapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// Created by Marc Rousavy on 22.02.24.
//

#pragma once

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

namespace margelo {

using namespace facebook;

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::string toJSUnion(Enum) {
static_assert(always_false<Enum>::value, "This type is not supported by the EnumMapper!");
return std::string();
}

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 std::string toJSUnion(TestEnum value) {
switch (value) {
case FIRST:
return "first";
case SECOND:
return "second";
case THIRD:
return "third";
}
throw invalidEnum(value);
}
};

} // namespace margelo
12 changes: 12 additions & 0 deletions package/cpp/jsi/JSIConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

#include "EnumMapper.h"
#include "HybridObject.h"
#include <array>
#include <jsi/jsi.h>
Expand Down Expand Up @@ -100,6 +101,17 @@ 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);
}
static jsi::Value toJSI(jsi::Runtime& runtime, TEnum arg) {
std::string string = EnumMapper<TEnum>::toJSUnion(arg);
return jsi::String::createFromUtf8(runtime, string);
}
};

template <typename ReturnType, typename... Args> struct JSIConverter<std::function<ReturnType(Args...)>> {
static std::function<ReturnType(Args...)> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
jsi::Function function = arg.asObject(runtime).asFunction(runtime);
Expand Down
13 changes: 13 additions & 0 deletions package/cpp/test/TestEnum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// Created by Marc Rousavy on 22.02.24.
//

#pragma once

#include "jsi/EnumMapper.h"

namespace margelo {

enum TestEnum { FIRST, SECOND, THIRD };

}
3 changes: 3 additions & 0 deletions package/cpp/test/TestHybridObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ void TestHybridObject::loadHybridMethods() {
// this.string get & set
registerHybridGetter("string", &TestHybridObject::getString, this);
registerHybridSetter("string", &TestHybridObject::setString, this);
// this.enum
registerHybridGetter("enum", &TestHybridObject::getEnum, this);
registerHybridSetter("enum", &TestHybridObject::setEnum, this);
// methods
registerHybridMethod("multipleArguments", &TestHybridObject::multipleArguments, this);
// callbacks
Expand Down
8 changes: 8 additions & 0 deletions package/cpp/test/TestHybridObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

#include "TestEnum.h"
#include "jsi/HybridObject.h"
#include <string>
#include <vector>
Expand All @@ -24,6 +25,12 @@ class TestHybridObject : public HybridObject {
void setString(std::string newValue) {
_string = newValue;
}
void setEnum(TestEnum testEnum) {
_enum = testEnum;
}
TestEnum getEnum() {
return _enum;
}

std::unordered_map<std::string, double> multipleArguments(int first, bool second, std::string third) {
return std::unordered_map<std::string, double>{{"first", 5312}, {"second", 532233}, {"third", 2786}};
Expand All @@ -42,6 +49,7 @@ class TestHybridObject : public HybridObject {
private:
int _int;
std::string _string;
TestEnum _enum;

void loadHybridMethods() override;
};
Expand Down
1 change: 1 addition & 0 deletions package/src/native/FilamentProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface TestHybridObject {
getIntGetter(): () => number
sayHelloCallback(callback: () => string): void
createNewHybridObject: () => TestHybridObject
enum: 'first' | 'second' | 'third'
}

export interface TFilamentProxy {
Expand Down
13 changes: 9 additions & 4 deletions package/src/test/TestHybridObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,26 @@ export function testHybridObject() {
hybridObject.int = 6723
console.log(`New Int: ${hybridObject.int}`)

// 4. String Getter & Setter
// 4. Enum Getter & Setter
console.log(`Enum: ${hybridObject.enum}`)
hybridObject.enum = 'second'
console.log(`New Enum: ${hybridObject.enum}`)

// 5. String Getter & Setter
console.log(`String: ${hybridObject.string}`)
hybridObject.string = 'new string value!'
console.log(`New String: ${hybridObject.string}`)

// 5. Testing multiple arguments and maps
// 6. Testing multiple arguments and maps
const result = hybridObject.multipleArguments(5, true, 'hahah!')
console.log(`multipleArguments() -> ${JSON.stringify(result)}`)

// 6. Testing callbacks
// 7. Testing callbacks
hybridObject.sayHelloCallback(() => 'hello from JS!')
const getter = hybridObject.getIntGetter()
console.log(`Int getter: ${getter()}`)

// 7. Create a new one
// 8. Create a new one
const newObject = hybridObject.createNewHybridObject()
console.log(`Created new hybrid object!`, newObject)

Expand Down
Loading