|
1 | 1 | package com.github.elebras1.flecs.processor; |
2 | 2 |
|
3 | | -import com.palantir.javapoet.*; |
| 3 | +import com.github.elebras1.flecs.util.internal.codegen.CodeBuilder; |
| 4 | +import com.github.elebras1.flecs.util.internal.codegen.SourceFile; |
4 | 5 |
|
5 | | -import javax.lang.model.element.Modifier; |
| 6 | +import javax.lang.model.element.Element; |
6 | 7 | import javax.lang.model.element.PackageElement; |
7 | 8 | import javax.lang.model.element.TypeElement; |
8 | | -import javax.lang.model.element.Element; |
9 | 9 | import java.util.List; |
10 | | -import java.util.function.Supplier; |
11 | 10 |
|
12 | 11 | public class ComponentMapGenerator { |
13 | 12 |
|
14 | | - private static final ClassName COMPONENT_INTERFACE = ClassName.get("com.github.elebras1.flecs", "Component"); |
15 | | - private static final ClassName COMPONENT_VIEW_INTERFACE = ClassName.get("com.github.elebras1.flecs", "ComponentView"); |
16 | | - private static final ClassName COMPONENT_ROW_VIEW_INTERFACE = ClassName.get("com.github.elebras1.flecs", "ComponentRowView"); |
17 | 13 | private static final String MAP_PACKAGE = "com.github.elebras1.flecs"; |
18 | 14 | private static final String MAP_COMPONENT_CLASS_NAME = "ComponentMap"; |
19 | 15 |
|
20 | | - public JavaFile generateComponentMap(List<TypeElement> components) { |
21 | | - TypeSpec.Builder mapClass = TypeSpec.classBuilder(MAP_COMPONENT_CLASS_NAME) |
22 | | - .addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "$S", "unchecked").build()) |
23 | | - .addModifiers(Modifier.PUBLIC, Modifier.FINAL) |
24 | | - .addField(this.createComponentSizeField(components)) |
25 | | - .addField(this.createComponentsField()) |
26 | | - .addField(this.createComponentRowViewsField()) |
27 | | - .addField(this.createComponentViewsField()) |
28 | | - .addField(this.createClassValueField(components)) |
29 | | - .addStaticBlock(this.createStaticInitializer(components)) |
30 | | - .addMethod(this.createConstructor()) |
31 | | - .addMethod(this.createGetIndexMethod()) |
32 | | - .addMethod(this.createSizeMethod()) |
33 | | - .addMethod(this.createGetInstanceMethod()) |
34 | | - .addMethod(this.createGetViewMethod()) |
35 | | - .addMethod(this.createGetRowViewMethod()); |
36 | | - |
37 | | - return JavaFile.builder(MAP_PACKAGE, mapClass.build()) |
38 | | - .addFileComment("Generated by ComponentMapGenerator.") |
39 | | - .indent(" ") |
40 | | - .build(); |
41 | | - } |
| 16 | + public SourceFile generateComponentMap(List<TypeElement> components) { |
| 17 | + CodeBuilder body = new CodeBuilder(); |
42 | 18 |
|
43 | | - private FieldSpec createComponentSizeField(List<TypeElement> components) { |
44 | | - return FieldSpec.builder(int.class, "COMPONENT_COUNT", |
45 | | - Modifier.PRIVATE, |
46 | | - Modifier.STATIC, |
47 | | - Modifier.FINAL) |
48 | | - .initializer("$L", components.size()) |
49 | | - .build(); |
50 | | - } |
| 19 | + body.append("@SuppressWarnings(\"unchecked\")").newline(); |
| 20 | + body.append("public final class ComponentMap {").newline(); |
51 | 21 |
|
52 | | - private FieldSpec createComponentsField() { |
53 | | - return FieldSpec.builder(ArrayTypeName.of(ParameterizedTypeName.get( |
54 | | - COMPONENT_INTERFACE, WildcardTypeName.subtypeOf(Object.class))), |
55 | | - "COMPONENTS", |
56 | | - Modifier.PRIVATE, |
57 | | - Modifier.STATIC, |
58 | | - Modifier.FINAL |
59 | | - ).build(); |
60 | | - } |
| 22 | + body.indent4().append("private static final int COMPONENT_COUNT = ").append(components.size()).append(";").newline(); |
61 | 23 |
|
62 | | - private FieldSpec createComponentViewsField() { |
63 | | - ParameterizedTypeName supplierType = ParameterizedTypeName.get(ClassName.get(Supplier.class), COMPONENT_VIEW_INTERFACE); |
64 | | - return FieldSpec.builder( |
65 | | - ArrayTypeName.of(supplierType), |
66 | | - "VIEWS", |
67 | | - Modifier.PRIVATE, |
68 | | - Modifier.STATIC, |
69 | | - Modifier.FINAL |
70 | | - ).build(); |
71 | | - } |
| 24 | + body.newline(); |
| 25 | + body.indent4().append("private static final Component<?>[] COMPONENTS;").newline(); |
72 | 26 |
|
73 | | - private FieldSpec createComponentRowViewsField() { |
74 | | - ParameterizedTypeName supplierType = ParameterizedTypeName.get(ClassName.get(Supplier.class), COMPONENT_ROW_VIEW_INTERFACE); |
75 | | - return FieldSpec.builder( |
76 | | - ArrayTypeName.of(supplierType), |
77 | | - "ROW_VIEWS", |
78 | | - Modifier.PRIVATE, |
79 | | - Modifier.STATIC, |
80 | | - Modifier.FINAL |
81 | | - ).build(); |
82 | | - } |
| 27 | + body.newline(); |
| 28 | + body.indent4().append("private static final Supplier<ComponentRowView>[] ROW_VIEWS;").newline(); |
83 | 29 |
|
84 | | - private FieldSpec createClassValueField(List<TypeElement> components) { |
85 | | - ParameterizedTypeName classValueType = ParameterizedTypeName.get( |
86 | | - ClassName.get(ClassValue.class), ClassName.get(Integer.class)); |
87 | | - |
88 | | - TypeSpec anonymousClassValue = TypeSpec.anonymousClassBuilder("") |
89 | | - .superclass(classValueType) |
90 | | - .addMethod(MethodSpec.methodBuilder("computeValue") |
91 | | - .addAnnotation(Override.class) |
92 | | - .addModifiers(Modifier.PROTECTED) |
93 | | - .returns(ClassName.get(Integer.class)) |
94 | | - .addParameter(ParameterizedTypeName.get(ClassName.get(Class.class), WildcardTypeName.subtypeOf(Object.class)), "clazz") |
95 | | - .addCode(this.createComputeValueBody(components)) |
96 | | - .build()) |
97 | | - .build(); |
98 | | - |
99 | | - return FieldSpec.builder(classValueType, "COMPONENT_INDEX", |
100 | | - Modifier.PRIVATE, |
101 | | - Modifier.STATIC, |
102 | | - Modifier.FINAL) |
103 | | - .initializer("$L", anonymousClassValue) |
104 | | - .build(); |
105 | | - } |
| 30 | + body.newline(); |
| 31 | + body.indent4().append("private static final Supplier<ComponentView>[] VIEWS;").newline(); |
106 | 32 |
|
107 | | - private CodeBlock createComputeValueBody(List<TypeElement> components) { |
108 | | - CodeBlock.Builder builder = CodeBlock.builder(); |
109 | | - int index = 0; |
110 | | - for (TypeElement component : components) { |
| 33 | + body.newline(); |
| 34 | + body.indent4().append("private static final ClassValue<Integer> COMPONENT_INDEX = new ClassValue<Integer>() {").newline(); |
| 35 | + body.indent8().append("@Override").newline(); |
| 36 | + body.indent8().append("protected Integer computeValue(Class<?> clazz) {").newline(); |
| 37 | + for (int i = 0; i < components.size(); i++) { |
| 38 | + TypeElement component = components.get(i); |
111 | 39 | String packageName = this.getPackageName(component); |
112 | 40 | String recordName = component.getSimpleName().toString(); |
113 | | - ClassName recordClass = ClassName.get(packageName, recordName); |
114 | | - builder.addStatement("if (clazz == $T.class) return $L", recordClass, index++); |
| 41 | + String fqn = packageName.isEmpty() ? recordName : packageName + "." + recordName; |
| 42 | + body.indent12().append("if (clazz == ").append(fqn).append(".class) return ").append(i).append(";").newline(); |
115 | 43 | } |
116 | | - builder.addStatement("return -1"); |
117 | | - return builder.build(); |
118 | | - } |
| 44 | + body.indent12().append("return -1;").newline(); |
| 45 | + body.indent8().append("}").newline(); |
| 46 | + body.indent4().append("};").newline(); |
119 | 47 |
|
120 | | - private CodeBlock createStaticInitializer(List<TypeElement> components) { |
121 | | - CodeBlock.Builder builder = CodeBlock.builder(); |
| 48 | + body.newline(); |
| 49 | + body.indent4().append("static {").newline(); |
122 | 50 |
|
123 | | - builder.add("COMPONENTS = new $T[] {\n", ParameterizedTypeName.get(COMPONENT_INTERFACE, WildcardTypeName.subtypeOf(Object.class))); |
| 51 | + body.indent8().append("COMPONENTS = new Component<?>[] {").newline(); |
124 | 52 | for (TypeElement component : components) { |
125 | 53 | String packageName = this.getPackageName(component); |
126 | 54 | String recordName = component.getSimpleName().toString(); |
127 | | - ClassName componentClass = ClassName.get(packageName, recordName + "Component"); |
128 | | - builder.add(" $T.getInstance(),\n", componentClass); |
| 55 | + String fqn = packageName.isEmpty() ? recordName + "Component" : packageName + "." + recordName + "Component"; |
| 56 | + body.indent12().append(fqn).append(".getInstance(),").newline(); |
129 | 57 | } |
130 | | - builder.add("};\n\n"); |
| 58 | + body.indent8().append("};").newline(); |
| 59 | + body.newline(); |
131 | 60 |
|
132 | | - builder.add("VIEWS = new $T[] {\n", ClassName.get(Supplier.class)); |
| 61 | + body.indent8().append("VIEWS = new Supplier[] {").newline(); |
133 | 62 | for (TypeElement component : components) { |
134 | 63 | String packageName = this.getPackageName(component); |
135 | 64 | String recordName = component.getSimpleName().toString(); |
136 | | - ClassName viewClass = ClassName.get(packageName, recordName + "View"); |
137 | | - builder.add(" $T::new,\n", viewClass); |
| 65 | + String fqn = packageName.isEmpty() ? recordName + "View" : packageName + "." + recordName + "View"; |
| 66 | + body.indent12().append(fqn).append("::new,").newline(); |
138 | 67 | } |
139 | | - builder.add("};\n"); |
| 68 | + body.indent8().append("};").newline(); |
140 | 69 |
|
141 | | - builder.add("ROW_VIEWS = new $T[] {\n", ClassName.get(Supplier.class)); |
| 70 | + body.indent8().append("ROW_VIEWS = new Supplier[] {").newline(); |
142 | 71 | for (TypeElement component : components) { |
143 | 72 | String packageName = this.getPackageName(component); |
144 | 73 | String recordName = component.getSimpleName().toString(); |
145 | | - ClassName rowViewClass = ClassName.get(packageName, recordName + "RowView"); |
146 | | - builder.add(" $T::new,\n", rowViewClass); |
| 74 | + String fqn = packageName.isEmpty() ? recordName + "RowView" : packageName + "." + recordName + "RowView"; |
| 75 | + body.indent12().append(fqn).append("::new,").newline(); |
147 | 76 | } |
148 | | - builder.add("};\n"); |
149 | | - |
150 | | - return builder.build(); |
151 | | - } |
152 | | - |
153 | | - private MethodSpec createConstructor() { |
154 | | - return MethodSpec.constructorBuilder() |
155 | | - .addModifiers(Modifier.PRIVATE) |
156 | | - .build(); |
157 | | - } |
158 | | - |
159 | | - private MethodSpec createGetIndexMethod() { |
160 | | - return MethodSpec.methodBuilder("getIndex") |
161 | | - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) |
162 | | - .addParameter(ParameterizedTypeName.get(ClassName.get(Class.class), WildcardTypeName.subtypeOf(Object.class)), "componentClass") |
163 | | - .returns(TypeName.INT) |
164 | | - .addStatement("return COMPONENT_INDEX.get(componentClass)") |
165 | | - .build(); |
166 | | - } |
167 | | - |
168 | | - private MethodSpec createSizeMethod() { |
169 | | - return MethodSpec.methodBuilder("size") |
170 | | - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) |
171 | | - .returns(TypeName.INT) |
172 | | - .addStatement("return COMPONENT_COUNT") |
173 | | - .build(); |
174 | | - } |
175 | | - |
176 | | - private MethodSpec createGetInstanceMethod() { |
177 | | - return MethodSpec.methodBuilder("getInstance") |
178 | | - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) |
179 | | - .addTypeVariable(TypeVariableName.get("T")) |
180 | | - .addParameter(ParameterizedTypeName.get(ClassName.get(Class.class), TypeVariableName.get("T")), "componentClass") |
181 | | - .returns(ParameterizedTypeName.get(COMPONENT_INTERFACE, TypeVariableName.get("T"))) |
182 | | - .addStatement("int index = COMPONENT_INDEX.get(componentClass)") |
183 | | - .addStatement("return index >= 0 ? ($T<T>) COMPONENTS[index] : null", COMPONENT_INTERFACE) |
184 | | - .build(); |
185 | | - } |
186 | | - |
187 | | - private MethodSpec createGetViewMethod() { |
188 | | - ParameterizedTypeName supplierType = ParameterizedTypeName.get(ClassName.get(Supplier.class), COMPONENT_VIEW_INTERFACE); |
189 | | - |
190 | | - return MethodSpec.methodBuilder("getView") |
191 | | - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) |
192 | | - .addTypeVariable(TypeVariableName.get("T")) |
193 | | - .addParameter(ParameterizedTypeName.get(ClassName.get(Class.class), TypeVariableName.get("T")), "componentClass") |
194 | | - .returns(COMPONENT_VIEW_INTERFACE) |
195 | | - .addStatement("int index = COMPONENT_INDEX.get(componentClass)") |
196 | | - .addStatement("$T supplier = index >= 0 ? VIEWS[index] : null", supplierType) |
197 | | - .addStatement("return supplier != null ? supplier.get() : null") |
198 | | - .build(); |
199 | | - } |
200 | | - |
201 | | - private MethodSpec createGetRowViewMethod() { |
202 | | - ParameterizedTypeName supplierType = ParameterizedTypeName.get(ClassName.get(Supplier.class), COMPONENT_ROW_VIEW_INTERFACE); |
203 | | - |
204 | | - return MethodSpec.methodBuilder("getRowView") |
205 | | - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) |
206 | | - .addTypeVariable(TypeVariableName.get("T")) |
207 | | - .addParameter(ParameterizedTypeName.get(ClassName.get(Class.class), TypeVariableName.get("T")), "componentClass") |
208 | | - .returns(COMPONENT_ROW_VIEW_INTERFACE) |
209 | | - .addStatement("int index = COMPONENT_INDEX.get(componentClass)") |
210 | | - .addStatement("$T supplier = index >= 0 ? ROW_VIEWS[index] : null", supplierType) |
211 | | - .addStatement("return supplier != null ? supplier.get() : null") |
| 77 | + body.indent8().append("};").newline(); |
| 78 | + |
| 79 | + body.indent4().append("}").newline(); |
| 80 | + |
| 81 | + body.newline(); |
| 82 | + body.indent4().append("private ComponentMap() {").newline(); |
| 83 | + body.indent4().append("}").newline(); |
| 84 | + |
| 85 | + body.newline(); |
| 86 | + body.indent4().append("public static int getIndex(Class<?> componentClass) {").newline(); |
| 87 | + body.indent8().append("return COMPONENT_INDEX.get(componentClass);").newline(); |
| 88 | + body.indent4().append("}").newline(); |
| 89 | + |
| 90 | + body.newline(); |
| 91 | + body.indent4().append("public static int size() {").newline(); |
| 92 | + body.indent8().append("return COMPONENT_COUNT;").newline(); |
| 93 | + body.indent4().append("}").newline(); |
| 94 | + |
| 95 | + body.newline(); |
| 96 | + body.indent4().append("public static <T> Component<T> getInstance(Class<T> componentClass) {").newline(); |
| 97 | + body.indent8().append("int index = COMPONENT_INDEX.get(componentClass);").newline(); |
| 98 | + body.indent8().append("return index >= 0 ? (Component<T>) COMPONENTS[index] : null;").newline(); |
| 99 | + body.indent4().append("}").newline(); |
| 100 | + |
| 101 | + body.newline(); |
| 102 | + body.indent4().append("public static <T> ComponentView getView(Class<T> componentClass) {").newline(); |
| 103 | + body.indent8().append("int index = COMPONENT_INDEX.get(componentClass);").newline(); |
| 104 | + body.indent8().append("Supplier<ComponentView> supplier = index >= 0 ? VIEWS[index] : null;").newline(); |
| 105 | + body.indent8().append("return supplier != null ? supplier.get() : null;").newline(); |
| 106 | + body.indent4().append("}").newline(); |
| 107 | + |
| 108 | + body.newline(); |
| 109 | + body.indent4().append("public static <T> ComponentRowView getRowView(Class<T> componentClass) {").newline(); |
| 110 | + body.indent8().append("int index = COMPONENT_INDEX.get(componentClass);").newline(); |
| 111 | + body.indent8().append("Supplier<ComponentRowView> supplier = index >= 0 ? ROW_VIEWS[index] : null;").newline(); |
| 112 | + body.indent8().append("return supplier != null ? supplier.get() : null;").newline(); |
| 113 | + body.indent4().append("}").newline(); |
| 114 | + |
| 115 | + body.append("}").newline(); |
| 116 | + |
| 117 | + return SourceFile.builder(MAP_PACKAGE, MAP_COMPONENT_CLASS_NAME) |
| 118 | + .fileComment("Generated by ComponentMapGenerator.") |
| 119 | + .addImport("com.github.elebras1.flecs.Component") |
| 120 | + .addImport("com.github.elebras1.flecs.ComponentRowView") |
| 121 | + .addImport("com.github.elebras1.flecs.ComponentView") |
| 122 | + .addImport("java.util.function.Supplier") |
| 123 | + .classBody(body.toString()) |
212 | 124 | .build(); |
213 | 125 | } |
214 | 126 |
|
|
0 commit comments