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