Skip to content

Commit

Permalink
Merge 2e67cc4 into ca170f6
Browse files Browse the repository at this point in the history
  • Loading branch information
LanderlYoung committed Apr 21, 2021
2 parents ca170f6 + 2e67cc4 commit 75d45c5
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 11 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:

jobs:
coverage-mac-clang:
timeout-minutes: 30
runs-on: macos-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -60,6 +61,7 @@ jobs:
parallel: true

coverage-finish:
timeout-minutes: 30
needs: coverage-mac-clang
runs-on: ubuntu-latest
steps:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/sync_to_tencent_code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:

jobs:
sync:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:

jobs:
mac-clang-run:
timeout-minutes: 30
runs-on: macos-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -49,6 +50,7 @@ jobs:
./UnitTests
windows-msvc-run:
timeout-minutes: 30
runs-on: windows-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -98,6 +100,7 @@ jobs:
${{ matrix.build_type }}/UnitTests
ubuntu-gcc-build:
timeout-minutes: 30
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -133,6 +136,7 @@ jobs:
# 1. we don't have android libraries
# 2. -undefined dynamic_lookup not work with NDK
if: ${{ false }}
timeout-minutes: 30
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -167,6 +171,7 @@ jobs:
cmake --build . -j $(nproc) --target UnitTests
node-gcc-run:
timeout-minutes: 30
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -190,6 +195,7 @@ jobs:
npm run test
webassembly-emscripten-run:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand Down
16 changes: 9 additions & 7 deletions src/Native.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,25 +513,27 @@ template <typename RetType, typename... Args>
std::enable_if_t<::script::converter::isConvertible<RetType> &&
isArgsConvertible<std::tuple<Args...>>,
std::function<RetType(Args...)>>
createFunctionWrapperInner(const Local<Function>& function, const std::tuple<Args...>*) {
createFunctionWrapperInner(const Local<Function>& function, const Local<Value>& thiz,
const std::tuple<Args...>*) {
using EngineImpl = typename ImplType<ScriptEngine>::type;
return std::function(
[f = Global<Function>(function),
[func = Global<Function>(function), receiver = Global<Value>(thiz),
engine = EngineScope::currentEngineAs<EngineImpl>()](Args... args) -> RetType {
// use EngineImpl to avoid possible dynamic_cast
EngineScope scope(engine);
auto ret = f.get().call({}, args...);
auto ret = func.get().call(receiver.getValue(), args...);
if constexpr (!std::is_void_v<RetType>) {
return ::script::converter::Converter<RetType>::toCpp(ret);
}
});
}

template <typename FuncType>
inline std::function<FuncType> createFunctionWrapper(const Local<Function>& function) {
inline std::function<FuncType> createFunctionWrapper(const Local<Function>& function,
const Local<Value>& thiz) {
using FC = traits::FunctionTrait<FuncType>;
return createFunctionWrapperInner<typename FC::ReturnType>(
function, static_cast<typename FC::Arguments*>(nullptr));
function, thiz, static_cast<typename FC::Arguments*>(nullptr));
}

} // namespace script::internal
Expand Down Expand Up @@ -585,8 +587,8 @@ Local<Function>::call(const Local<Value>& thiz, T&&... args) const {
}

template <typename FuncType>
std::function<FuncType> Local<Function>::wrapper() const {
return internal::createFunctionWrapper<FuncType>(*this);
std::function<FuncType> Local<Function>::wrapper(const Local<Value>& thiz) const {
return internal::createFunctionWrapper<FuncType>(*this, thiz);
}

template <typename... T>
Expand Down
14 changes: 10 additions & 4 deletions src/Reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,9 @@ class Local<Function> {
template <typename... T>
Local<Value> call(const Local<Value>& thiz, T&&... args) const;

/**
* helper function to call with null thiz(receiver) and no arguments.
*/
Local<Value> call() const { return call({}); }

/**
Expand All @@ -490,12 +493,15 @@ class Local<Function> {
* \endcode
*
* @tparam FuncType function signature, like "int(int, int)" or "std::string(const char*, int)"
* @param function a std::function
* @note the returned std::function holds a Global<Function> to this reference, and will be auto
* released when destroy engine, after that, the returned std::function is not valid anymore.
* @return a std::function
* @param thiz the receiver of the function, default to null
* @note the returned std::function holds a Global<Function> to the function and receiver
* reference, and will be auto released when destroy engine, after that, the returned
* std::function is not valid anymore.
*/
// implemented in Native.hpp
template <typename FuncType>
std::function<FuncType> wrapper() const; // implemented in Native.hpp
std::function<FuncType> wrapper(const Local<Value>& thiz = {}) const;

SPECIALIZE_NON_VALUE(Function)

Expand Down
26 changes: 26 additions & 0 deletions test/src/NativeTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,32 @@ TEST_F(NativeTest, FunctionWrapper) {
EXPECT_EQ(add(1, 1), 2) << "Out of EngineScope test";
}

TEST_F(NativeTest, FunctionWrapperReceiver) {
EngineScope scope(engine);
try {
auto func =
engine
->eval(
TS().js("(function () { if (this && this.num) return this.num; else return -1 ;})")
.lua("return function (self) if self ~= nil then return self.num else return "
"-1 end end")
.select())
.asFunction();

auto receiver =
engine->eval(TS().js("({ num: 42})").lua("num = {}; num.num = 42; return num;").select())
.asObject();

auto withReceiver = func.wrapper<int()>(receiver);
EXPECT_EQ(withReceiver(), 42);

auto noReceiver = func.wrapper<int()>();
EXPECT_EQ(noReceiver(), -1);
} catch (const Exception& e) {
FAIL() << e;
}
}

TEST_F(NativeTest, ValidateClassDefine) {
// static & instance are empty
EXPECT_THROW({ defineClass("hello").build(); }, std::runtime_error);
Expand Down

0 comments on commit 75d45c5

Please sign in to comment.