Skip to content

Commit

Permalink
feat: Improve enum and Variant usability
Browse files Browse the repository at this point in the history
Change enums to not have unnecessary prefixes. Setup `Variant.getType` to return a `VariantType` enum instead of an integer. Add `Variant.cast<T>` to support getting an object from a Variant easily.

refs: #21
  • Loading branch information
fuzzybinary committed Oct 27, 2024
1 parent 963d165 commit f5abb87
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 25 deletions.
6 changes: 6 additions & 0 deletions src/dart/godot_dart/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.6.0

- Adjust generate global constats to avoid unnecessary prefixes.
- Have `Variant.getType` return `VariantType` instead of int.
- Add `Variant.cast` to support getting an object directly from a Variant.

## 0.5.2

- Fix `Future<void>` throwing an error when put in a Variant, which could happen with `async` signal recievers.
Expand Down
2 changes: 1 addition & 1 deletion src/dart/godot_dart/lib/src/core/property_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class PropertyInfo {
PropertyInfo({
required this.typeInfo,
required this.name,
this.hint = PropertyHint.propertyHintNone,
this.hint = PropertyHint.none,
this.hintString = '',
this.flags = 6, // PropertyUsage.propertyUsageDefault
});
Expand Down
10 changes: 8 additions & 2 deletions src/dart/godot_dart/lib/src/variant/variant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,20 @@ class Variant implements Finalizable {
_attachFinalizer();
}

int getType() {
return gde.ffiBindings.gde_variant_get_type(_opaque.cast());
VariantType getType() {
final cValue = gde.ffiBindings.gde_variant_get_type(_opaque.cast());
return VariantType.fromValue(cValue);
}

void constructCopy(GDExtensionTypePtr ptr) {
gde.ffiBindings.gde_variant_new_copy(ptr, nativePtr.cast());
}

T? cast<T>() {
var typeInfo = gde.dartBindings.getGodotTypeInfo(T);
return convertFromVariant(this, typeInfo) as T?;
}

void _attachFinalizer() {
finalizer.attach(this, _opaque.cast());
}
Expand Down
2 changes: 1 addition & 1 deletion src/dart/godot_dart/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: godot_dart
description: Dart bindings for the Godot game engine
repository: https://github.com/fuzzybinary/godot_dart
version: 0.5.2
version: 0.6.0

environment:
sdk: '>=3.2.0 <4.0.0'
Expand Down
69 changes: 65 additions & 4 deletions tools/binding_generator/lib/src/common_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -739,31 +739,92 @@ void writePtrReturn(ArgumentProxy argument, CodeSink o) {
o.p('$ret;');
}

// A map of enumTypes to prefixes that are different from their type name, and
// can be removed in Dart.
const removePrefixes = <String, String>{
'KeyModifierMask': 'keyMask',
'Variant.Type': 'type',
'Error': 'err',
'MethodFlags': 'methodFlag',
'PropertyUsageFlags': 'propertyUsage',
'Variant.Operator': 'op',
'Planes': 'plane',
};

// Reserved words that get used as enum names, and should instead
// default back to their original, prefixed names.
final reservedWordEnumNames = [
'default',
'const',
'static',
'in',
'index',
'new',
'class',
'continue',
];

Value _transformEnumValues(Value e, String name) {
final lowerEnumName = name.lowerFirstLetter();
String originalName = e.name.toLowerCamelCase();
String transformedName = originalName;
if (originalName != lowerEnumName && originalName.startsWith(lowerEnumName)) {
transformedName =
originalName.replaceFirst(lowerEnumName, '').lowerFirstLetter();
} else if (removePrefixes.containsKey(name)) {
final prefix = removePrefixes[name]!;
transformedName =
transformedName.replaceFirst(prefix, '').lowerFirstLetter();
}

// Don't allow keywords
if (transformedName == 'int') transformedName = 'integer';
if (transformedName == 'enum') transformedName = 'enumVal';
if (reservedWordEnumNames.contains(transformedName)) {
transformedName = originalName;
}

return Value(name: transformedName, value: e.value);
}

extension EnumTransform on BuiltinClassEnum {
List<Value> transformedValues() {
return values.map((e) => _transformEnumValues(e, name)).toList();
}
}

extension EnumTranform on GlobalEnumElement {
List<Value> transformedValues() {
return values.map((e) => _transformEnumValues(e, name)).toList();
}
}

void writeEnum(dynamic godotEnum, String? inClass, CodeSink o) {
String name;
List<Value> valueList;
bool isBitfield = false;
if (godotEnum is BuiltinClassEnum) {
name = godotEnum.name;
valueList = godotEnum.values;
valueList = godotEnum.transformedValues();
} else if (godotEnum is GlobalEnumElement) {
name = godotEnum.name;
valueList = godotEnum.values;
valueList = godotEnum.transformedValues();
isBitfield = godotEnum.isBitfield;
} else {
throw ArgumentError(
'Trying to write an enum that is of type ${godotEnum.runtimeType}');
}

var enumName = getEnumName(name, inClass);

o.b('enum $enumName {', () {
if (isBitfield) {
if (isBitfield && valueList.where((e) => e.name == 'none').isEmpty) {
o.p('none(0),');
}
for (int i = 0; i < valueList.length; ++i) {
final value = valueList[i];
final end = i == valueList.length - 1 ? ';' : ',';
o.p('${value.name.toLowerCamelCase()}(${value.value})$end');
o.p('${value.name}(${value.value})$end');
}
o.nl();

Expand Down
20 changes: 4 additions & 16 deletions tools/binding_generator/lib/src/godot_api_info.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:collection/collection.dart';
import 'package:tuple/tuple.dart';

import 'common_helpers.dart';
import 'godot_extension_api_json.dart';
import 'string_extensions.dart';
import 'type_helpers.dart';

enum TypeCategory {
Expand Down Expand Up @@ -98,26 +98,14 @@ class GodotApiInfo {
}

String findEnumValue(String type, String value) {
// Special case -- Vector3Axis was reimplemented
if (type == 'Vector3Axis') {
switch (value) {
case '0':
return 'Vector3Axis.x';
case '1':
return 'Vector3Axis.y';
case '2':
return 'Vector3Axis.z';
}
}

final godotEnum = enumMap[type];
if (godotEnum == null) return value;

List<Value> valueList;
if (godotEnum is BuiltinClassEnum) {
valueList = godotEnum.values;
valueList = godotEnum.transformedValues();
} else if (godotEnum is GlobalEnumElement) {
valueList = godotEnum.values;
valueList = godotEnum.transformedValues();
} else {
throw ArgumentError(
'Trying to write an enum that is of type ${godotEnum.runtimeType}');
Expand All @@ -126,7 +114,7 @@ class GodotApiInfo {
final foundValue = valueList
.firstWhereOrNull((element) => element.value.toString() == value);
if (foundValue != null) {
return '$type.${foundValue.name.toLowerCamelCase()}';
return '$type.${foundValue.name}';
}

return value;
Expand Down
4 changes: 4 additions & 0 deletions tools/binding_generator/lib/src/string_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ extension StringHelpers on String {
return lowerCamel.replaceRange(
0, 1, lowerCamel[0].toUpperCase().toString());
}

String lowerFirstLetter() {
return replaceRange(0, 1, this[0].toLowerCase().toString());
}
}
2 changes: 1 addition & 1 deletion tools/binding_generator/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version: 1.0.0
publish_to: none

environment:
sdk: '>=2.18.2 <3.0.0'
sdk: '>=3.5.0 <4.0.0'

dependencies:
collection: ^1.17.1
Expand Down

0 comments on commit f5abb87

Please sign in to comment.