1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef OHOS_FFI_CJ_LAMBDA_H
17 #define OHOS_FFI_CJ_LAMBDA_H
18 
19 #include <cstdint>
20 #include <tuple>
21 
22 #include "ffi_remote_data.h"
23 
24 #ifndef FFI_EXPORT
25 #ifndef WINDOWS_PLATFORM
26 #define FFI_EXPORT __attribute__((visibility("default")))
27 #else
28 #define FFI_EXPORT __declspec(dllexport)
29 #endif
30 #endif
31 
32 class FFI_EXPORT CJLambda {
33     template <size_t I>
34     struct TupleRuntimeHelper {
35         template <typename T>
GetElementAddrTupleRuntimeHelper36         static void* GetElementAddr(T& tup, size_t idx)
37         {
38             if (idx == I - 1) {
39                 return &(std::get<I - 1>(tup));
40             } else {
41                 return TupleRuntimeHelper<I - 1>::GetElementAddr(tup, idx);
42             }
43         }
44     };
45 
46     template <>
47     struct TupleRuntimeHelper<0> {
48         template <typename T>
49         static void* GetElementAddr(T& tup, size_t idx)
50         {
51             // Unreachable
52             return nullptr;
53         }
54     };
55 
56     template <typename... Types>
57     static inline void* GetElementAddr(std::tuple<Types...> const& tup, size_t idx)
58     {
59         return TupleRuntimeHelper<sizeof...(Types)>::GetElementAddr(tup, idx);
60     }
61 
62     template <typename... Types>
63     static inline void* GetElementAddr(std::tuple<Types...>& tup, size_t idx)
64     {
65         return TupleRuntimeHelper<sizeof...(Types)>::GetElementAddr(tup, idx);
66     }
67 public:
68     template<class... I>
69     static std::function<void(I...)> Create(void (*callback)(I...))
70     {
71         auto handle = OHOS::FFI::RemoteData::Create<OHOS::FFI::CJLambdaRemoteData>(reinterpret_cast<int64_t>(callback));
72         return [handle](I...args) -> void {
73             constexpr int32_t argc = std::tuple_size_v<std::tuple<I...>>;
74             if (argc == 0) {
75                 InvokeLambda(handle->GetID(), argc, nullptr, nullptr);
76                 return;
77             }
78             auto argsTuple = std::make_tuple(args...);
79             void* argv[argc];
80             for (size_t i = 0; i < argc; ++i) {
81                 argv[i] = GetElementAddr(argsTuple, i);
82             }
83             InvokeLambda(handle->GetID(), argc, argv, nullptr);
84         };
85     }
86 
87     template<class... I, class R>
88     static std::function<R(I...)> Create(R (*callback)(I...))
89     {
90         auto handle = OHOS::FFI::RemoteData::Create<OHOS::FFI::CJLambdaRemoteData>(reinterpret_cast<int64_t>(callback));
91         return [handle](I...args) -> R {
92             R res;
93             constexpr int32_t argc = std::tuple_size_v<std::tuple<I...>>;
94             if (argc == 0) {
95                 InvokeLambda(handle->GetID(), argc, nullptr, &res);
96                 return res;
97             }
98             auto argsTuple = std::make_tuple(args...);
99             void* argv[argc];
100             for (size_t i = 0; i < argc; ++i) {
101                 argv[i] = GetElementAddr(argsTuple, i);
102             }
103             InvokeLambda(handle->GetID(), argc, argv, &res);
104             return res;
105         };
106     }
107 
108 private:
109     static inline void InvokeLambda(int64_t lambdaId, int32_t argc, void** argv, void* result)
110     {
111         auto invoker = CJFFIFnInvoker::GetInstance()->GetCJFuncs().atCOHOSFFICallbackInvoker;
112         invoker(lambdaId, argc, argv, result);
113     }
114 };
115 
116 #endif // OHOS_FFI_CJ_LAMBDA_H
117