File: foreign.cpp

package info (click to toggle)
cjs 128.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,872 kB
  • sloc: cpp: 34,377; javascript: 27,762; ansic: 13,033; sh: 1,611; python: 780; xml: 116; makefile: 38
file content (132 lines) | stat: -rw-r--r-- 4,260 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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
// SPDX-FileCopyrightText: 2010 litl, LLC

#include <config.h>

#include <stddef.h>  // for size_t

#include <string>
#include <unordered_map>
#include <utility>  // for pair

#include <girepository.h>
#include <glib.h>

#include <js/RootingAPI.h>
#include <js/TypeDecls.h>

#include "gi/foreign.h"
#include "cjs/context-private.h"
#include "cjs/jsapi-util.h"
#include "cjs/macros.h"

enum LoadedStatus { NotLoaded, Loaded };
static std::unordered_map<std::string, LoadedStatus> foreign_modules{
    {"cairo", NotLoaded}};

using StructID = std::pair<std::string, std::string>;
struct StructIDHash {
    [[nodiscard]] size_t operator()(StructID val) const {
        std::hash<std::string> hasher;
        return hasher(val.first) ^ hasher(val.second);
    }
};
static std::unordered_map<StructID, GjsForeignInfo*, StructIDHash>
    foreign_structs_table;

[[nodiscard]] static bool gjs_foreign_load_foreign_module(
    JSContext* cx, const char* gi_namespace) {
    auto entry = foreign_modules.find(gi_namespace);
    if (entry == foreign_modules.end())
        return false;

    if (entry->second == Loaded)
        return true;

    // FIXME: Find a way to check if a module is imported and only execute this
    // statement if it isn't
    std::string script = "imports." + entry->first + ';';
    JS::RootedValue retval{cx};
    GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
    if (!gjs->eval_with_scope(nullptr, script.c_str(), script.length(),
                              "<internal>", &retval)) {
        g_critical("ERROR importing foreign module %s\n", gi_namespace);
        return false;
    }
    entry->second = Loaded;
    return true;
}

void gjs_struct_foreign_register(const char* gi_namespace,
                                 const char* type_name, GjsForeignInfo* info) {
    foreign_structs_table.insert({{gi_namespace, type_name}, info});
}

GJS_JSAPI_RETURN_CONVENTION
static GjsForeignInfo* gjs_struct_foreign_lookup(JSContext* cx,
                                                 GIStructInfo* info) {
    const char* ns = g_base_info_get_namespace(info);
    StructID key{ns, g_base_info_get_name(info)};
    auto entry = foreign_structs_table.find(key);
    if (entry == foreign_structs_table.end()) {
        if (gjs_foreign_load_foreign_module(cx, ns))
            entry = foreign_structs_table.find(key);
    }

    if (entry == foreign_structs_table.end()) {
        gjs_throw(cx, "Unable to find module implementing foreign type %s.%s",
                  key.first.c_str(), key.second.c_str());
        return nullptr;
    }

    return entry->second;
}

bool gjs_struct_foreign_convert_to_gi_argument(
    JSContext* context, JS::Value value, GIStructInfo* info,
    const char* arg_name, GjsArgumentType argument_type, GITransfer transfer,
    GjsArgumentFlags flags, GIArgument* arg) {
    GjsForeignInfo *foreign;

    foreign = gjs_struct_foreign_lookup(context, info);
    if (!foreign)
        return false;

    if (!foreign->to_func(context, value, arg_name, argument_type, transfer,
                          flags, arg))
        return false;

    return true;
}

bool gjs_struct_foreign_convert_from_gi_argument(JSContext* context,
                                                 JS::MutableHandleValue value_p,
                                                 GIStructInfo* info,
                                                 GIArgument* arg) {
    GjsForeignInfo* foreign = gjs_struct_foreign_lookup(context, info);
    if (!foreign)
        return false;

    if (!foreign->from_func(context, value_p, arg))
        return false;

    return true;
}

bool gjs_struct_foreign_release_gi_argument(JSContext* context,
                                            GITransfer transfer,
                                            GIStructInfo* info,
                                            GIArgument* arg) {
    GjsForeignInfo* foreign = gjs_struct_foreign_lookup(context, info);
    if (!foreign)
        return false;

    if (!foreign->release_func)
        return true;

    if (!foreign->release_func(context, transfer, arg))
        return false;

    return true;
}