[gjs] arg: Automatically set all the numeric values to GIArguments
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] arg: Automatically set all the numeric values to GIArguments
- Date: Sun, 4 Oct 2020 23:35:56 +0000 (UTC)
commit 6698716c91d8a8b7a0cbd99dfff1de7c9be3c305
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date: Thu May 14 20:37:16 2020 +0200
arg: Automatically set all the numeric values to GIArguments
Use a template-function to convert all the JS Values to the proper c++
type and ensure they're within the valid ranges.
As per this we need to use a more relaxed conversion to unsigned types using
doubles not to have implicit conversion of negative types.
Use a function override in order to keep a more generic version as
inline implementation, while we specialize the out-of-range error
handling per type
gi/arg-inl.h | 23 ++++++++++
gi/arg.cpp | 135 +++++++++++++++++++++++-------------------------------
gi/js-value-inl.h | 30 ++++++++++++
3 files changed, 111 insertions(+), 77 deletions(-)
---
diff --git a/gi/arg-inl.h b/gi/arg-inl.h
index 6d45e682..45779b62 100644
--- a/gi/arg-inl.h
+++ b/gi/arg-inl.h
@@ -17,8 +17,11 @@
#include <girepository.h>
#include <glib-object.h> // for GType
#include <glib.h> // for gboolean
+#include <js/TypeDecls.h> // for HandleValue
+#include "gi/js-value-inl.h"
#include "gi/utils-inl.h"
+#include "gjs/macros.h"
// GIArgument accessor templates
//
@@ -205,3 +208,23 @@ gjs_arg_get_maybe_rounded(GIArgument* arg) {
return static_cast<double>(val);
}
+
+template <typename T>
+GJS_JSAPI_RETURN_CONVENTION inline bool gjs_arg_set_from_js_value(
+ JSContext* cx, const JS::HandleValue& value, GArgument* arg,
+ bool* out_of_range) {
+ if constexpr (Gjs::type_has_js_getter<T>())
+ return Gjs::js_value_to_c(cx, value, &gjs_arg_member<T>(arg));
+
+ Gjs::JsValueHolder::Relaxed<T> val;
+
+ if (!Gjs::js_value_to_c_checked<T>(cx, value, &val, out_of_range))
+ return false;
+
+ if (*out_of_range)
+ return false;
+
+ gjs_arg_set<T>(arg, val);
+
+ return true;
+}
diff --git a/gi/arg.cpp b/gi/arg.cpp
index ef13b858..a3315363 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -54,7 +54,6 @@
#include "gi/gerror.h"
#include "gi/gtype.h"
#include "gi/interface.h"
-#include "gi/js-value-inl.h"
#include "gi/object.h"
#include "gi/param.h"
#include "gi/union.h"
@@ -1751,6 +1750,26 @@ static bool value_to_interface_gi_argument(
return false;
}
+template <typename T>
+GJS_JSAPI_RETURN_CONVENTION inline static bool gjs_arg_set_from_js_value(
+ JSContext* cx, const JS::HandleValue& value, GArgument* arg,
+ GITypeTag type_tag, const char* arg_name, GjsArgumentType arg_type) {
+ bool out_of_range = false;
+
+ if (!gjs_arg_set_from_js_value<T>(cx, value, arg, &out_of_range)) {
+ if (out_of_range) {
+ GjsAutoChar display_name =
+ gjs_argument_display_name(arg_name, arg_type);
+ gjs_throw(cx, "value is out of range for %s (type %s)",
+ display_name.get(), g_type_tag_to_string(type_tag));
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
bool
gjs_value_to_g_argument(JSContext *context,
JS::HandleValue value,
@@ -1770,7 +1789,6 @@ gjs_value_to_g_argument(JSContext *context,
bool nullable_type = false;
bool wrong = false; // return false
- bool out_of_range = false;
bool report_type_mismatch = false; // wrong=true, and still need to
// gjs_throw a type problem
@@ -1781,97 +1799,66 @@ gjs_value_to_g_argument(JSContext *context,
gjs_arg_unset<void*>(arg);
break;
- case GI_TYPE_TAG_INT8: {
- gint32 i;
- if (!JS::ToInt32(context, value, &i))
- wrong = true;
- if (i > G_MAXINT8 || i < G_MININT8)
- out_of_range = true;
- gjs_arg_set<int8_t>(arg, i);
+ case GI_TYPE_TAG_INT8:
+ if (!gjs_arg_set_from_js_value<int8_t>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
- }
- case GI_TYPE_TAG_UINT8: {
- guint32 i;
- if (!JS::ToUint32(context, value, &i))
- wrong = true;
- if (i > G_MAXUINT8)
- out_of_range = true;
- gjs_arg_set<uint8_t>(arg, i);
+ case GI_TYPE_TAG_UINT8:
+ if (!gjs_arg_set_from_js_value<uint8_t>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
- }
- case GI_TYPE_TAG_INT16: {
- gint32 i;
- if (!JS::ToInt32(context, value, &i))
- wrong = true;
- if (i > G_MAXINT16 || i < G_MININT16)
- out_of_range = true;
- gjs_arg_set<int16_t>(arg, i);
+ case GI_TYPE_TAG_INT16:
+ if (!gjs_arg_set_from_js_value<int16_t>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
- }
- case GI_TYPE_TAG_UINT16: {
- guint32 i;
- if (!JS::ToUint32(context, value, &i))
- wrong = true;
- if (i > G_MAXUINT16)
- out_of_range = true;
- gjs_arg_set<uint16_t>(arg, i);
+ case GI_TYPE_TAG_UINT16:
+ if (!gjs_arg_set_from_js_value<uint16_t>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
- }
case GI_TYPE_TAG_INT32:
- if (!JS::ToInt32(context, value, &gjs_arg_member<int32_t>(arg)))
- wrong = true;
+ if (!gjs_arg_set_from_js_value<int32_t>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
- case GI_TYPE_TAG_UINT32: {
- gdouble i;
- if (!JS::ToNumber(context, value, &i))
- wrong = true;
- if (i > G_MAXUINT32 || i < 0)
- out_of_range = true;
- gjs_arg_set<uint32_t>(arg, CLAMP(i, 0, G_MAXUINT32));
+ case GI_TYPE_TAG_UINT32:
+ if (!gjs_arg_set_from_js_value<uint32_t>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
- }
- case GI_TYPE_TAG_INT64: {
- double v;
- if (!JS::ToNumber(context, value, &v))
- wrong = true;
- if (v > G_MAXINT64 || v < G_MININT64)
- out_of_range = true;
- gjs_arg_set<int64_t>(arg, v);
- }
+ case GI_TYPE_TAG_INT64:
+ if (!gjs_arg_set_from_js_value<int64_t>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
- case GI_TYPE_TAG_UINT64: {
- double v;
- if (!JS::ToNumber(context, value, &v))
- wrong = true;
- if (v < 0)
- out_of_range = true;
- /* XXX we fail with values close to G_MAXUINT64 */
- gjs_arg_set<uint64_t>(arg, MAX(v, 0));
- }
+ case GI_TYPE_TAG_UINT64:
+ if (!gjs_arg_set_from_js_value<uint64_t>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
case GI_TYPE_TAG_BOOLEAN:
gjs_arg_set(arg, JS::ToBoolean(value));
break;
- case GI_TYPE_TAG_FLOAT: {
- double v;
- if (!JS::ToNumber(context, value, &v))
- wrong = true;
- if (v > G_MAXFLOAT || v < - G_MAXFLOAT)
- out_of_range = true;
- gjs_arg_set<float>(arg, v);
- }
+ case GI_TYPE_TAG_FLOAT:
+ if (!gjs_arg_set_from_js_value<float>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
case GI_TYPE_TAG_DOUBLE:
- if (!JS::ToNumber(context, value, &gjs_arg_member<double>(arg)))
- wrong = true;
+ if (!gjs_arg_set_from_js_value<double>(context, value, arg, type_tag,
+ arg_name, arg_type))
+ return false;
break;
case GI_TYPE_TAG_UNICHAR:
@@ -2162,12 +2149,6 @@ _Pragma("GCC diagnostic pop")
throw_invalid_argument(context, value, type_info, arg_name, arg_type);
}
return false;
- } else if (G_UNLIKELY(out_of_range)) {
- GjsAutoChar display_name =
- gjs_argument_display_name(arg_name, arg_type);
- gjs_throw(context, "value is out of range for %s (type %s)",
- display_name.get(), g_type_tag_to_string(type_tag));
- return false;
} else if (nullable_type && !gjs_arg_get<void*>(arg) && !may_be_null) {
GjsAutoChar display_name =
gjs_argument_display_name(arg_name, arg_type);
diff --git a/gi/js-value-inl.h b/gi/js-value-inl.h
index 32bd3749..b597a0b9 100644
--- a/gi/js-value-inl.h
+++ b/gi/js-value-inl.h
@@ -41,6 +41,20 @@ constexpr auto get_strict() {
return int32_t{};
else if constexpr (type_fits<T, uint32_t>())
return uint32_t{};
+ else if constexpr (type_fits<T, double>())
+ return double{};
+ else
+ return T{};
+}
+
+template <typename T>
+constexpr auto get_relaxed() {
+ if constexpr (type_fits<T, int32_t>())
+ return int32_t{};
+ else if constexpr (type_fits<T, uint16_t>())
+ return uint32_t{};
+ else if constexpr (std::is_arithmetic_v<T>)
+ return double{};
else
return T{};
}
@@ -48,8 +62,18 @@ constexpr auto get_strict() {
template <typename T>
using Strict = decltype(JsValueHolder::get_strict<T>());
+
+template <typename T>
+using Relaxed = decltype(JsValueHolder::get_relaxed<T>());
+
} // namespace JsValueHolder
+
+template <typename T, typename MODE = JsValueHolder::Relaxed<T>>
+constexpr bool type_has_js_getter() {
+ return std::is_same_v<T, MODE>;
+}
+
/* Avoid implicit conversions */
template <typename T>
GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c(JSContext*,
@@ -68,6 +92,12 @@ inline bool js_value_to_c(JSContext* cx, const JS::HandleValue& value,
return JS::ToUint32(cx, value, out);
}
+GJS_JSAPI_RETURN_CONVENTION
+inline bool js_value_to_c(JSContext* cx, const JS::HandleValue& value,
+ double* out) {
+ return JS::ToNumber(cx, value, out);
+}
+
template <typename WantedType, typename T>
GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked(
JSContext* cx, const JS::HandleValue& value, T* out, bool* out_of_range) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]