133eb0b6dSopenharmony_ci/*
233eb0b6dSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
333eb0b6dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
433eb0b6dSopenharmony_ci * you may not use this file except in compliance with the License.
533eb0b6dSopenharmony_ci * You may obtain a copy of the License at
633eb0b6dSopenharmony_ci *
733eb0b6dSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
833eb0b6dSopenharmony_ci *
933eb0b6dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1033eb0b6dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1133eb0b6dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1233eb0b6dSopenharmony_ci * See the License for the specific language governing permissions and
1333eb0b6dSopenharmony_ci * limitations under the License.
1433eb0b6dSopenharmony_ci */
1533eb0b6dSopenharmony_ci
1633eb0b6dSopenharmony_ci#ifndef OHOS_FFI_CJ_LAMBDA_H
1733eb0b6dSopenharmony_ci#define OHOS_FFI_CJ_LAMBDA_H
1833eb0b6dSopenharmony_ci
1933eb0b6dSopenharmony_ci#include <cstdint>
2033eb0b6dSopenharmony_ci#include <tuple>
2133eb0b6dSopenharmony_ci
2233eb0b6dSopenharmony_ci#include "ffi_remote_data.h"
2333eb0b6dSopenharmony_ci
2433eb0b6dSopenharmony_ci#ifndef FFI_EXPORT
2533eb0b6dSopenharmony_ci#ifndef WINDOWS_PLATFORM
2633eb0b6dSopenharmony_ci#define FFI_EXPORT __attribute__((visibility("default")))
2733eb0b6dSopenharmony_ci#else
2833eb0b6dSopenharmony_ci#define FFI_EXPORT __declspec(dllexport)
2933eb0b6dSopenharmony_ci#endif
3033eb0b6dSopenharmony_ci#endif
3133eb0b6dSopenharmony_ci
3233eb0b6dSopenharmony_ciclass FFI_EXPORT CJLambda {
3333eb0b6dSopenharmony_ci    template <size_t I>
3433eb0b6dSopenharmony_ci    struct TupleRuntimeHelper {
3533eb0b6dSopenharmony_ci        template <typename T>
3633eb0b6dSopenharmony_ci        static void* GetElementAddr(T& tup, size_t idx)
3733eb0b6dSopenharmony_ci        {
3833eb0b6dSopenharmony_ci            if (idx == I - 1) {
3933eb0b6dSopenharmony_ci                return &(std::get<I - 1>(tup));
4033eb0b6dSopenharmony_ci            } else {
4133eb0b6dSopenharmony_ci                return TupleRuntimeHelper<I - 1>::GetElementAddr(tup, idx);
4233eb0b6dSopenharmony_ci            }
4333eb0b6dSopenharmony_ci        }
4433eb0b6dSopenharmony_ci    };
4533eb0b6dSopenharmony_ci
4633eb0b6dSopenharmony_ci    template <>
4733eb0b6dSopenharmony_ci    struct TupleRuntimeHelper<0> {
4833eb0b6dSopenharmony_ci        template <typename T>
4933eb0b6dSopenharmony_ci        static void* GetElementAddr(T& tup, size_t idx)
5033eb0b6dSopenharmony_ci        {
5133eb0b6dSopenharmony_ci            // Unreachable
5233eb0b6dSopenharmony_ci            return nullptr;
5333eb0b6dSopenharmony_ci        }
5433eb0b6dSopenharmony_ci    };
5533eb0b6dSopenharmony_ci
5633eb0b6dSopenharmony_ci    template <typename... Types>
5733eb0b6dSopenharmony_ci    static inline void* GetElementAddr(std::tuple<Types...> const& tup, size_t idx)
5833eb0b6dSopenharmony_ci    {
5933eb0b6dSopenharmony_ci        return TupleRuntimeHelper<sizeof...(Types)>::GetElementAddr(tup, idx);
6033eb0b6dSopenharmony_ci    }
6133eb0b6dSopenharmony_ci
6233eb0b6dSopenharmony_ci    template <typename... Types>
6333eb0b6dSopenharmony_ci    static inline void* GetElementAddr(std::tuple<Types...>& tup, size_t idx)
6433eb0b6dSopenharmony_ci    {
6533eb0b6dSopenharmony_ci        return TupleRuntimeHelper<sizeof...(Types)>::GetElementAddr(tup, idx);
6633eb0b6dSopenharmony_ci    }
6733eb0b6dSopenharmony_cipublic:
6833eb0b6dSopenharmony_ci    template<class... I>
6933eb0b6dSopenharmony_ci    static std::function<void(I...)> Create(void (*callback)(I...))
7033eb0b6dSopenharmony_ci    {
7133eb0b6dSopenharmony_ci        auto handle = OHOS::FFI::RemoteData::Create<OHOS::FFI::CJLambdaRemoteData>(reinterpret_cast<int64_t>(callback));
7233eb0b6dSopenharmony_ci        return [handle](I...args) -> void {
7333eb0b6dSopenharmony_ci            constexpr int32_t argc = std::tuple_size_v<std::tuple<I...>>;
7433eb0b6dSopenharmony_ci            if (argc == 0) {
7533eb0b6dSopenharmony_ci                InvokeLambda(handle->GetID(), argc, nullptr, nullptr);
7633eb0b6dSopenharmony_ci                return;
7733eb0b6dSopenharmony_ci            }
7833eb0b6dSopenharmony_ci            auto argsTuple = std::make_tuple(args...);
7933eb0b6dSopenharmony_ci            void* argv[argc];
8033eb0b6dSopenharmony_ci            for (size_t i = 0; i < argc; ++i) {
8133eb0b6dSopenharmony_ci                argv[i] = GetElementAddr(argsTuple, i);
8233eb0b6dSopenharmony_ci            }
8333eb0b6dSopenharmony_ci            InvokeLambda(handle->GetID(), argc, argv, nullptr);
8433eb0b6dSopenharmony_ci        };
8533eb0b6dSopenharmony_ci    }
8633eb0b6dSopenharmony_ci
8733eb0b6dSopenharmony_ci    template<class... I, class R>
8833eb0b6dSopenharmony_ci    static std::function<R(I...)> Create(R (*callback)(I...))
8933eb0b6dSopenharmony_ci    {
9033eb0b6dSopenharmony_ci        auto handle = OHOS::FFI::RemoteData::Create<OHOS::FFI::CJLambdaRemoteData>(reinterpret_cast<int64_t>(callback));
9133eb0b6dSopenharmony_ci        return [handle](I...args) -> R {
9233eb0b6dSopenharmony_ci            R res;
9333eb0b6dSopenharmony_ci            constexpr int32_t argc = std::tuple_size_v<std::tuple<I...>>;
9433eb0b6dSopenharmony_ci            if (argc == 0) {
9533eb0b6dSopenharmony_ci                InvokeLambda(handle->GetID(), argc, nullptr, &res);
9633eb0b6dSopenharmony_ci                return res;
9733eb0b6dSopenharmony_ci            }
9833eb0b6dSopenharmony_ci            auto argsTuple = std::make_tuple(args...);
9933eb0b6dSopenharmony_ci            void* argv[argc];
10033eb0b6dSopenharmony_ci            for (size_t i = 0; i < argc; ++i) {
10133eb0b6dSopenharmony_ci                argv[i] = GetElementAddr(argsTuple, i);
10233eb0b6dSopenharmony_ci            }
10333eb0b6dSopenharmony_ci            InvokeLambda(handle->GetID(), argc, argv, &res);
10433eb0b6dSopenharmony_ci            return res;
10533eb0b6dSopenharmony_ci        };
10633eb0b6dSopenharmony_ci    }
10733eb0b6dSopenharmony_ci
10833eb0b6dSopenharmony_ciprivate:
10933eb0b6dSopenharmony_ci    static inline void InvokeLambda(int64_t lambdaId, int32_t argc, void** argv, void* result)
11033eb0b6dSopenharmony_ci    {
11133eb0b6dSopenharmony_ci        auto invoker = CJFFIFnInvoker::GetInstance()->GetCJFuncs().atCOHOSFFICallbackInvoker;
11233eb0b6dSopenharmony_ci        invoker(lambdaId, argc, argv, result);
11333eb0b6dSopenharmony_ci    }
11433eb0b6dSopenharmony_ci};
11533eb0b6dSopenharmony_ci
11633eb0b6dSopenharmony_ci#endif // OHOS_FFI_CJ_LAMBDA_H
117