From 8a133cbe0c14416a2d49cb65098df5c9841ebb93 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Mon, 12 Oct 2026 16:26:03 +0200 Subject: [PATCH] Generate the enums of jmeos-core from the catalog FunctionsGenerator writes one Java enum per enum the catalog states for the public surface, beside GeneratedFunctions: the enums of the public headers of an enabled family, neither those of meos_internal.h nor those of a vendored library. Each keeps its C name and the value MEOS gives each constant, and getValue() answers that value, so a call passing an enum constant to MEOS passes the number MEOS reads. Over the catalog of MobilityDB ebf26ad0da and MEOS-API 9b337a00fe the generator writes 10 of the 14: errorCode, tempSubtype, interpType, IndexSearchOp, SPTreeKind, MeosType, MeosOper, spatialRel, nullHandleType and MeosPixType. The generated IndexSearchOp, with the 21 search operations of the in-memory indexes, takes the place of RTreeSearchOp, which declared 3 of them under the enum's former name, and MeosType and MeosOper take the place of utils.meosCatalog.MeosEnums, whose meosType declared 46 of the 89 values of MeosType, 44 of them with another number (T_DOUBLE2(2) against T_DOUBLE2 = 8), and whose meosOper declared 43 of 45. The catalog structs of jmeos-core hold a MeosType. A C type is an enum when the catalog states it, so the type map carries no list of enum names of its own; FunctionsGeneratorTest checks that a name the catalog states no enum of maps to a pointer, that an enum keeps its names and values, that only the enums of the public surface are written, and that run writes each enum beside the generated functions. --- codegen/src/main/java/FunctionsGenerator.java | 59 +++++++- .../src/test/java/FunctionsGeneratorTest.java | 84 ++++++++++- .../main/java/functions/RTreeSearchOp.java | 20 --- .../java/utils/meosCatalog/MeosEnums.java | 130 ------------------ .../meosCatalog/SettypeCatalogStruct.java | 14 +- .../meosCatalog/SpansettypeCatalogStruct.java | 14 +- .../meosCatalog/SpantypeCatalogStruct.java | 14 +- .../meosCatalog/TemptypeCatalogStruct.java | 14 +- 8 files changed, 158 insertions(+), 191 deletions(-) delete mode 100644 jmeos-core/src/main/java/functions/RTreeSearchOp.java delete mode 100644 jmeos-core/src/main/java/utils/meosCatalog/MeosEnums.java diff --git a/codegen/src/main/java/FunctionsGenerator.java b/codegen/src/main/java/FunctionsGenerator.java index f1f95aa9f..27b11bc9e 100644 --- a/codegen/src/main/java/FunctionsGenerator.java +++ b/codegen/src/main/java/FunctionsGenerator.java @@ -23,6 +23,8 @@ public class FunctionsGenerator { // Enum names extracted from the JSON "enums" section. // These are mapped to int in Java (JNR-FFI represents C enums as int). private final Set enumNames = new HashSet<>(); + /** The enums of the catalog, in its order, each written as a Java enum by {@link #writeEnumClasses}. */ + private final List enumDefs = new ArrayList<>(); /** Struct names the catalog defines, used to spot a by-value struct return. */ private final Set structNames = new HashSet<>(); /** Fields of each struct the catalog defines, keyed by struct name. */ @@ -241,6 +243,7 @@ private void run(String inputPath, String outputPath) throws IOException { Files.createDirectories(out.getParent()); Files.writeString(out, content); System.out.println("Written: " + out.toAbsolutePath()); + writeEnumClasses(out.getParent()); System.out.println("=== Done ==="); } @@ -481,11 +484,61 @@ private void collectEnumNames(JsonNode root) { JsonNode nameNode = e.get("name"); if (nameNode != null) { enumNames.add(nameNode.asText()); + enumDefs.add(e); } } } } + /** + * Writes one Java enum per enum of the catalog a binding reaches, under its C name and with + * the values MEOS gives its constants, beside {@code GeneratedFunctions}: the enums of the + * public headers of an enabled family, neither those of {@code meos_internal.h} nor those of + * a vendored library. + */ + private void writeEnumClasses(Path dir) throws IOException { + int written = 0; + for (JsonNode e : enumDefs) { + if (emitsEnum(e)) { + Files.writeString(dir.resolve(e.get("name").asText() + ".java"), enumSource(e)); + written++; + } + } + System.out.println("Enums written: " + written + " of " + enumDefs.size()); + } + + /** Whether the enum belongs to the public surface this run generates. */ + private boolean emitsEnum(JsonNode e) { + JsonNode file = e.get("file"); + JsonNode vendored = e.get("vendored"); + return (vendored == null || !vendored.asBoolean()) + && (file == null || !file.asText().startsWith("meos_internal")) + && familyEnabled(familyOf(e)); + } + + /** The Java source of an enum of the catalog. */ + static String enumSource(JsonNode e) { + String name = e.get("name").asText(); + JsonNode file = e.get("file"); + StringBuilder sb = new StringBuilder("package functions;\n\n"); + sb.append("/** {@code ").append(name).append("} as ") + .append(file == null ? "MEOS" : "{@code " + file.asText() + "}") + .append(" declares it. */\n"); + sb.append("public enum ").append(name).append(" {\n"); + JsonNode values = e.get("values"); + for (int i = 0; i < values.size(); i++) { + JsonNode v = values.get(i); + sb.append("\t").append(v.get("name").asText()).append("(").append(v.get("value").asLong()) + .append(i + 1 < values.size() ? "),\n" : ");\n"); + } + sb.append("\n\tprivate final int value;\n\n"); + sb.append("\t").append(name).append("(int value) {\n\t\tthis.value = value;\n\t}\n\n"); + sb.append("\t/** The value MEOS gives this constant. */\n"); + sb.append("\tpublic int getValue() {\n\t\treturn value;\n\t}\n"); + sb.append("}\n"); + return sb.toString(); + } + private FunctionDef parseFunctionDef(JsonNode fn) { String name = fn.get("name").asText(); @@ -609,10 +662,6 @@ private String mapCTypeToJava(String cType) { // becomes Pointer, breaking every h3index/th3index binding. case "H3Index" -> "long"; - // Explicit enum names (in case not in JSON enums section) - case "interpType", "RTreeSearchOp", - "tempSubtype", "spatialRel", - "errorCode" -> "int"; default -> "Pointer"; }; } @@ -781,8 +830,6 @@ private String generateFile(List functions) { import jnr.ffi.byref.PointerByReference; import jnr.ffi.Struct; import utils.JarLibraryLoader; - import utils.meosCatalog.MeosEnums.meosType; - import utils.meosCatalog.MeosEnums.meosOper; import functions.MeosErrorHandler; import java.time.*; diff --git a/codegen/src/test/java/FunctionsGeneratorTest.java b/codegen/src/test/java/FunctionsGeneratorTest.java index e83782009..192fd2240 100644 --- a/codegen/src/test/java/FunctionsGeneratorTest.java +++ b/codegen/src/test/java/FunctionsGeneratorTest.java @@ -163,10 +163,10 @@ void unknownType() throws Exception { } @ParameterizedTest - @ValueSource(strings = {"interpType", "RTreeSearchOp", "tempSubtype", "spatialRel", "errorCode"}) - @DisplayName("explicit enum names → int") - void explicitEnums(String cType) throws Exception { - assertEquals("int", mapJava(cType)); + @ValueSource(strings = {"interpType", "IndexSearchOp", "tempSubtype", "spatialRel", "errorCode"}) + @DisplayName("a name the catalog states no enum of is not an enum") + void enumOnlyFromCatalog(String cType) throws Exception { + assertEquals("Pointer", mapJava(cType)); } @Test @@ -376,7 +376,7 @@ void enumsPresent() throws Exception { String json = """ { "enums": [ - {"name": "RTreeSearchOp"}, + {"name": "IndexSearchOp"}, {"name": "interpType"} ], "functions": [] @@ -396,7 +396,7 @@ void enumsPresent() throws Exception { @SuppressWarnings("unchecked") Set names = (Set) enumNamesField.get(generator); - assertTrue(names.contains("RTreeSearchOp")); + assertTrue(names.contains("IndexSearchOp")); assertTrue(names.contains("interpType")); assertEquals(2, names.size()); } @@ -418,6 +418,76 @@ void noEnumsSection() throws Exception { } } + // ========================================================================= + // The Java enums of the catalog + // ========================================================================= + + @Nested + @DisplayName("enum classes") + class EnumClassTests { + + private JsonNode enumNode(String json) throws Exception { + return new ObjectMapper().readTree(json); + } + + private boolean emits(JsonNode e) throws Exception { + Method m = FunctionsGenerator.class.getDeclaredMethod("emitsEnum", JsonNode.class); + m.setAccessible(true); + return (boolean) m.invoke(generator, e); + } + + @Test + @DisplayName("an enum keeps its C name and the value MEOS gives each constant") + void enumSourceKeepsNamesAndValues() throws Exception { + String src = FunctionsGenerator.enumSource(enumNode(""" + {"name": "MeosType", "file": "meos_catalog.h", "family": "CORE", + "values": [{"name": "T_UNKNOWN", "value": 0}, {"name": "T_DOUBLE2", "value": 8}, + {"name": "T_FLOAT8", "value": 11}]} + """)); + assertTrue(src.startsWith("package functions;")); + assertTrue(src.contains("public enum MeosType {")); + assertTrue(src.contains("\tT_UNKNOWN(0),\n\tT_DOUBLE2(8),\n\tT_FLOAT8(11);\n")); + assertTrue(src.contains("public int getValue()")); + } + + @Test + @DisplayName("the enums of a public header are written, internal and vendored ones are not") + void emitsPublicEnumsOnly() throws Exception { + assertTrue(emits(enumNode(""" + {"name": "IndexSearchOp", "file": "meos.h", "family": "CORE", "vendored": false, + "values": [{"name": "INDEX_OVERLAPS", "value": 0}]} + """))); + assertFalse(emits(enumNode(""" + {"name": "SkipListType", "file": "meos_internal.h", "family": "CORE", "vendored": false, + "values": [{"name": "TIMESTAMPTZ", "value": 0}]} + """))); + assertFalse(emits(enumNode(""" + {"name": "ENDIANS", "file": "pc_api.h", "family": "POINTCLOUD", "vendored": true, + "values": [{"name": "PC_XDR", "value": 0}]} + """))); + } + + @Test + @DisplayName("run writes each enum beside the generated functions") + void runWritesEnumFiles() throws Exception { + Path input = tempDir.resolve("idl.json"); + Files.writeString(input, """ + {"enums": [{"name": "IndexSearchOp", "file": "meos.h", "family": "CORE", + "values": [{"name": "INDEX_OVERLAPS", "value": 0}, + {"name": "INDEX_ADJACENT", "value": 20}]}, + {"name": "SkipListType", "file": "meos_internal.h", "family": "CORE", + "values": [{"name": "TIMESTAMPTZ", "value": 0}]}], + "functions": []} + """); + Path out = tempDir.resolve("functions/GeneratedFunctions.java"); + run.invoke(generator, input.toString(), out.toString()); + Path written = tempDir.resolve("functions/IndexSearchOp.java"); + assertTrue(Files.exists(written)); + assertTrue(Files.readString(written).contains("INDEX_ADJACENT(20);")); + assertFalse(Files.exists(tempDir.resolve("functions/SkipListType.java"))); + } + } + // ========================================================================= // run(): end-to-end / integration // ========================================================================= @@ -940,7 +1010,7 @@ void fileHeaderCorrect() throws Exception { void enumFromJsonSection() throws Exception { String json = """ { - "enums": [{"name": "MyOp"}], + "enums": [{"name": "MyOp", "file": "meos.h", "family": "CORE", "values": [{"name": "MY_OP", "value": 0}]}], "functions": [{ "name": "do_op", "returnType": {"c": "void"}, diff --git a/jmeos-core/src/main/java/functions/RTreeSearchOp.java b/jmeos-core/src/main/java/functions/RTreeSearchOp.java deleted file mode 100644 index cd00d8b14..000000000 --- a/jmeos-core/src/main/java/functions/RTreeSearchOp.java +++ /dev/null @@ -1,20 +0,0 @@ -package functions; - -public enum RTreeSearchOp { - /** Find stored boxes that overlap the query */ - RTREE_OVERLAPS(0), - /** Find stored boxes that contain the query */ - RTREE_CONTAINS(1), - /** Find stored boxes contained by the query */ - RTREE_CONTAINED_BY(2); - - private final int value; - - RTreeSearchOp(int value) { - this.value = value; - } - - public int getValue() { - return value; - } -} diff --git a/jmeos-core/src/main/java/utils/meosCatalog/MeosEnums.java b/jmeos-core/src/main/java/utils/meosCatalog/MeosEnums.java deleted file mode 100644 index d088e2b46..000000000 --- a/jmeos-core/src/main/java/utils/meosCatalog/MeosEnums.java +++ /dev/null @@ -1,130 +0,0 @@ -package utils.meosCatalog; - - -/** - * Meos enumeration storing the type and operators through MEOS integer values. - * - * @author Nidhal Mareghni - * @since 18/10/2023 - */ -public class MeosEnums { - public enum meosType { - T_UNKNOWN(0), - T_BOOL(1), - T_DOUBLE2(2), - T_DOUBLE3(3), - T_DOUBLE4(4), - T_FLOAT8(5), - T_FLOATSET(6), - T_FLOATSPAN(7), - T_FLOATSPANSET(8), - T_INT4(9), - T_INT4RANGE(10), - T_INT4MULTIRANGE(11), - T_INTSET(12), - T_INTSPAN(13), - T_INTSPANSET(14), - T_INT8(15), - T_BIGINTSET(16), - T_BIGINTSPAN(17), - T_BIGINTSPANSET(18), - T_STBOX(19), - T_TBOOL(20), - T_TBOX(21), - T_TDOUBLE2(22), - T_TDOUBLE3(23), - T_TDOUBLE4(24), - T_TEXT(25), - T_TEXTSET(26), - T_TFLOAT(27), - T_TIMESTAMPTZ(28), - T_TINT(29), - T_TSTZMULTIRANGE(30), - T_TSTZRANGE(31), - T_TSTZSET(32), - T_TSTZSPAN(33), - T_TSTZSPANSET(34), - T_TTEXT(35), - T_GEOMETRY(36), - T_GEOMSET(37), - T_GEOGRAPHY(38), - T_GEOGSET(39), - T_TGEOMPOINT(40), - T_TGEOGPOINT(41), - T_NPOINT(42), - T_NPOINTSET(43), - T_NSEGMENT(44), - T_TNPOINT(45); - - private final int value; - - meosType(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - } - - - - - public enum meosOper { - UNKNOWN_OP(0), - EQ_OP(1), - NE_OP(2), - LT_OP(3), - LE_OP(4), - GT_OP(5), - GE_OP(6), - ADJACENT_OP(7), - UNION_OP(8), - MINUS_OP(9), - INTERSECT_OP(10), - OVERLAPS_OP(11), - CONTAINS_OP(12), - CONTAINED_OP(13), - SAME_OP(14), - LEFT_OP(15), - OVERLEFT_OP(16), - RIGHT_OP(17), - OVERRIGHT_OP(18), - BELOW_OP(19), - OVERBELOW_OP(20), - ABOVE_OP(21), - OVERABOVE_OP(22), - FRONT_OP(23), - OVERFRONT_OP(24), - BACK_OP(25), - OVERBACK_OP(26), - BEFORE_OP(27), - OVERBEFORE_OP(28), - AFTER_OP(29), - OVERAFTER_OP(30), - EVEREQ_OP(31), - EVERNE_OP(32), - EVERLT_OP(33), - EVERLE_OP(34), - EVERGT_OP(35), - EVERGE_OP(36), - ALWAYSEQ_OP(37), - ALWAYSNE_OP(38), - ALWAYSLT_OP(39), - ALWAYSLE_OP(40), - ALWAYSGT_OP(41), - ALWAYSGE_OP(42); - - private final int value; - - meosOper(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - } - - -} diff --git a/jmeos-core/src/main/java/utils/meosCatalog/SettypeCatalogStruct.java b/jmeos-core/src/main/java/utils/meosCatalog/SettypeCatalogStruct.java index 7bf31af83..300a2d37b 100644 --- a/jmeos-core/src/main/java/utils/meosCatalog/SettypeCatalogStruct.java +++ b/jmeos-core/src/main/java/utils/meosCatalog/SettypeCatalogStruct.java @@ -1,27 +1,27 @@ package utils.meosCatalog; -import utils.meosCatalog.MeosEnums.meosType; +import functions.MeosType; /** - * Class for setting set meosType in an object. + * Class for setting set MeosType in an object. * * @author Nidhal Mareghni * @since 18/10/2023 */ public class SettypeCatalogStruct { - private final meosType settype; - private final meosType basetype; + private final MeosType settype; + private final MeosType basetype; - public SettypeCatalogStruct(meosType settype, meosType basetype) { + public SettypeCatalogStruct(MeosType settype, MeosType basetype) { this.settype = settype; this.basetype = basetype; } - public meosType getSettype() { + public MeosType getSettype() { return settype; } - public meosType getBasetype() { + public MeosType getBasetype() { return basetype; } } diff --git a/jmeos-core/src/main/java/utils/meosCatalog/SpansettypeCatalogStruct.java b/jmeos-core/src/main/java/utils/meosCatalog/SpansettypeCatalogStruct.java index a7ac2df9f..633d558c9 100644 --- a/jmeos-core/src/main/java/utils/meosCatalog/SpansettypeCatalogStruct.java +++ b/jmeos-core/src/main/java/utils/meosCatalog/SpansettypeCatalogStruct.java @@ -1,27 +1,27 @@ package utils.meosCatalog; -import utils.meosCatalog.MeosEnums.meosType; +import functions.MeosType; /** - * Class for setting spanSet meosType in an object. + * Class for setting spanSet MeosType in an object. * * @author Nidhal Mareghni * @since 18/10/2023 */ public class SpansettypeCatalogStruct { - private final meosType spansettype; - private final meosType spantype; + private final MeosType spansettype; + private final MeosType spantype; - public SpansettypeCatalogStruct(meosType spansettype, meosType spantype) { + public SpansettypeCatalogStruct(MeosType spansettype, MeosType spantype) { this.spansettype = spansettype; this.spantype = spantype; } - public meosType getSpansettype() { + public MeosType getSpansettype() { return spansettype; } - public meosType getSpantype() { + public MeosType getSpantype() { return spantype; } } diff --git a/jmeos-core/src/main/java/utils/meosCatalog/SpantypeCatalogStruct.java b/jmeos-core/src/main/java/utils/meosCatalog/SpantypeCatalogStruct.java index 792c4bc71..75e30cc5c 100644 --- a/jmeos-core/src/main/java/utils/meosCatalog/SpantypeCatalogStruct.java +++ b/jmeos-core/src/main/java/utils/meosCatalog/SpantypeCatalogStruct.java @@ -1,27 +1,27 @@ package utils.meosCatalog; -import utils.meosCatalog.MeosEnums.meosType; +import functions.MeosType; /** - * Class for setting span meosType in an object. + * Class for setting span MeosType in an object. * * @author Nidhal Mareghni * @since 18/10/2023 */ public class SpantypeCatalogStruct { - private final meosType spantype; - private final meosType basetype; + private final MeosType spantype; + private final MeosType basetype; - public SpantypeCatalogStruct(meosType spantype, meosType basetype) { + public SpantypeCatalogStruct(MeosType spantype, MeosType basetype) { this.spantype = spantype; this.basetype = basetype; } - public meosType getSpantype() { + public MeosType getSpantype() { return spantype; } - public meosType getBasetype() { + public MeosType getBasetype() { return basetype; } } diff --git a/jmeos-core/src/main/java/utils/meosCatalog/TemptypeCatalogStruct.java b/jmeos-core/src/main/java/utils/meosCatalog/TemptypeCatalogStruct.java index 22e794e59..00f6bff38 100644 --- a/jmeos-core/src/main/java/utils/meosCatalog/TemptypeCatalogStruct.java +++ b/jmeos-core/src/main/java/utils/meosCatalog/TemptypeCatalogStruct.java @@ -1,27 +1,27 @@ package utils.meosCatalog; -import utils.meosCatalog.MeosEnums.meosType; +import functions.MeosType; /** - * Class for setting temporal meosType in an object. + * Class for setting temporal MeosType in an object. * * @author Nidhal Mareghni * @since 18/10/2023 */ public class TemptypeCatalogStruct { - private final meosType temptype; - private final meosType basetype; + private final MeosType temptype; + private final MeosType basetype; - public TemptypeCatalogStruct(meosType temptype, meosType basetype) { + public TemptypeCatalogStruct(MeosType temptype, MeosType basetype) { this.temptype = temptype; this.basetype = basetype; } - public meosType getTemptype() { + public MeosType getTemptype() { return temptype; } - public meosType getBasetype() { + public MeosType getBasetype() { return basetype; } }