Skip to content

Commit

Permalink
Wrapper class for GHashTable that implements java.util.Map<K,V> (fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jwharm committed Oct 12, 2024
1 parent 453c9b5 commit 0fbca8a
Show file tree
Hide file tree
Showing 6 changed files with 1,095 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -315,25 +315,14 @@ PartialStatement marshalNativeToJava(Type type,
"$" + targetTypeTag + ":T.of(" + identifier + ")",
targetTypeTag, target.typeName());

if (type.checkIsGList() && target != null) {
// Generate constructor call for GList/GSList with generic element types
if (target != null && type.checkIsGList()) {
if (type.anyTypes() == null || type.anyTypes().size() > 1)
throw new UnsupportedOperationException("Unsupported element type: " + type);

PartialStatement elementConstructor = switch (type.anyTypes().getFirst()) {
case Type t when t.isString() -> PartialStatement.of("(_p -> $interop:T.getStringFrom(_p))", "interop", ClassNames.INTEROP);
case Type t when t.isMemorySegment() -> PartialStatement.of("(_p -> _p)");
case Array _ -> PartialStatement.of("(_p -> _p)");
case Type t when t.get() != null -> t.get().constructorName();
default -> throw new UnsupportedOperationException("Unsupported element type: " + type);
};

PartialStatement elementDestructor = switch (type.anyTypes().getFirst()) {
case Array _ -> PartialStatement.of("(_ -> {}) /* unsupported */");
case Type t when t.isString() -> null;
case Type t when t.isMemorySegment() -> PartialStatement.of("$glib:T::free", "glib", ClassNames.GLIB);
case Type t when t.get() != null -> t.get().destructorName();
default -> throw new UnsupportedOperationException("Unsupported element type: " + type);
};
// Generate lambdas or method references to create and destruct elements
PartialStatement elementConstructor = getElementConstructor(type, 0);
PartialStatement elementDestructor = getElementDestructor(type, 0);

// Get parent node (parameter, return value, ...)
Node parent = type.parent();
Expand All @@ -360,6 +349,20 @@ PartialStatement marshalNativeToJava(Type type,
return stmt;
}

// Generate constructor call for HashTable with generic types for keys and values
if (target != null && type.checkIsGHashTable()) {
if (type.anyTypes() == null || type.anyTypes().size() != 2)
throw new UnsupportedOperationException("Unsupported element type: " + type);

PartialStatement keyConstructor = getElementConstructor(type, 0);
PartialStatement valueConstructor = getElementConstructor(type, 1);

return PartialStatement.of("new $" + targetTypeTag + ":T(" + identifier + ", ",
targetTypeTag, type.typeName())
.add(keyConstructor).add(", ").add(valueConstructor).add(")");

}

if ((target instanceof Record && (!isTypeClass))
|| target instanceof Union
|| target instanceof Boxed
Expand Down Expand Up @@ -410,6 +413,26 @@ PartialStatement marshalNativeToJava(Type type,
return PartialStatement.of(identifier);
}

private static PartialStatement getElementConstructor(Type type, int child) {
return switch (type.anyTypes().get(child)) {
case Type t when t.isString() -> PartialStatement.of("$interop:T::getStringFrom", "interop", ClassNames.INTEROP);
case Type t when t.isMemorySegment() -> PartialStatement.of("(_p -> _p)");
case Array _ -> PartialStatement.of("(_p -> _p)");
case Type t when t.get() != null -> t.get().constructorName();
default -> throw new UnsupportedOperationException("Unsupported element type: " + type);
};
}

private static PartialStatement getElementDestructor(Type type, int child) {
return switch (type.anyTypes().get(child)) {
case Array _ -> PartialStatement.of("(_ -> {}) /* unsupported */");
case Type t when t.isString() -> null;
case Type t when t.isMemorySegment() -> PartialStatement.of("$glib:T::free", "glib", ClassNames.GLIB);
case Type t when t.get() != null -> t.get().destructorName();
default -> throw new UnsupportedOperationException("Unsupported element type: " + type);
};
}

private PartialStatement marshalNativeToJavaArray(Type type,
String size,
String identifier) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ default boolean checkIsGList() {
return cType() != null && List.of("GList", "GSList").contains(cType());
}

/** Return true if this is GHashTable */
default boolean checkIsGHashTable() {
return cType() != null && "GHashTable".equals(cType());
}

default boolean isFloating() {
// GObject has a ref_sink function, but we don't want to treat all
// GObjects as floating references.
Expand Down
28 changes: 19 additions & 9 deletions buildSrc/src/main/java/io/github/jwharm/javagi/gir/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ public List<AnyType> anyTypes() {

@Override
public TypeName typeName() {
if (checkIsGList())
return glistTypeName();
if (checkIsGList() || checkIsGHashTable())
return genericTypeName();

String javaBaseType = toJavaBaseType(name());
return switch(javaBaseType) {
Expand All @@ -76,16 +76,21 @@ public TypeName typeName() {
};
}

private TypeName glistTypeName() {
private TypeName genericTypeName() {
var target = get();
var rawType = toJavaQualifiedType(target.name(), target.namespace());
if (anyTypes().getFirst() instanceof Type t) {
return ParameterizedTypeName.get(rawType, t.typeName());
} else {
// Fallback to pointer for a list of arrays
TypeName pointer = TypeName.get(MemorySegment.class);
return ParameterizedTypeName.get(rawType, pointer);
var elements = new TypeName[anyTypes().size()];
int i = 0;
for (var anyType : anyTypes()) {
if (anyType instanceof Type t)
elements[i++] = t.typeName();
else {
// Fallback to pointer for a list of arrays
TypeName pointer = TypeName.get(MemorySegment.class);
return ParameterizedTypeName.get(rawType, pointer);
}
}
return ParameterizedTypeName.get(rawType, elements);
}

public boolean isPrimitive() {
Expand Down Expand Up @@ -145,6 +150,11 @@ public boolean checkIsGList() {
return target != null && target.checkIsGList();
}

public boolean checkIsGHashTable() {
RegisteredType target = get();
return target != null && target.checkIsGHashTable();
}

public boolean isActuallyAnArray() {
return cType() != null && cType().endsWith("**")
&& (! (parent() instanceof Parameter p && p.isOutParameter()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,13 @@ public GirElement patch(GirElement element, String namespace) {
}

/*
* GLib.List and GLib.SList are not generated from the gir data.
* Java-GI provides custom List and SList classes that implement
* java.util.List, to make them easier to use from Java.
* GLib.HashTable, GLib.List and GLib.SList are not generated from the
* gir data. Java-GI provides custom HashTable, List and SList classes
* that implement java.util.Map or java.util.List, to make them easier
* to use from Java.
*/
if (element instanceof Record r
&& List.of("List", "SList").contains(r.name()))
&& List.of("HashTable", "List", "SList").contains(r.name()))
return r.withAttribute("java-gi-skip", "1");

return element;
Expand Down
Loading

0 comments on commit 0fbca8a

Please sign in to comment.