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;
}
|