generateForAnnotatedElement method
- Element element,
- ConstantReader annotation,
- BuildStep buildStep
Implement to return source code to generate for element
.
This method is invoked based on finding elements annotated with an
instance of T
. The annotation
is provided as a ConstantReader
.
Supported return values include a single String or multiple String instances within an Iterable or Stream. It is also valid to return a Future of String, Iterable, or Stream. When multiple values are returned through an iterable or stream they will be deduplicated. Typically each value will be an independent unit of code and the deduplication prevents re-defining the same member multiple times. For example if multiple annotated elements may need a specific utility method available it can be output for each one, and the single deduplicated definition can be shared.
Implementations should return null
when no content is generated. Empty
or whitespace-only String instances are also ignored.
Implementation
@override
FutureOr<String> generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) async {
const keywords = {"in"};
final resp = await http.get(Uri.parse(
"https://rawgit.flutter-io.cn/KhronosGroup/OpenGL-Registry/refs/heads/main/xml/gl.xml"));
final document = XmlDocument.parse(utf8.decode(resp.bodyBytes));
final enumValues = <String, int>{};
final commandValues = <NativeSignature>[];
List<String> parts = [];
for (final type in coreTypes.entries) {
if (type.key.contains("*") || type.key == "void") {
continue;
}
parts.add(
"typedef ${type.key} = ${nativeTypeMapping[type.value] ?? type.value};");
}
parts.add("\n");
final enums = document.findAllElements('enums');
for (final enumsNode in enums) {
for (final enumNode in enumsNode.findElements("enum")) {
enumValues[enumNode.getAttribute("name")!] =
int.parse(enumNode.getAttribute("value")!);
}
}
final commands = document.findAllElements("commands");
for (final commandsNode
in commands.where((e) => e.getAttribute("namespace") == "GL")) {
final commandNodes = commandsNode.findElements("command");
for (final commandNode in commandNodes) {
final returnType = commandNode
.findElements("proto")
.first
.findElements("ptype")
.firstOrNull
?.innerText ??
"void";
final functionName = commandNode
.findElements("proto")
.first
.findElements("name")
.first
.innerText;
final paramsList = <(String, String)>[];
for (final param in commandNode.findAllElements("param")) {
String pType =
param.findElements("ptype").firstOrNull?.innerText ?? "void";
String pName = param.findElements("name").first.innerText;
if (keywords.contains(pName)) {
pName = "${pName}_";
}
if (param.innerText.contains("const")) {
pType = "const $pType";
}
if (param.innerText.contains("**") ||
param.innerText.contains("*const*")) {
pType = "$pType**";
} else if (param.innerText.contains("*")) {
pType = "$pType*";
}
paramsList.add((pType, pName));
}
final stringParams =
paramsList.map((e) => "${typeMapping[e.$1]} ${e.$2}");
parts.add(
"typedef _$functionName = ${typeMapping[returnType]} Function(${stringParams.join(", ")});");
final nativeParams = <(String, String)>[];
for (final param in paramsList) {
final ffiType = typeMapping[param.$1];
final nativeType = nativeTypeMapping[ffiType] ?? ffiType;
nativeParams.add((nativeType!, param.$2));
}
commandValues.add(NativeSignature(
nativeTypeMapping[typeMapping[returnType]] ?? returnType,
functionName,
nativeParams));
}
}
final feature = document
.findAllElements("feature")
.where((e) => e.getAttribute("name") == "GL_ES_VERSION_2_0")
.firstOrNull;
if (feature != null) {
for (final enumNode in feature.findAllElements("enum")) {
String enumName = enumNode.getAttribute("name")!;
parts.add(
' const GLenum $enumName = ${enumValues[enumName]!};',
);
}
parts.add("\n");
for (final command in feature.findAllElements("command")) {
String commandName = command.getAttribute("name")!;
if (_specialCases.containsKey(commandName)) {
parts.add(_specialCases[commandName]!);
} else {
final nativeSignature =
commandValues.where((e) => e.name == commandName).first;
final dartSignature =
"${nativeSignature.returnType} Function(${nativeSignature.params.map((e) => "${e.$1} ${e.$2}").join(', ')})";
parts.add(
" dynamic ${nativeSignature.name}(${nativeSignature.params.map((e) => "${e.$1} ${e.$2}").join(', ')}) {");
parts.add(
" return GL.dylib!.lookup<NativeFunction<_$commandName>>('$commandName').asFunction<$dartSignature>()(${nativeSignature.params.map((e) => e.$2).join(", ")});");
parts.add("}");
}
}
} else {
return '// No features';
}
return parts.join('\n');
}