Skip to content

Commit

Permalink
Merge pull request #23 from vixalien/vfuncs
Browse files Browse the repository at this point in the history
Vfuncs
  • Loading branch information
ahgilak authored Jan 31, 2024
2 parents 217abd6 + e7036ce commit 3452c42
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 17 deletions.
6 changes: 5 additions & 1 deletion src/bindings/girepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const { g } = openLib(libName("girepository-1.0", 1), {
},
base_info: {
get_name: $string($pointer),
get_container: $pointer($pointer),
is_deprecated: $bool($pointer),
get_type: $i32($pointer),
ref: $void($pointer),
Expand Down Expand Up @@ -75,6 +76,7 @@ const { g } = openLib(libName("girepository-1.0", 1), {
get_n_fields: $i32($pointer),
get_field: $pointer($pointer, $i32),
get_size: $i32($pointer),
find_field: $pointer($pointer, $string),
},
object_info: {
get_n_methods: $i32($pointer),
Expand All @@ -99,6 +101,7 @@ const { g } = openLib(libName("girepository-1.0", 1), {
get_vfunc: $pointer($pointer, $i32),
get_n_properties: $i32($pointer),
get_property: $pointer($pointer, $i32),
get_iface_struct: $pointer($pointer),
},
property_info: {
get_flags: $i32($pointer),
Expand All @@ -110,8 +113,9 @@ const { g } = openLib(libName("girepository-1.0", 1), {
field_info: {
get_flags: $i32($pointer),
get_type: $pointer($pointer),
get_field: $i32($pointer,$pointer, $buffer),
get_field: $bool($pointer,$pointer, $buffer),
set_field: $i32($pointer,$pointer, $buffer),
get_offset: $i32($pointer),
},
},
});
Expand Down
66 changes: 56 additions & 10 deletions src/types/callable.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { cast_ptr_u64, deref_buf } from "../base_utils/convert.ts";
import {
GIDirection,
GIFunctionInfoFlags,
Expand All @@ -11,6 +12,7 @@ import { createConstructor } from "./callable/constructor.js";
import { createFunction } from "./callable/function.js";
import { createMethod } from "./callable/method.js";
import { createVFunc } from "./callable/vfunc.js";
import { createCallback } from "./callback.js";

export function createArg(info) {
const type = g.arg_info.get_type(info);
Expand Down Expand Up @@ -120,19 +122,63 @@ export function handleCallable(target, info) {
}

case GIInfoType.VFUNC: {
if (Object.hasOwn(target.prototype, name)) {
return;
}

const value = createVFunc(info);
Object.defineProperty(target.prototype, name, {
Object.defineProperty(target.prototype, `vfunc_` + name, {
enumerable: true,
value(...args) {
return value(
Reflect.getOwnMetadata("gi:ref", this),
Reflect.getOwnMetadata("gi:gtype", this.constructor),
...args,
get() {
return (...args) => {
return value(
Reflect.getOwnMetadata("gi:ref", this),
Reflect.getOwnMetadata("gi:gtype", this.constructor),
...args,
);
};
},
set(value) {
const cName = g.base_info.get_name(info);

const containerInfo = g.base_info.get_container(info);
const containerType = g.base_info.get_type(containerInfo);

let containerStruct, pointer;

if (containerType === GIInfoType.INTERFACE) {
// we are setting a vfunc provided by an interface
containerStruct = g.interface_info.get_iface_struct(containerInfo);
const klass = g.type_class.ref(
Reflect.getOwnMetadata("gi:gtype", this.constructor),
);
// get the pointer to the interface struct of this class
pointer = g.type_interface.peek(
klass,
g.registered_type_info.get_g_type(containerInfo),
);
} else {
// we are directly setting a vfunc provided by a class
containerStruct = g.object_info.get_class_struct(containerInfo);
pointer = g.type_class.ref(
Reflect.getOwnMetadata("gi:gtype", this.constructor),
);
}

const fieldInfo = g.struct_info.find_field(containerStruct, cName);

if (!fieldInfo) {
// This vfunc doesn't have a corresponding field in the class or
// interface struct
return;
}

const cb = createCallback(info, value, this);
const offset = g.field_info.get_offset(fieldInfo);
const dataView = new ExtendedDataView(
deref_buf(
pointer,
offset + 8,
offset,
),
);
dataView.setBigUint64(cast_ptr_u64(cb.pointer));
},
});
return;
Expand Down
55 changes: 49 additions & 6 deletions src/types/field.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { GFieldInfoFlags } from "../bindings/enums.js";
import { cast_ptr_u64, deref_buf } from "../base_utils/convert.ts";
import { GFieldInfoFlags, GIInfoType, GITypeTag } from "../bindings/enums.js";
import g from "../bindings/mod.js";
import { ExtendedDataView } from "../utils/dataview.js";
import { getName } from "../utils/string.ts";
import { boxArgument, unboxArgument } from "./argument.js";
import { createCallback } from "./callback.js";

export function handleField(
target,
Expand All @@ -18,6 +21,7 @@ export function handleField(

Object.defineProperty(target.prototype, name, {
enumerable: true,
configurable: true,
get() {
if (!(flags & GFieldInfoFlags.READABLE)) {
throw new Error(`Field ${name} is not readable`);
Expand All @@ -44,11 +48,50 @@ export function handleField(
throw new Error(`Field ${name} is not writable`);
}

g.field_info.set_field(
fieldInfo,
Reflect.getOwnMetadata("gi:ref", this),
boxArgument(type, value),
);
const tag = g.type_info.get_tag(type);

switch (tag) {
case GITypeTag.OBJECT:
case GITypeTag.STRUCT: {
console.warn(`cannot set complex field: ${name}`);
break;
}
case GITypeTag.INTERFACE: {
const info = g.type_info.get_interface(type);
switch (g.base_info.get_type(info)) {
case GIInfoType.CALLBACK: {
// create a callback and set it to the field's pointer
const cb = createCallback(info, value);
const offset = g.field_info.get_offset(fieldInfo);
const dataView = new ExtendedDataView(
deref_buf(
Reflect.getOwnMetadata("gi:ref", this),
offset + 8,
offset,
),
);
dataView.setBigUint64(cast_ptr_u64(cb.pointer));
break;
}
default: {
console.warn(`cannot set complex field: ${name}`);
break;
}
}
g.base_info.unref(info);
break;
}
default: {
const boxed = boxArgument(type, value);

g.field_info.set_field(
fieldInfo,
Reflect.getOwnMetadata("gi:ref", this),
boxed,
);
break;
}
}
},
});
}

0 comments on commit 3452c42

Please sign in to comment.