Branch data Line data Source code
1 : : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
3 : : // SPDX-FileCopyrightText: 2010 litl, LLC
4 : :
5 : : #include <config.h>
6 : :
7 : : #include <stddef.h> // for size_t
8 : :
9 : : #include <string>
10 : : #include <unordered_map>
11 : : #include <utility> // for pair
12 : :
13 : : #include <girepository.h>
14 : : #include <glib.h>
15 : :
16 : : #include <js/RootingAPI.h>
17 : : #include <js/TypeDecls.h>
18 : :
19 : : #include "gi/foreign.h"
20 : : #include "gjs/context-private.h"
21 : : #include "gjs/jsapi-util.h"
22 : : #include "gjs/macros.h"
23 : :
24 : : enum LoadedStatus { NotLoaded, Loaded };
25 : : static std::unordered_map<std::string, LoadedStatus> foreign_modules{
26 : : {"cairo", NotLoaded}};
27 : :
28 : : using StructID = std::pair<std::string, std::string>;
29 : : struct StructIDHash {
30 : 3 : [[nodiscard]] size_t operator()(StructID val) const {
31 : : std::hash<std::string> hasher;
32 : 3 : return hasher(val.first) ^ hasher(val.second);
33 : : }
34 : : };
35 : : static std::unordered_map<StructID, GjsForeignInfo*, StructIDHash>
36 : : foreign_structs_table;
37 : :
38 : 0 : [[nodiscard]] static bool gjs_foreign_load_foreign_module(
39 : : JSContext* cx, const char* gi_namespace) {
40 : 0 : auto entry = foreign_modules.find(gi_namespace);
41 [ # # ]: 0 : if (entry == foreign_modules.end())
42 : 0 : return false;
43 : :
44 [ # # ]: 0 : if (entry->second == Loaded)
45 : 0 : return true;
46 : :
47 : : // FIXME: Find a way to check if a module is imported and only execute this
48 : : // statement if it isn't
49 : 0 : std::string script = "imports." + entry->first + ';';
50 : 0 : JS::RootedValue retval{cx};
51 : 0 : GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
52 [ # # ]: 0 : if (!gjs->eval_with_scope(nullptr, script.c_str(), script.length(),
53 : : "<internal>", &retval)) {
54 : 0 : g_critical("ERROR importing foreign module %s\n", gi_namespace);
55 : 0 : return false;
56 : : }
57 : 0 : entry->second = Loaded;
58 : 0 : return true;
59 : 0 : }
60 : :
61 : 3 : void gjs_struct_foreign_register(const char* gi_namespace,
62 : : const char* type_name, GjsForeignInfo* info) {
63 : 3 : foreign_structs_table.insert({{gi_namespace, type_name}, info});
64 : 3 : }
65 : :
66 : : GJS_JSAPI_RETURN_CONVENTION
67 : 0 : static GjsForeignInfo* gjs_struct_foreign_lookup(JSContext* cx,
68 : : GIStructInfo* info) {
69 : 0 : const char* ns = g_base_info_get_namespace(info);
70 : 0 : StructID key{ns, g_base_info_get_name(info)};
71 : 0 : auto entry = foreign_structs_table.find(key);
72 [ # # ]: 0 : if (entry == foreign_structs_table.end()) {
73 [ # # ]: 0 : if (gjs_foreign_load_foreign_module(cx, ns))
74 : 0 : entry = foreign_structs_table.find(key);
75 : : }
76 : :
77 [ # # ]: 0 : if (entry == foreign_structs_table.end()) {
78 : 0 : gjs_throw(cx, "Unable to find module implementing foreign type %s.%s",
79 : : key.first.c_str(), key.second.c_str());
80 : 0 : return nullptr;
81 : : }
82 : :
83 : 0 : return entry->second;
84 : 0 : }
85 : :
86 : 0 : bool gjs_struct_foreign_convert_to_gi_argument(
87 : : JSContext* context, JS::Value value, GIStructInfo* info,
88 : : const char* arg_name, GjsArgumentType argument_type, GITransfer transfer,
89 : : GjsArgumentFlags flags, GIArgument* arg) {
90 : : GjsForeignInfo *foreign;
91 : :
92 : 0 : foreign = gjs_struct_foreign_lookup(context, info);
93 [ # # ]: 0 : if (!foreign)
94 : 0 : return false;
95 : :
96 [ # # ]: 0 : if (!foreign->to_func(context, value, arg_name, argument_type, transfer,
97 : : flags, arg))
98 : 0 : return false;
99 : :
100 : 0 : return true;
101 : : }
102 : :
103 : 0 : bool gjs_struct_foreign_convert_from_gi_argument(JSContext* context,
104 : : JS::MutableHandleValue value_p,
105 : : GIStructInfo* info,
106 : : GIArgument* arg) {
107 : 0 : GjsForeignInfo* foreign = gjs_struct_foreign_lookup(context, info);
108 [ # # ]: 0 : if (!foreign)
109 : 0 : return false;
110 : :
111 [ # # ]: 0 : if (!foreign->from_func(context, value_p, arg))
112 : 0 : return false;
113 : :
114 : 0 : return true;
115 : : }
116 : :
117 : 0 : bool gjs_struct_foreign_release_gi_argument(JSContext* context,
118 : : GITransfer transfer,
119 : : GIStructInfo* info,
120 : : GIArgument* arg) {
121 : 0 : GjsForeignInfo* foreign = gjs_struct_foreign_lookup(context, info);
122 [ # # ]: 0 : if (!foreign)
123 : 0 : return false;
124 : :
125 [ # # ]: 0 : if (!foreign->release_func)
126 : 0 : return true;
127 : :
128 [ # # ]: 0 : if (!foreign->release_func(context, transfer, arg))
129 : 0 : return false;
130 : :
131 : 0 : return true;
132 : : }
|