18#define JS_KV_PERMISSION_ERROR_HELPER(C_FUNC_NAME, JS_METHOD_NAME) \
19 static JSValue C_FUNC_NAME( \
20 JSContext* ctx, JSValueConst this_val, int, JSValueConst*) \
22 js::core::Context& jsctx = *(js::core::Context*)JS_GetContextOpaque(ctx); \
23 const auto table_name = \
24 jsctx.to_str(JS_GetPropertyStr(jsctx, this_val, "_map_name")) \
26 if (table_name.empty()) \
28 return JS_ThrowTypeError(ctx, "Internal: No map name stored on handle"); \
30 auto func = jsctx.get_property(this_val, JS_METHOD_NAME); \
31 std::string explanation; \
32 auto error_msg = func["_error_msg"]; \
33 if (!error_msg.is_undefined()) \
35 explanation = jsctx.to_str(error_msg).value_or(""); \
37 return JS_ThrowTypeError( \
39 "Cannot call " #JS_METHOD_NAME " on table named %s. %s", \
41 explanation.c_str()); \
52 js_kv_get_version_of_previous_write_denied, "getVersionOfPreviousWrite")
53#undef JS_KV_PERMISSION_ERROR_HELPER
55#define JS_CHECK_HANDLE(h) \
60 return JS_ThrowInternalError( \
61 ctx, "Internal: Unable to access MapHandle"); \
65 template <ROHandleGetter GetReadOnlyHandle>
66 static JSValue js_kv_map_has(
73 return JS_ThrowTypeError(
74 ctx,
"Passed %d arguments, but expected 1",
argc);
82 return JS_ThrowTypeError(ctx,
"Argument must be an ArrayBuffer");
93 template <ROHandleGetter GetReadOnlyHandle>
94 static JSValue js_kv_map_get(
101 return JS_ThrowTypeError(
102 ctx,
"Passed %d arguments, but expected 1",
argc);
110 return JS_ThrowTypeError(ctx,
"Argument must be an ArrayBuffer");
118 if (!val.has_value())
120 return ccf::js::core::constants::Undefined;
130 template <ROHandleGetter GetReadOnlyHandle>
131 static JSValue js_kv_get_version_of_previous_write(
134 js::core::Context& jsctx = *(js::core::Context*)JS_GetContextOpaque(ctx);
138 return JS_ThrowTypeError(
139 ctx,
"Passed %d arguments, but expected 1",
argc);
147 return JS_ThrowTypeError(ctx,
"Argument must be an ArrayBuffer");
155 if (!val.has_value())
157 return ccf::js::core::constants::Undefined;
160 return JS_NewInt64(ctx, val.value());
163 template <ROHandleGetter GetReadOnlyHandle>
164 static JSValue js_kv_map_size_getter(
165 JSContext* ctx, JSValueConst
this_val,
int argc, JSValueConst*)
167 js::core::Context& jsctx = *(js::core::Context*)JS_GetContextOpaque(ctx);
172 const uint64_t size =
handle->size();
173 if (size > INT64_MAX)
175 return JS_ThrowInternalError(
176 ctx,
"Map size (%lu) is too large to represent in int64", size);
179 return JS_NewInt64(ctx, (int64_t)size);
182 template <RWHandleGetter GetWriteHandle>
183 static JSValue js_kv_map_delete(
186 js::core::Context& jsctx = *(js::core::Context*)JS_GetContextOpaque(ctx);
190 return JS_ThrowTypeError(
191 ctx,
"Passed %d arguments, but expected 1",
argc);
199 return JS_ThrowTypeError(ctx,
"Argument must be an ArrayBuffer");
207 return ccf::js::core::constants::Undefined;
210 template <RWHandleGetter GetWriteHandle>
211 static JSValue js_kv_map_set(
214 js::core::Context& jsctx = *(js::core::Context*)JS_GetContextOpaque(ctx);
218 return JS_ThrowTypeError(
219 ctx,
"Passed %d arguments, but expected 2",
argc);
226 uint8_t* val = JS_GetArrayBuffer(ctx, &val_size,
argv[1]);
230 return JS_ThrowTypeError(ctx,
"Arguments must be ArrayBuffers");
241 template <RWHandleGetter GetWriteHandle>
242 static JSValue js_kv_map_clear(
245 js::core::Context& jsctx = *(js::core::Context*)JS_GetContextOpaque(ctx);
249 return JS_ThrowTypeError(
250 ctx,
"Passed %d arguments, but expected 0",
argc);
258 return ccf::js::core::constants::Undefined;
261 template <ROHandleGetter GetReadOnlyHandle>
262 static JSValue js_kv_map_foreach(
265 js::core::Context& jsctx = *(js::core::Context*)JS_GetContextOpaque(ctx);
268 return JS_ThrowTypeError(
269 ctx,
"Passed %d arguments, but expected 1",
argc);
271 js::core::JSWrappedValue func(ctx,
argv[0]);
272 js::core::JSWrappedValue obj(ctx,
this_val);
274 if (!JS_IsFunction(ctx, func.val))
276 return JS_ThrowTypeError(ctx,
"Argument must be a function");
284 [&jsctx, &obj, &func, &failed](
const auto& k,
const auto& v) {
285 auto value = jsctx.new_array_buffer_copy(v.data(), v.size());
286 if (value.is_exception())
291 auto key = jsctx.new_array_buffer_copy(k.data(), k.size());
292 if (
key.is_exception())
298 std::vector<js::core::JSWrappedValue> args = {value,
key, obj};
300 auto val = jsctx.inner_call(func, args);
302 if (val.is_exception())
313 return ccf::js::core::constants::Exception;
316 return ccf::js::core::constants::Undefined;
318#undef JS_CHECK_HANDLE
320 template <ROHandleGetter GetReadOnlyHandle, RWHandleGetter GetWriteHandle>
321 static JSValue create_kv_map_handle(
322 js::core::Context& ctx,
323 const std::string& map_name,
325 const std::string& permission_explanation)
335 auto map_name_val = ctx.new_string(map_name);
337 JS_CHECK_SET(view_val.set(
"_map_name", std::move(map_name_val)));
344#define MAKE_FUNCTION( \
348 FUNC_FACTORY_METHOD, \
355 const auto permitted = \
356 ccf::js::intersect_access_permissions( \
357 access_permission, PERMISSION_FLAGS) != KVAccessPermissions::ILLEGAL; \
358 auto fn_val = ctx.FUNC_FACTORY_METHOD( \
359 !permitted ? C_FUNC_NAME##_denied : C_FUNC_NAME<HANDLE_GETTER>, \
362 JS_CHECK_EXC(fn_val); \
366 fn_val.set("_error_msg", ctx.new_string(permission_explanation))); \
368 JS_CHECK_SET(view_val.SETTER_METHOD(JS_METHOD_NAME, std::move(fn_val))); \
371#define MAKE_READ_FUNCTION(C_FUNC_NAME, JS_METHOD_NAME, ARG_COUNT) \
378 KVAccessPermissions::READ_ONLY, \
381#define MAKE_WRITE_FUNCTION(C_FUNC_NAME, JS_METHOD_NAME, ARG_COUNT) \
388 KVAccessPermissions::WRITE_ONLY, \
396 js_kv_get_version_of_previous_write,
"getVersionOfPreviousWrite", 1);
404 js_kv_map_size_getter,
407 new_getter_c_function,
412#undef MAKE_RW_FUNCTION
413#undef MAKE_RO_FUNCTION
416 return view_val.take();
JSWrappedValue new_array_buffer_copy(const uint8_t *buf, size_t buf_len) const
Definition context.cpp:332