File: enumeration.cpp

package info (click to toggle)
gjs 1.86.0-3.1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,724 kB
  • sloc: cpp: 39,075; javascript: 30,720; ansic: 15,971; sh: 1,759; python: 772; xml: 135; makefile: 40
file content (113 lines) | stat: -rw-r--r-- 3,777 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
// SPDX-FileCopyrightText: 2008 litl, LLC

#include <config.h>

#include <inttypes.h>

#include <glib-object.h>
#include <glib.h>

#include <js/PropertyAndElement.h>
#include <js/RootingAPI.h>
#include <js/TypeDecls.h>
#include <jsapi.h>  // for JS_NewPlainObject

#include "gi/cwrapper.h"
#include "gi/enumeration.h"
#include "gi/info.h"
#include "gi/wrapperutils.h"
#include "gjs/auto.h"
#include "gjs/jsapi-util.h"
#include "gjs/macros.h"
#include "util/log.h"

GJS_JSAPI_RETURN_CONVENTION
static bool gjs_define_enum_value(JSContext* context,
                                  JS::HandleObject in_object,
                                  const GI::ValueInfo info) {
    gsize i;

    const char* value_name = info.name();
    int64_t value_val = info.value();

    /* g-i converts enum members such as GDK_GRAVITY_SOUTH_WEST to
     * Gdk.GravityType.south-west (where 'south-west' is value_name)
     * Convert back to all SOUTH_WEST.
     */
    Gjs::AutoChar fixed_name{g_ascii_strup(value_name, -1)};
    for (i = 0; fixed_name[i]; ++i) {
        char c = fixed_name[i];
        if (!(('A' <= c && c <= 'Z') ||
              ('0' <= c && c <= '9')))
            fixed_name[i] = '_';
    }

    gjs_debug(GJS_DEBUG_GENUM,
              "Defining enum value %s (fixed from %s) %" PRId64,
              fixed_name.get(), value_name, value_val);

    if (!JS_DefineProperty(context, in_object,
                           fixed_name, (double) value_val,
                           GJS_MODULE_PROP_FLAGS)) {
        gjs_throw(context,
                  "Unable to define enumeration value %s %" G_GINT64_FORMAT
                  " (no memory most likely)",
                  fixed_name.get(), value_val);
        return false;
    }

    return true;
}

bool gjs_define_enum_values(JSContext* context, JS::HandleObject in_object,
                            const GI::EnumInfo info) {
    /* Fill in enum values first, so we don't define the enum itself until we're
     * sure we can finish successfully.
     */
    for (GI::AutoValueInfo value_info : info.values()) {
        if (!gjs_define_enum_value(context, in_object, value_info))
            return false;
    }
    return true;
}

bool gjs_define_enumeration(JSContext* context, JS::HandleObject in_object,
                            const GI::EnumInfo info) {
    /* An enumeration is simply an object containing integer attributes for
     * each enum value. It does not have a special JSClass.
     *
     * We could make this more typesafe and also print enum values as strings
     * if we created a class for each enum and made the enum values instances
     * of that class. However, it would have a lot more overhead and just
     * be more complicated in general. I think this is fine.
     */

    const char* enum_name = info.name();

    JS::RootedObject enum_obj(context, JS_NewPlainObject(context));
    if (!enum_obj) {
        gjs_throw(context, "Could not create enumeration %s.%s", info.ns(),
                  enum_name);
        return false;
    }

    GType gtype = info.gtype();

    if (!gjs_define_enum_values(context, enum_obj, info) ||
        !gjs_define_static_methods(context, enum_obj, gtype, info) ||
        !gjs_wrapper_define_gtype_prop(context, enum_obj, gtype))
        return false;

    gjs_debug(GJS_DEBUG_GENUM, "Defining %s.%s as %p", info.ns(), enum_name,
              enum_obj.get());

    if (!JS_DefineProperty(context, in_object, enum_name, enum_obj,
                           GJS_MODULE_PROP_FLAGS)) {
        gjs_throw(context, "Unable to define enumeration property (no memory most likely)");
        return false;
    }

    return true;
}