• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 NAPI_API_FUNCTION_CONTEXT_H
17 #define NAPI_API_FUNCTION_CONTEXT_H
18 
19 #ifdef __OHOS_PLATFORM__
20 #include "napi/native_api.h"
21 #else
22 #include <node_api.h>
23 #endif
24 
25 #include <base/containers/string.h>
26 
27 #include "env.h"
28 #include "object.h"
29 #include "utils.h"
30 #include "value.h"
31 
32 namespace NapiApi {
33 
34 // Should the requested arg count match the provided count or do we allow partial requests.
35 enum class ArgCount { EXACT, PARTIAL };
36 
37 template<typename... RequestedArgs>
38 class FunctionContext {
39 public:
40     FunctionContext(const napi_env env, const napi_callback_info info, ArgCount argMode = ArgCount::EXACT)
41     {
42         if ((!env) || (!info)) {
43             return;
44         }
45         napi_status status { napi_ok };
46         status = napi_get_cb_info(env, info, &providedArgCount_, nullptr, &jsThis_, &data_);
47         if (status != napi_ok) {
48             return;
49         }
50         env_ = NapiApi::Env(env);
51         info_ = info;
52         if constexpr (sizeof...(RequestedArgs) > 0) {
53             // validate arg count first
54             const bool exactOk = argMode == ArgCount::EXACT && requestedArgCount_ == providedArgCount_;
55             const bool partialOk = argMode == ArgCount::PARTIAL && requestedArgCount_ <= providedArgCount_;
56             if (!exactOk && !partialOk) {
57                 jsThis_ = nullptr;
58                 data_ = nullptr;
59                 info_ = nullptr;
60                 return;
61             }
62 
63             // get the arguments
64             auto getThisManyArgs = requestedArgCount_; // The napi call needs a non-const.
65             status = napi_get_cb_info(env, info, &getThisManyArgs, args, nullptr, nullptr);
66             if (!validate<RequestedArgs...>(0)) {
67                 // non matching types in context!
68                 jsThis_ = nullptr;
69                 data_ = nullptr;
70                 info_ = nullptr;
71                 return;
72             }
73         }
74     }
75 
76     template<typename... Other>
FunctionContext(const FunctionContext<Other...> & other)77     FunctionContext(const FunctionContext<Other...>& other) : FunctionContext(other.GetEnv(), other.GetInfo())
78     {}
79 
80     operator bool() const
81     {
82         return (env_ && info_);
83     }
84 
GetData()85     void* GetData() const
86     {
87         return data_;
88     }
89 
Env()90     NapiApi::Env Env() const
91     {
92         return env_;
93     }
94 
GetEnv()95     napi_env GetEnv() const
96     {
97         return env_;
98     }
99 
GetInfo()100     napi_callback_info GetInfo() const
101     {
102         return info_;
103     }
104 
This()105     NapiApi::Object This()
106     {
107         return { env_, jsThis_ };
108     }
109 
value(size_t index)110     napi_value value(size_t index)
111     {
112         if (index < requestedArgCount_) {
113             return args[index];
114         }
115         return nullptr;
116     }
117 
118     template<size_t I, typename T, typename... TypesI>
119     struct GetTypeImpl {
120         using type = typename GetTypeImpl<I - 1, TypesI...>::type;
121     };
122 
123     template<typename T, typename... TypesI>
124     struct GetTypeImpl<0, T, TypesI...> {
125         using type = T;
126     };
127 
128     template<size_t index>
129     auto Arg()
130     {
131         if constexpr (sizeof...(RequestedArgs) > 0) {
132             if constexpr (index < sizeof...(RequestedArgs)) {
133                 return NapiApi::Value<typename GetTypeImpl<index, RequestedArgs...>::type> { env_, args[index] };
134             }
135             if constexpr (index >= sizeof...(RequestedArgs)) {
136                 static_assert(index < sizeof...(RequestedArgs), "Index out of range !");
137                 return NapiApi::Value<void*>((napi_env) nullptr, (void*)nullptr);
138             }
139         }
140         if constexpr (sizeof...(RequestedArgs) == 0) {
141             return;
142         }
143     }
144 
145     size_t ArgCount() const
146     {
147         return providedArgCount_;
148     }
149 
150     napi_value GetUndefined()
151     {
152         return env_.GetUndefined();
153     }
154 
155     napi_value GetNull()
156     {
157         return env_.GetNull();
158     }
159 
160     napi_value GetBoolean(bool value)
161     {
162         return env_.GetBoolean(value);
163     }
164 
165     napi_value GetNumber(int32_t value)
166     {
167         return env_.GetNumber(value);
168     }
169 
170     napi_value GetNumber(uint32_t value)
171     {
172         return env_.GetNumber(value);
173     }
174 
175     napi_value GetNumber(float value)
176     {
177         return env_.GetNumber(value);
178     }
179 
180     napi_value GetNumber(double value)
181     {
182         return env_.GetNumber(value);
183     }
184 
185     napi_value GetString(const BASE_NS::string_view value)
186     {
187         return env_.GetString(value);
188     }
189 
190 private:
191     template<typename First, typename... Rest>
192     inline bool validate(size_t index)
193     {
194         napi_valuetype jstype;
195         napi_status status = napi_invalid_arg;
196         status = napi_typeof(env_, args[index], &jstype);
197         bool isArray = false;
198         napi_is_array(env_, args[index], &isArray);
199 
200         bool ret = NapiApi::ValidateType<First>(jstype, isArray);
201         if (ret) {
202             if constexpr (sizeof...(Rest) == 0) {
203                 return true;
204             }
205             if constexpr (sizeof...(Rest) > 0) {
206                 return validate<Rest...>(index + 1);
207             }
208         }
209         return false;
210     }
211 
212     napi_value jsThis_ { nullptr };
213     void* data_ { nullptr };
214     // How many args we want to access from the JS function call.
215     const size_t requestedArgCount_ { sizeof...(RequestedArgs) };
216     napi_value args[sizeof...(RequestedArgs) + 1] {};
217     NapiApi::Env env_ { nullptr };
218     napi_callback_info info_ { nullptr };
219     // How many args actually were in the JS function call.
220     size_t providedArgCount_ { 0 };
221 };
222 
223 } // namespace NapiApi
224 
225 #endif
226