Skip to content

Commit

Permalink
Merge pull request #12 from vixalien/log-invoke-error
Browse files Browse the repository at this point in the history
Throw invoke errors
  • Loading branch information
ahgilak authored Dec 23, 2023
2 parents f5126e9 + 2f170b4 commit d4876cd
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 29 deletions.
6 changes: 5 additions & 1 deletion src/bindings/girepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ import {
const { g } = openLib(libName("girepository-1.0", 1), {
g: {
irepository: {
require: $void($pointer, $string, $string, $i32, $pointer),
require: $pointer($pointer, $string, $string, $i32, $buffer),
get_n_infos: $i32($pointer, $string),
get_info: $pointer($pointer, $string, $i32),
find_by_gtype: $pointer($pointer, $i64),
enumerate_versions: $pointer($pointer, $string),
get_version: $string($pointer, $string),
is_registered: $bool($pointer, $string, $string),
},
registered_type_info: {
get_g_type: $i64($pointer),
Expand All @@ -43,6 +46,7 @@ const { g } = openLib(libName("girepository-1.0", 1), {
enum_info: {
get_n_values: $i32($pointer),
get_value: $pointer($pointer, $i32),
get_error_domain: $string($pointer),
},
value_info: {
get_value: $i32($pointer),
Expand Down
15 changes: 15 additions & 0 deletions src/bindings/glib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { libName, openLib } from "../base_utils/ffipp.js";

import { $pointer, $string, $u32 } from "../base_utils/types.ts";

const { g } = openLib(libName("glib-2.0", 0), {
g: {
quark_from_string: $u32($string),
slist: {
length: $u32($pointer),
nth: $pointer($pointer, $u32),
},
},
});

export default g;
3 changes: 2 additions & 1 deletion src/bindings/mod.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import glib from "./glib.js";
import gir from "./girepository.js";
import gobject from "./gobject.js";

export default { ...gir, ...gobject };
export default { ...gir, ...gobject, ...glib };
87 changes: 79 additions & 8 deletions src/gi.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,90 @@
import { cast_u64_ptr, deref_buf, deref_str } from "./base_utils/convert.ts";
import g from "./bindings/mod.js";
import handleInfo from "./handleInfo.js";
import { ExtendedDataView } from "./utils/dataview.js";

const repos = new Map();

function getLatestVersion(namespace) {
if (g.irepository.is_registered(null, namespace, null)) {
return g.irepository.get_version(null, namespace);
}

const versions = g.irepository.enumerate_versions(null, namespace);

// No versions are available, require will throw an error
if (!versions) return null;

const array = [];

for (let i = 0; i < g.slist.length(versions); i++) {
const version = g.slist.nth(versions, i);
const dataView = new ExtendedDataView(deref_buf(version, 8));
const pointer = cast_u64_ptr(dataView.getBigUint64());

array.push(deref_str(pointer));
}

if (array.length === 0) return null;

if (array.length > 1) {
console.warn(
`Requiring ${namespace} but it has ${array.length} versions available. Specify version to pick one.`,
);
}

return array
.sort((a, b) => {
return a.localeCompare(b, undefined, { numeric: true });
})
.reverse()[0];
}

/**
* @param {string} namespace
* @param {string?} version
* @returns
*/
export function require(namespace, version) {
const repo = new Object();
if (!version) {
version = getLatestVersion(namespace);
}

// if no version is specified, the latest
const key = `${namespace}-${version}`;

if (repos.has(key)) {
return repos.get(key);
}

const error = new BigUint64Array(1);

if (
!g.irepository.require(
null,
namespace,
version,
0, // disable lazy load
error,
)
) {
let message = "Unknown error";

g.irepository.require(
null,
namespace,
version,
0, // disable lazy load
null,
);
if (error) {
const dataView = new ExtendedDataView(
deref_buf(cast_u64_ptr(error[0]), 16),
);
message = deref_str(cast_u64_ptr(dataView.getBigUint64(8)));
}

const versionString = version ? ` version ${version}` : "";

throw new Error(
`Requiring ${namespace}${versionString} failed: ${message}`,
);
}

const repo = new Object();

const nInfos = g.irepository.get_n_infos(null, namespace);

Expand All @@ -25,5 +94,7 @@ export function require(namespace, version) {
g.base_info.unref(info);
}

repos.set(key, repo);

return repo;
}
10 changes: 7 additions & 3 deletions src/types/callable/constructor.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import g from "../../bindings/mod.js";
import { cast_u64_ptr } from "../../base_utils/convert.ts";
import { createGError } from "../../utils/error.ts";
import { ExtendedDataView } from "../../utils/dataview.js";
import { getName } from "../../utils/string.ts";
import { parseCallableArgs } from "../callable.js";

export function createConstructor(info, prototype) {
Expand All @@ -10,7 +10,7 @@ export function createConstructor(info, prototype) {
return (...args) => {
const inArgs = parseInArgs(...args);

const error = new ArrayBuffer(16);
const error = new BigUint64Array(1);
const returnValue = new ArrayBuffer(8);

const success = g.function_info.invoke(
Expand All @@ -24,7 +24,11 @@ export function createConstructor(info, prototype) {
);

if (!success) {
console.error(`Error invoking function ${getName(info)}`);
if (!error[0]) {
throw new Error(`Error invoking constructor ${getName(info)}`);
}

throw createGError(error[0]);
}

const result = Object.create(prototype);
Expand Down
11 changes: 7 additions & 4 deletions src/types/callable/function.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GITypeTag } from "../../bindings/enums.js";
import g from "../../bindings/mod.js";
import { getName } from "../../utils/string.ts";
import { createGError } from "../../utils/error.ts";
import { unboxArgument } from "../argument.js";
import { parseCallableArgs } from "../callable.js";

Expand All @@ -12,7 +12,7 @@ export function createFunction(info) {
const inArgs = parseInArgs(...args);
const outArgs = initOutArgs();

const error = new ArrayBuffer(16);
const error = new BigUint64Array(1);
const returnValue = new ArrayBuffer(8);

const success = g.function_info.invoke(
Expand All @@ -26,8 +26,11 @@ export function createFunction(info) {
);

if (!success) {
console.error(`Error invoking function ${getName(info)}`);
return;
if (!error[0]) {
throw new Error(`Error invoking function ${getName(info)}`);
}

throw createGError(error[0]);
}

const retVal = unboxArgument(returnType, returnValue);
Expand Down
11 changes: 7 additions & 4 deletions src/types/callable/method.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import g from "../../bindings/mod.js";
import { cast_ptr_u64 } from "../../base_utils/convert.ts";
import { getName } from "../../utils/string.ts";
import { createGError } from "../../utils/error.ts";
import { unboxArgument } from "../argument.js";
import { parseCallableArgs } from "../callable.js";

Expand All @@ -15,7 +15,7 @@ export function createMethod(info) {

inArgs.unshift(cast_ptr_u64(caller));

const error = new ArrayBuffer(16);
const error = new BigUint64Array(1);
const returnValue = new ArrayBuffer(8);

const success = g.function_info.invoke(
Expand All @@ -29,8 +29,11 @@ export function createMethod(info) {
);

if (!success) {
console.error(`Error invoking method ${getName(info)}`);
return;
if (!error[0]) {
throw new Error(`Error invoking method ${getName(info)}`);
}

throw createGError(error[0]);
}

const retVal = unboxArgument(returnType, returnValue);
Expand Down
11 changes: 7 additions & 4 deletions src/types/callable/vfunc.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import g from "../../bindings/mod.js";
import { cast_ptr_u64 } from "../../base_utils/convert.ts";
import { getName } from "../../utils/string.ts";
import { createGError } from "../../utils/error.ts";
import { unboxArgument } from "../argument.js";
import { parseCallableArgs } from "../callable.js";

Expand All @@ -15,7 +15,7 @@ export function createVFunc(info) {

inArgs.unshift(cast_ptr_u64(caller));

const error = new ArrayBuffer(16);
const error = new BigUint64Array(1);
const returnValue = new ArrayBuffer(8);

const success = g.vfunc_info.invoke(
Expand All @@ -30,8 +30,11 @@ export function createVFunc(info) {
);

if (!success) {
console.error(`Error invoking vfunc ${getName(info)}`);
return;
if (!error[0]) {
throw new Error(`Error invoking vfunc ${getName(info)}`);
}

throw createGError(error[0]);
}

const retVal = unboxArgument(returnType, returnValue);
Expand Down
45 changes: 41 additions & 4 deletions src/types/enum.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,53 @@
import g from "../bindings/mod.js";
import handleInfo from "../handleInfo.js";
import { getGLibError } from "../utils/error.ts";
import { getName } from "../utils/string.ts";

export function createEnum(info) {
const result = new Object();

function defineValues(target, info) {
const nValues = g.enum_info.get_n_values(info);

for (let i = 0; i < nValues; i++) {
const valueInfo = g.enum_info.get_value(info, i);
handleInfo(result, valueInfo);
handleInfo(target, valueInfo);
g.base_info.unref(valueInfo);
}
}

export function createError(info, error_domain) {
const GError = getGLibError();

const ObjectClass = class extends GError {
constructor(props) {
super({
...props,
domain: g.quark_from_string(error_domain),
});
}

[Symbol.hasInstance](instance) {
return (instance instanceof GError) && (instance.domain === this.domain);
}
};

Object.defineProperty(ObjectClass, "name", {
value: getName(info),
});

defineValues(ObjectClass, info);

return ObjectClass;
}

export function createEnum(info) {
const error_domain = g.enum_info.get_error_domain(info);

if (error_domain) {
return createError(info, error_domain);
}

const result = new Object();

defineValues(result, info);

return Object.freeze(result);
}
17 changes: 17 additions & 0 deletions src/utils/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { cast_u64_ptr } from "../base_utils/convert.ts";
import { require } from "../gi.js";

export function createGError(pointer: bigint) {
const GError = getGLibError();

const error = Object.create(GError.prototype);
Reflect.defineMetadata("gi:ref", cast_u64_ptr(pointer), error);

error.stack = new Error().stack;

return error;
}

export function getGLibError() {
return require("GLib", "2.0").Error;
}

0 comments on commit d4876cd

Please sign in to comment.