[gjs: 4/6] jsapi-util-args: Add 'S' conversion specifier




commit 309a51ccc878760c4fb8275c5b0e563711a050b7
Author: Philip Chimento <philip chimento gmail com>
Date:   Fri Jul 2 18:09:23 2021 -0700

    jsapi-util-args: Add 'S' conversion specifier
    
    The 'S' specifier also expects a string argument, or additionally null if
    it is given as '?S'. Unlike 's' and 'F', it does not convert the string
    value at all, and instead puts it into a JS::MutableHandleString.
    
    This will be used in the Encoding specification.

 gjs/jsapi-util-args.h       | 37 ++++++++++++++++++++++--------
 test/gjs-test-call-args.cpp | 56 ++++++++++++++++++++++++++++-----------------
 2 files changed, 62 insertions(+), 31 deletions(-)
---
diff --git a/gjs/jsapi-util-args.h b/gjs/jsapi-util-args.h
index 62843121..576d638d 100644
--- a/gjs/jsapi-util-args.h
+++ b/gjs/jsapi-util-args.h
@@ -98,6 +98,21 @@ assign(JSContext      *cx,
         throw g_strdup("Couldn't convert to filename");
 }
 
+GJS_ALWAYS_INLINE
+static inline void assign(JSContext*, char c, bool nullable,
+                          JS::HandleValue value, JS::MutableHandleString ref) {
+    if (c != 'S')
+        throw g_strdup_printf("Wrong type for %c, got JS::MutableHandleString",
+                              c);
+    if (nullable && value.isNull()) {
+        ref.set(nullptr);
+        return;
+    }
+    if (!value.isString())
+        throw g_strdup("Not a string");
+    ref.set(value.toString());
+}
+
 GJS_ALWAYS_INLINE
 static inline void
 assign(JSContext      *cx,
@@ -187,12 +202,13 @@ GJS_ALWAYS_INLINE static inline void assign(JSContext* cx, char c,
 template <typename T>
 static inline void free_if_necessary(T param_ref [[maybe_unused]]) {}
 
-GJS_ALWAYS_INLINE
-static inline void free_if_necessary(JS::RootedObject* param_ref) {
-    /* This is not exactly right, since before we consumed a JS::ObjectValue
-     * there may have been something different inside the handle. But it has
-     * already been clobbered at this point anyhow */
-    JS::MutableHandleObject(param_ref).set(nullptr);
+template <typename T>
+GJS_ALWAYS_INLINE static inline void free_if_necessary(
+    JS::Rooted<T>* param_ref) {
+    // This is not exactly right, since before we consumed a JS::Value there may
+    // have been something different inside the handle. But it has already been
+    // clobbered at this point anyhow.
+    JS::MutableHandle<T>(param_ref).set(nullptr);
 }
 
 template <typename T>
@@ -247,7 +263,7 @@ GJS_JSAPI_RETURN_CONVENTION static bool parse_call_args_helper(
     bool retval = parse_call_args_helper(cx, function_name, args, fmt_required,
                                          fmt_optional, ++param_ix, params...);
 
-    /* We still own the strings in the error case, free any we converted */
+    // We still own JSString/JSObject in the error case, free any we converted
     if (!retval)
         free_if_necessary(param_ref);
     return retval;
@@ -295,6 +311,7 @@ GJS_JSAPI_RETURN_CONVENTION [[maybe_unused]] static bool gjs_parse_call_args(
  * s: A string, converted into UTF-8 (pass a JS::UniqueChars*)
  * F: A string, converted into "filename encoding" (i.e. active locale) (pass
  *   a GjsAutoChar *)
+ * S: A string, no conversion (pass a JS::MutableHandleString)
  * i: A number, will be converted to a 32-bit int (pass an int32_t * or a
  *   pointer to an enum type)
  * u: A number, converted into a 32-bit unsigned int (pass a uint32_t *)
@@ -309,9 +326,9 @@ GJS_JSAPI_RETURN_CONVENTION [[maybe_unused]] static bool gjs_parse_call_args(
  * after a '|' when not specified, do not cause any changes in the C
  * value location.
  *
- * A prefix character '?' in front of 's', 'F', or 'o' means that the next value
- * may be null. For 's' or 'F' a null pointer is returned, for 'o' the handle is
- * set to null.
+ * A prefix character '?' in front of 's', 'F', 'S', or 'o' means that the next
+ * value may be null. For 's' or 'F' a null pointer is returned, for 'S' or 'o'
+ * the handle is set to null.
  */
 template <typename... Args>
 GJS_JSAPI_RETURN_CONVENTION static bool gjs_parse_call_args(
diff --git a/test/gjs-test-call-args.cpp b/test/gjs-test-call-args.cpp
index 17d2039d..d5413600 100644
--- a/test/gjs-test-call-args.cpp
+++ b/test/gjs-test-call-args.cpp
@@ -116,23 +116,23 @@ JSNATIVE_TEST_FUNC_BEGIN(one_of_each_type)
     bool boolval;
     JS::UniqueChars strval;
     GjsAutoChar fileval;
+    JS::RootedString jsstrval(cx);
     int intval;
     unsigned uintval;
     int64_t int64val;
     double dblval;
     JS::RootedObject objval(cx);
-    retval = gjs_parse_call_args(cx, "oneOfEachType", args, "bsFiutfo",
-                                 "bool", &boolval,
-                                 "str", &strval,
-                                 "file", &fileval,
-                                 "int", &intval,
-                                 "uint", &uintval,
-                                 "int64", &int64val,
-                                 "dbl", &dblval,
-                                 "obj", &objval);
+    retval = gjs_parse_call_args(
+        cx, "oneOfEachType", args, "bsFSiutfo", "bool", &boolval, "str",
+        &strval, "file", &fileval, "jsstr", &jsstrval, "int", &intval, "uint",
+        &uintval, "int64", &int64val, "dbl", &dblval, "obj", &objval);
     g_assert_cmpint(boolval, ==, true);
     g_assert_cmpstr(strval.get(), ==, "foo");
     g_assert_cmpstr(fileval, ==, "foo");
+    bool match;
+    bool ok = JS_StringEqualsLiteral(cx, jsstrval, "foo", &match);
+    g_assert_true(ok);
+    g_assert_true(match);
     g_assert_cmpint(intval, ==, 1);
     g_assert_cmpint(uintval, ==, 1);
     g_assert_cmpint(int64val, ==, 1);
@@ -186,25 +186,27 @@ JSNATIVE_TEST_FUNC_END
 JSNATIVE_TEST_FUNC_BEGIN(one_of_each_nullable_type)
     JS::UniqueChars strval;
     GjsAutoChar fileval;
+    JS::RootedString jsstrval(cx);
     JS::RootedObject objval(cx);
-    retval = gjs_parse_call_args(cx, "oneOfEachNullableType", args, "?s?F?o",
-                                 "strval", &strval,
-                                 "fileval", &fileval,
-                                 "objval", &objval);
+    retval = gjs_parse_call_args(cx, "oneOfEachNullableType", args, "?s?F?S?o",
+                                 "strval", &strval, "fileval", &fileval,
+                                 "jsstrval", &jsstrval, "objval", &objval);
     g_assert_null(strval);
     g_assert_null(fileval);
+    g_assert_false(jsstrval);
     g_assert_false(objval);
 JSNATIVE_TEST_FUNC_END
 
 JSNATIVE_TEST_FUNC_BEGIN(unwind_free_test)
     int intval;
     unsigned uval;
+    JS::RootedString jsstrval(cx);
     JS::RootedObject objval(cx);
-    retval = gjs_parse_call_args(cx, "unwindFreeTest", args, "oiu",
-                                 "objval", &objval,
-                                 "intval", &intval,
-                                 "error", &uval);
+    retval = gjs_parse_call_args(cx, "unwindFreeTest", args, "oSiu", "objval",
+                                 &objval, "jsstrval", &jsstrval, "intval",
+                                 &intval, "error", &uval);
     g_assert_false(objval);
+    g_assert_false(jsstrval);
 JSNATIVE_TEST_FUNC_END
 
 #define JSNATIVE_BAD_NULLABLE_TEST_FUNC(type, fmt)                 \
@@ -245,6 +247,12 @@ JSNATIVE_TEST_FUNC_BEGIN(UniqueChars_invalid_type)
                                  "value", &value);
 JSNATIVE_TEST_FUNC_END
 
+JSNATIVE_TEST_FUNC_BEGIN(JSString_invalid_type)
+    JS::RootedString val(cx);
+    retval =
+        gjs_parse_call_args(cx, "JSStringInvalidType", args, "i", "val", &val);
+JSNATIVE_TEST_FUNC_END
+
 JSNATIVE_TEST_FUNC_BEGIN(object_invalid_type)
     JS::RootedObject val(cx);
     retval = gjs_parse_call_args(cx, "objectInvalidType", args, "i",
@@ -279,6 +287,7 @@ static JSFunctionSpec native_test_funcs[] = {
     JS_FN("doubleInvalidType", double_invalid_type, 0, 0),
     JS_FN("GjsAutoCharInvalidType", GjsAutoChar_invalid_type, 0, 0),
     JS_FN("UniqueCharsInvalidType", UniqueChars_invalid_type, 0, 0),
+    JS_FN("JSStringInvalidType", JSString_invalid_type, 0, 0),
     JS_FN("objectInvalidType", object_invalid_type, 0, 0),
     JS_FS_END};
 
@@ -371,8 +380,9 @@ gjs_test_add_tests_for_parse_call_args(void)
                              "optionalIntArgsNoAssert()//*At least 1 argument "
                              "required, but only 0 passed");
     ADD_CALL_ARGS_TEST("args-ignores-trailing", "argsIgnoreTrailing(1, 2, 3)");
-    ADD_CALL_ARGS_TEST("one-of-each-type-works",
-                       "oneOfEachType(true, 'foo', 'foo', 1, 1, 1, 1, {})");
+    ADD_CALL_ARGS_TEST(
+        "one-of-each-type-works",
+        "oneOfEachType(true, 'foo', 'foo', 'foo', 1, 1, 1, 1, {})");
     ADD_CALL_ARGS_TEST("optional-args-work-when-passing-all-args",
                        "optionalArgsAll(true, true, true)");
     ADD_CALL_ARGS_TEST("optional-args-work-when-passing-only-required-args",
@@ -380,7 +390,7 @@ gjs_test_add_tests_for_parse_call_args(void)
     ADD_CALL_ARGS_TEST("enum-types-work", "unsignedEnumArg(1)");
     ADD_CALL_ARGS_TEST("signed-enum-types-work", "signedEnumArg(-1)");
     ADD_CALL_ARGS_TEST("one-of-each-nullable-type-works",
-                       "oneOfEachNullableType(null, null, null)");
+                       "oneOfEachNullableType(null, null, null, null)");
     ADD_CALL_ARGS_TEST("passing-no-arguments-when-all-optional",
                        "onlyOptionalArgs()");
     ADD_CALL_ARGS_TEST("passing-some-arguments-when-all-optional",
@@ -388,7 +398,7 @@ gjs_test_add_tests_for_parse_call_args(void)
     ADD_CALL_ARGS_TEST("passing-all-arguments-when-all-optional",
                        "onlyOptionalArgs(1, 1)");
     ADD_CALL_ARGS_TEST_XFAIL("allocated-args-are-freed-on-error",
-                             "unwindFreeTest({}, 1, -1)"
+                             "unwindFreeTest({}, 'foo', 1, -1)"
                              "//*Value * is out of range");
     ADD_CALL_ARGS_TEST_XFAIL("nullable-bool-is-invalid",
                              "boolInvalidNullable(true)"
@@ -426,6 +436,10 @@ gjs_test_add_tests_for_parse_call_args(void)
     ADD_CALL_ARGS_TEST_XFAIL("invalid-autojschar-type",
                              "UniqueCharsInvalidType(1)"
                              "//*Wrong type for i, got JS::UniqueChars?");
+    ADD_CALL_ARGS_TEST_XFAIL(
+        "invalid-jsstring-type",
+        "JSStringInvalidType(1)"
+        "//*Wrong type for i, got JS::MutableHandleString");
     ADD_CALL_ARGS_TEST_XFAIL("invalid-object-type",
                              "objectInvalidType(1)"
                              "//*Wrong type for i, got JS::MutableHandleObject");


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]