Skip to content

Commit

Permalink
Merge pull request #88 from jwharm/value-type-constructors
Browse files Browse the repository at this point in the history
Value type constructors
  • Loading branch information
jwharm authored Mar 27, 2024
2 parents 3214d97 + 6841e2f commit f872c68
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ dependencies {
}

group = 'io.github.jwharm.javagi'
version = '0.9.0'
version = '0.9.1-SNAPSHOT'

java {
if (! System.getenv('CI')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.util.List;
import java.util.stream.Collectors;

import com.squareup.javapoet.*;
import io.github.jwharm.javagi.configuration.ClassNames;
Expand Down Expand Up @@ -105,10 +106,13 @@ public TypeSpec generate() {
MethodSpec memoryLayout = new MemoryLayoutGenerator().generateMemoryLayout(rec);
if (memoryLayout != null) {
builder.addMethod(memoryLayout);
builder.addMethod(constructor());
builder.addMethod(allocate());

if (outerClass == null && hasFieldSetters())
if (outerClass == null && hasFieldSetters()) {
builder.addMethod(constructorWithParameters());
builder.addMethod(allocateWithParameters());
}

for (Field f : rec.fields())
generateField(f);
Expand Down Expand Up @@ -199,14 +203,68 @@ public void setFreeFunc(MethodSpec.Builder builder, String identifier, TypeName
}
}

private MethodSpec constructor() {
return MethodSpec.constructorBuilder()
.addJavadoc("""
Allocate a new $1T.
@param arena to control the memory allocation scope
""", rec.typeName())
.addModifiers(Modifier.PUBLIC)
.addParameter(Arena.class, "arena")
.addStatement("super(arena.allocate(getMemoryLayout()))")
.build();
}

private MethodSpec constructorWithParameters() {
var spec = MethodSpec.constructorBuilder()
.addJavadoc("""
Allocate a new $T with the fields set to the provided values.
@param arena to control the memory allocation scope
""", rec.typeName());

// Javadoc for parameters and return value
rec.fields().stream().filter(not(Field::isDisguised)).forEach(f ->
spec.addJavadoc("@param $1L $2L for the field {@code $1L}\n",
toJavaIdentifier(f.name()),
f.callback() == null ? "value" : "callback function")
);

// Set visibility, return type, and parameters
spec.addModifiers(Modifier.PUBLIC)
.addParameter(Arena.class, "arena");
rec.fields().stream().filter(not(Field::isDisguised)).forEach(f ->
spec.addParameter(
new TypedValueGenerator(f).getType(),
toJavaIdentifier(f.name()))
);

// Allocate the new instance
spec.addStatement("this(arena)");

// Copy the parameter values into the instance fields
rec.fields().stream().filter(not(Field::isDisguised)).forEach(f ->
spec.addStatement("$L$L($L$L)",
f.callback() == null ? "write" : "override",
toCamelCase(f.name(), true),
f.allocatesMemory() ? "arena, " : "",
toJavaIdentifier(f.name()))
);

return spec.build();
}

private MethodSpec allocate() {
return MethodSpec.methodBuilder("allocate")
.addJavadoc("""
Allocate a new $1T.
@param arena to control the memory allocation scope
@return a new, uninitialized {@link $1T}
""", rec.typeName())
@deprecated Replaced by {@link $1T#$1T($2T)}
""", rec.typeName(), Arena.class)
.addAnnotation(Deprecated.class)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(rec.typeName())
.addParameter(Arena.class, "arena")
Expand All @@ -225,7 +283,7 @@ private MethodSpec allocateWithParameters() {
var spec = MethodSpec.methodBuilder("allocate")
.addJavadoc("""
Allocate a new $T with the fields set to the provided values.
@param arena to control the memory allocation scope
""", rec.typeName());

Expand All @@ -238,6 +296,14 @@ private MethodSpec allocateWithParameters() {
spec.addJavadoc("@return a new {@link $T} with the fields set to the provided values\n",
rec.typeName());

String paramTypes = rec.fields().stream()
.filter(not(Field::isDisguised))
.map(f -> ", " + new TypedValueGenerator(f).getType().toString())
.collect(Collectors.joining());
spec.addJavadoc("@deprecated Replaced by {@link $1T#$1T($2T$3L)}\n",
rec.typeName(), Arena.class, paramTypes)
.addAnnotation(Deprecated.class);

// Set visibility, return type, and parameters
spec.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(rec.typeName())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.github.jwharm.javagi.util.GeneratedAnnotationBuilder;

import javax.lang.model.element.Modifier;
import java.lang.foreign.Arena;

public class UnionGenerator extends RegisteredTypeGenerator {

Expand All @@ -52,8 +53,10 @@ public TypeSpec generate() {
.addMethod(memoryAddressConstructor());

MethodSpec memoryLayout = new MemoryLayoutGenerator().generateMemoryLayout(union);
if (memoryLayout != null)
if (memoryLayout != null) {
builder.addMethod(memoryLayout);
builder.addMethod(constructor());
}

if (hasTypeMethod())
builder.addMethod(getTypeMethod());
Expand All @@ -63,4 +66,17 @@ public TypeSpec generate() {

return builder.build();
}

private MethodSpec constructor() {
return MethodSpec.constructorBuilder()
.addJavadoc("""
Allocate a new $1T.
@param arena to control the memory allocation scope
""", union.typeName())
.addModifiers(Modifier.PUBLIC)
.addParameter(Arena.class, "arena")
.addStatement("super(arena.allocate(getMemoryLayout()))")
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static void setProperty(GObject gobject, String propertyName, Object prop
GObject.ObjectClass gclass = (GObject.ObjectClass) gobject.readGClass();
Type valueType = readPropertyValueType(gclass, propertyName);
try (var arena = Arena.ofConfined()) {
var gvalue = Value.allocate(arena).init(valueType);
var gvalue = new Value(arena).init(valueType);
ValueUtil.objectToValue(propertyValue, gvalue);
gobject.setProperty(propertyName, gvalue);
gvalue.unset();
Expand All @@ -92,7 +92,7 @@ public static Object getProperty(GObject gobject, String propertyName) {
GObject.ObjectClass gclass = (GObject.ObjectClass) gobject.readGClass();
Type valueType = readPropertyValueType(gclass, propertyName);
try (var arena = Arena.ofConfined()) {
var gvalue = Value.allocate(arena).init(valueType);
var gvalue = new Value(arena).init(valueType);
gobject.getProperty(propertyName, gvalue);
Object result = ValueUtil.valueToObject(gvalue);
gvalue.unset();
Expand Down Expand Up @@ -150,7 +150,7 @@ public static <T extends GObject> T newGObjectWithProperties(Type objectType, Ob
Type valueType = readPropertyValueType(objectClass, name);

// Create a GValue and write the object to it
Value gvalue = Value.allocate(arena).init(valueType);
Value gvalue = new Value(arena).init(valueType);
ValueUtil.objectToValue(object, gvalue);
values.add(gvalue);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public static Object emit(GObject gobject, String detailedSignal, Object... para

try (var arena = Arena.ofConfined()) {
// Query the parameter details of the signal
SignalQuery query = SignalQuery.allocate(arena);
SignalQuery query = new SignalQuery(arena);
GObjects.signalQuery(signalId.get(), query);

// Create an array of Types for the parameters
Expand All @@ -269,18 +269,18 @@ public static Object emit(GObject gobject, String detailedSignal, Object... para
var values = new Value[nParams+1];

// Allocation return value
var returnValue = Value.allocate(arena);
var returnValue = new Value(arena);
Type returnType = query.readReturnType();
if (! Types.NONE.equals(returnType))
returnValue.init(returnType);

// Set instance parameter
values[0] = Value.allocate(arena).init(gtype);
values[0] = new Value(arena).init(gtype);
values[0].setObject(gobject);

// Set other parameters
for (int i = 0; i < nParams; i++) {
values[i+1] = Value.allocate(arena).init(paramTypes[i]);
values[i+1] = new Value(arena).init(paramTypes[i]);
ValueUtil.objectToValue(params[i], values[i+1]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ public static <T extends GObject, TC extends GObject.ObjectClass> Type register(
continue;
}

InterfaceInfo interfaceInfo = InterfaceInfo.allocate(arena);
InterfaceInfo interfaceInfo = new InterfaceInfo(arena);
Consumer<TypeInterface> ifaceOverridesInit = Overrides.overrideInterfaceMethods(cls, iface);
Consumer<TypeInterface> ifaceInit = getInterfaceInit(cls, iface);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ public void instanceGtypeIsCorrect() {
@Test
public void writeAndReadProperty() {
// With manually created GValues
Value input = Value.allocate(Arena.ofAuto()).init(Types.STRING);
Value output = Value.allocate(Arena.ofAuto()).init(Types.STRING);
Value input = new Value(Arena.ofAuto()).init(Types.STRING);
Value output = new Value(Arena.ofAuto()).init(Types.STRING);
input.setString("test value");

TestObject object = GObject.newInstance(TestObject.gtype);
Expand All @@ -98,8 +98,8 @@ public void writeAndReadProperty() {
@Test
public void writeAndReadBooleanProperty() {
// With manually created GValues
Value input = Value.allocate(Arena.ofAuto()).init(Types.BOOLEAN);
Value output = Value.allocate(Arena.ofAuto()).init(Types.BOOLEAN);
Value input = new Value(Arena.ofAuto()).init(Types.BOOLEAN);
Value output = new Value(Arena.ofAuto()).init(Types.BOOLEAN);
input.setBoolean(true);
TestObject object = GObject.newInstance(TestObject.gtype);
object.setProperty("bool-property", input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ public class ValueToStringTest {

@Test
public void testValueToString() {
Value vInt = Value.allocate(Arena.ofAuto()).init(Types.INT);
Value vInt = new Value(Arena.ofAuto()).init(Types.INT);
vInt.setInt(123);
assertEquals("123", vInt.toString());

Value vBool = Value.allocate(Arena.ofAuto()).init(Types.BOOLEAN);
Value vBool = new Value(Arena.ofAuto()).init(Types.BOOLEAN);
vBool.setBoolean(true);
assertEquals("TRUE", vBool.toString());

Value vStr = Value.allocate(Arena.ofAuto()).init(Types.STRING);
Value vStr = new Value(Arena.ofAuto()).init(Types.STRING);
vStr.setString("abc");
assertEquals("\"abc\"", vStr.toString());
}
Expand Down

0 comments on commit f872c68

Please sign in to comment.