[ffigen] Support for array parameters in functions, array workarounds in Structs (#18)
- Added multi-dimension array support in Struct using array-workaround config flag.
- Added support for arrays parameters in functions.
diff --git a/pkgs/ffigen/example/libclang-example/generated_bindings.dart b/pkgs/ffigen/example/libclang-example/generated_bindings.dart
index 8f19852..4fbfac3 100644
--- a/pkgs/ffigen/example/libclang-example/generated_bindings.dart
+++ b/pkgs/ffigen/example/libclang-example/generated_bindings.dart
@@ -71,17 +71,44 @@
ffi.Pointer<ffi.Void> _data_item_1;
ffi.Pointer<ffi.Void> _data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXCursor_data get data => _ArrayHelper_CXCursor_data(this, 3);
+ /// Helper for array `data`.
+ ArrayHelper_CXCursor_data_level0 get data =>
+ ArrayHelper_CXCursor_data_level0(this, [3], 0, 0);
}
-/// Helper for array data in struct CXCursor
-class _ArrayHelper_CXCursor_data {
+/// Helper for array `data` in struct `CXCursor`.
+class ArrayHelper_CXCursor_data_level0 {
final CXCursor _struct;
- final int length;
- _ArrayHelper_CXCursor_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXCursor_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ffi.Pointer<ffi.Void> operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._data_item_0;
+ case 1:
+ return _struct._data_item_1;
+ case 2:
+ return _struct._data_item_2;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, ffi.Pointer<ffi.Void> value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._data_item_0 = value;
break;
@@ -92,35 +119,9 @@
_struct._data_item_2 = value;
break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- ffi.Pointer<ffi.Void> operator [](int index) {
- switch (index) {
- case 0:
- return _struct._data_item_0;
- case 1:
- return _struct._data_item_1;
- case 2:
- return _struct._data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
class CXCursorAndRangeVisitor extends ffi.Struct {
@@ -152,18 +153,44 @@
@ffi.Uint64()
int _data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXFileUniqueID_data get data =>
- _ArrayHelper_CXFileUniqueID_data(this, 3);
+ /// Helper for array `data`.
+ ArrayHelper_CXFileUniqueID_data_level0 get data =>
+ ArrayHelper_CXFileUniqueID_data_level0(this, [3], 0, 0);
}
-/// Helper for array data in struct CXFileUniqueID
-class _ArrayHelper_CXFileUniqueID_data {
+/// Helper for array `data` in struct `CXFileUniqueID`.
+class ArrayHelper_CXFileUniqueID_data_level0 {
final CXFileUniqueID _struct;
- final int length;
- _ArrayHelper_CXFileUniqueID_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXFileUniqueID_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ int operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._data_item_0;
+ case 1:
+ return _struct._data_item_1;
+ case 2:
+ return _struct._data_item_2;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, int value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._data_item_0 = value;
break;
@@ -174,35 +201,9 @@
_struct._data_item_2 = value;
break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- int operator [](int index) {
- switch (index) {
- case 0:
- return _struct._data_item_0;
- case 1:
- return _struct._data_item_1;
- case 2:
- return _struct._data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
class CXGlobalOptFlags {
@@ -262,61 +263,55 @@
class CXIdxLoc extends ffi.Struct {
ffi.Pointer<ffi.Void> _ptr_data_item_0;
ffi.Pointer<ffi.Void> _ptr_data_item_1;
- ffi.Pointer<ffi.Void> _ptr_data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXIdxLoc_ptr_data get ptr_data =>
- _ArrayHelper_CXIdxLoc_ptr_data(this, 3);
+ /// Helper for array `ptr_data`.
+ ArrayHelper_CXIdxLoc_ptr_data_level0 get ptr_data =>
+ ArrayHelper_CXIdxLoc_ptr_data_level0(this, [2], 0, 0);
@ffi.Uint32()
int int_data;
}
-/// Helper for array ptr_data in struct CXIdxLoc
-class _ArrayHelper_CXIdxLoc_ptr_data {
+/// Helper for array `ptr_data` in struct `CXIdxLoc`.
+class ArrayHelper_CXIdxLoc_ptr_data_level0 {
final CXIdxLoc _struct;
- final int length;
- _ArrayHelper_CXIdxLoc_ptr_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXIdxLoc_ptr_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ffi.Pointer<ffi.Void> operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._ptr_data_item_0;
+ case 1:
+ return _struct._ptr_data_item_1;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, ffi.Pointer<ffi.Void> value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._ptr_data_item_0 = value;
break;
case 1:
_struct._ptr_data_item_1 = value;
break;
- case 2:
- _struct._ptr_data_item_2 = value;
- break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- ffi.Pointer<ffi.Void> operator [](int index) {
- switch (index) {
- case 0:
- return _struct._ptr_data_item_0;
- case 1:
- return _struct._ptr_data_item_1;
- case 2:
- return _struct._ptr_data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
class CXIdxObjCCategoryDeclInfo extends ffi.Struct {}
@@ -372,61 +367,55 @@
class CXSourceLocation extends ffi.Struct {
ffi.Pointer<ffi.Void> _ptr_data_item_0;
ffi.Pointer<ffi.Void> _ptr_data_item_1;
- ffi.Pointer<ffi.Void> _ptr_data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXSourceLocation_ptr_data get ptr_data =>
- _ArrayHelper_CXSourceLocation_ptr_data(this, 3);
+ /// Helper for array `ptr_data`.
+ ArrayHelper_CXSourceLocation_ptr_data_level0 get ptr_data =>
+ ArrayHelper_CXSourceLocation_ptr_data_level0(this, [2], 0, 0);
@ffi.Uint32()
int int_data;
}
-/// Helper for array ptr_data in struct CXSourceLocation
-class _ArrayHelper_CXSourceLocation_ptr_data {
+/// Helper for array `ptr_data` in struct `CXSourceLocation`.
+class ArrayHelper_CXSourceLocation_ptr_data_level0 {
final CXSourceLocation _struct;
- final int length;
- _ArrayHelper_CXSourceLocation_ptr_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXSourceLocation_ptr_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ffi.Pointer<ffi.Void> operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._ptr_data_item_0;
+ case 1:
+ return _struct._ptr_data_item_1;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, ffi.Pointer<ffi.Void> value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._ptr_data_item_0 = value;
break;
case 1:
_struct._ptr_data_item_1 = value;
break;
- case 2:
- _struct._ptr_data_item_2 = value;
- break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- ffi.Pointer<ffi.Void> operator [](int index) {
- switch (index) {
- case 0:
- return _struct._ptr_data_item_0;
- case 1:
- return _struct._ptr_data_item_1;
- case 2:
- return _struct._ptr_data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
/// Identifies a half-open character range in the source code.
@@ -436,11 +425,10 @@
class CXSourceRange extends ffi.Struct {
ffi.Pointer<ffi.Void> _ptr_data_item_0;
ffi.Pointer<ffi.Void> _ptr_data_item_1;
- ffi.Pointer<ffi.Void> _ptr_data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXSourceRange_ptr_data get ptr_data =>
- _ArrayHelper_CXSourceRange_ptr_data(this, 3);
+ /// Helper for array `ptr_data`.
+ ArrayHelper_CXSourceRange_ptr_data_level0 get ptr_data =>
+ ArrayHelper_CXSourceRange_ptr_data_level0(this, [2], 0, 0);
@ffi.Uint32()
int begin_int_data;
@@ -448,52 +436,47 @@
int end_int_data;
}
-/// Helper for array ptr_data in struct CXSourceRange
-class _ArrayHelper_CXSourceRange_ptr_data {
+/// Helper for array `ptr_data` in struct `CXSourceRange`.
+class ArrayHelper_CXSourceRange_ptr_data_level0 {
final CXSourceRange _struct;
- final int length;
- _ArrayHelper_CXSourceRange_ptr_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXSourceRange_ptr_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ffi.Pointer<ffi.Void> operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._ptr_data_item_0;
+ case 1:
+ return _struct._ptr_data_item_1;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, ffi.Pointer<ffi.Void> value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._ptr_data_item_0 = value;
break;
case 1:
_struct._ptr_data_item_1 = value;
break;
- case 2:
- _struct._ptr_data_item_2 = value;
- break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- ffi.Pointer<ffi.Void> operator [](int index) {
- switch (index) {
- case 0:
- return _struct._ptr_data_item_0;
- case 1:
- return _struct._ptr_data_item_1;
- case 2:
- return _struct._ptr_data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
/// Identifies an array of ranges.
@@ -554,20 +537,50 @@
int _int_data_item_1;
@ffi.Uint32()
int _int_data_item_2;
+ @ffi.Uint32()
+ int _int_data_item_3;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXToken_int_data get int_data =>
- _ArrayHelper_CXToken_int_data(this, 3);
+ /// Helper for array `int_data`.
+ ArrayHelper_CXToken_int_data_level0 get int_data =>
+ ArrayHelper_CXToken_int_data_level0(this, [4], 0, 0);
ffi.Pointer<ffi.Void> ptr_data;
}
-/// Helper for array int_data in struct CXToken
-class _ArrayHelper_CXToken_int_data {
+/// Helper for array `int_data` in struct `CXToken`.
+class ArrayHelper_CXToken_int_data_level0 {
final CXToken _struct;
- final int length;
- _ArrayHelper_CXToken_int_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXToken_int_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ int operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._int_data_item_0;
+ case 1:
+ return _struct._int_data_item_1;
+ case 2:
+ return _struct._int_data_item_2;
+ case 3:
+ return _struct._int_data_item_3;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, int value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._int_data_item_0 = value;
break;
@@ -577,36 +590,13 @@
case 2:
_struct._int_data_item_2 = value;
break;
+ case 3:
+ _struct._int_data_item_3 = value;
+ break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- int operator [](int index) {
- switch (index) {
- case 0:
- return _struct._int_data_item_0;
- case 1:
- return _struct._int_data_item_1;
- case 2:
- return _struct._int_data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
class CXTranslationUnitImpl extends ffi.Struct {}
@@ -618,58 +608,53 @@
ffi.Pointer<ffi.Void> _data_item_0;
ffi.Pointer<ffi.Void> _data_item_1;
- ffi.Pointer<ffi.Void> _data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXType_data get data => _ArrayHelper_CXType_data(this, 3);
+ /// Helper for array `data`.
+ ArrayHelper_CXType_data_level0 get data =>
+ ArrayHelper_CXType_data_level0(this, [2], 0, 0);
}
-/// Helper for array data in struct CXType
-class _ArrayHelper_CXType_data {
+/// Helper for array `data` in struct `CXType`.
+class ArrayHelper_CXType_data_level0 {
final CXType _struct;
- final int length;
- _ArrayHelper_CXType_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXType_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ffi.Pointer<ffi.Void> operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._data_item_0;
+ case 1:
+ return _struct._data_item_1;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, ffi.Pointer<ffi.Void> value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._data_item_0 = value;
break;
case 1:
_struct._data_item_1 = value;
break;
- case 2:
- _struct._data_item_2 = value;
- break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- ffi.Pointer<ffi.Void> operator [](int index) {
- switch (index) {
- case 0:
- return _struct._data_item_0;
- case 1:
- return _struct._data_item_1;
- case 2:
- return _struct._data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
/// Describes the kind of type
@@ -2572,6 +2557,7 @@
typedef _dart_clang_enableStackTraces = void Function();
+/// Returns non-zero if the ranges are the same, zero if they differ.
int clang_equalRanges_wrap(
ffi.Pointer<CXSourceRange> c1,
ffi.Pointer<CXSourceRange> c2,
diff --git a/pkgs/ffigen/example/libclang-example/pubspec.yaml b/pkgs/ffigen/example/libclang-example/pubspec.yaml
index d4dc2fd..832f111 100644
--- a/pkgs/ffigen/example/libclang-example/pubspec.yaml
+++ b/pkgs/ffigen/example/libclang-example/pubspec.yaml
@@ -59,5 +59,8 @@
unsigned long long: 8
enum: 4
- # Doc Comments for generated binings: Can be full, brief(default) or none
+ # False by default.
+ array-workaround: true
+
+ # Doc Comments for generated binings: Can be full, brief(default) or none.
comments: full
diff --git a/pkgs/ffigen/lib/src/code_generator/struc.dart b/pkgs/ffigen/lib/src/code_generator/struc.dart
index 4cb5152..5e2db56 100644
--- a/pkgs/ffigen/lib/src/code_generator/struc.dart
+++ b/pkgs/ffigen/lib/src/code_generator/struc.dart
@@ -43,6 +43,16 @@
}) : members = members ?? [],
super(name: name, dartDoc: dartDoc);
+ List<int> _getArrayDimensionLengths(Type type) {
+ final array = <int>[];
+ var startType = type;
+ while (startType.broadType == BroadType.ConstantArray) {
+ array.add(startType.length);
+ startType = startType.child;
+ }
+ return array;
+ }
+
@override
BindingString toBindingString(Writer w) {
final s = StringBuffer();
@@ -61,9 +71,9 @@
if (m.type.broadType == BroadType.ConstantArray) {
// TODO(5): Remove array helpers when inline array support arives.
final arrayHelper = ArrayHelper(
- helperClassName: '_ArrayHelper_${name}_${m.name}',
- elementType: m.type.elementType,
- length: 3,
+ helperClassGroupName: 'ArrayHelper_${name}_${m.name}',
+ elementType: m.type.getBaseArrayType(),
+ dimensions: _getArrayDimensionLengths(m.type),
name: m.name,
structName: name,
elementNamePrefix: '_${m.name}_item_',
@@ -104,19 +114,30 @@
// Helper bindings for struct array.
class ArrayHelper {
final Type elementType;
- final int length;
+ final List<int> dimensions;
final String structName;
final String name;
- final String helperClassName;
+ final String helperClassGroupName;
final String elementNamePrefix;
+ int _expandedArrayLength;
+ int get expandedArrayLength {
+ if (_expandedArrayLength != null) return _expandedArrayLength;
+
+ int arrayLength = 1;
+ for (final i in dimensions) {
+ arrayLength = arrayLength * i;
+ }
+ return arrayLength;
+ }
+
ArrayHelper({
@required this.elementType,
- @required this.length,
+ @required this.dimensions,
@required this.structName,
@required this.name,
- @required this.helperClassName,
+ @required this.helperClassGroupName,
@required this.elementNamePrefix,
});
@@ -126,76 +147,100 @@
final arrayDartType = elementType.getDartType(w);
final arrayCType = elementType.getCType(w);
- for (var i = 0; i < length; i++) {
+ for (int i = 0; i < expandedArrayLength; i++) {
if (elementType.isPrimitive) {
s.write(' @${arrayCType}()\n');
}
s.write(' ${arrayDartType} ${elementNamePrefix}$i;\n');
}
- s.write('/// helper for array, supports `[]` operator\n');
+ s.write('/// Helper for array `$name`.\n');
s.write(
- '$helperClassName get $name => ${helperClassName}(this, $length);\n');
+ '${helperClassGroupName}_level0 get $name => ${helperClassGroupName}_level0(this, $dimensions, 0, 0);\n');
return s.toString();
}
- /// Creates an array helper binding for struct array.
String helperClassString(Writer w) {
final s = StringBuffer();
-
final arrayType = elementType.getDartType(w);
+ for (int dim = 0; dim < dimensions.length; dim++) {
+ final helperClassName = '${helperClassGroupName}_level${dim}';
+ final structIdentifier = '_struct';
+ final dimensionsIdentifier = 'dimensions';
+ final levelIdentifier = 'level';
+ final absoluteIndexIdentifier = '_absoluteIndex';
+ final checkBoundsFunctionIdentifier = '_checkBounds';
+ final legthIdentifier = 'length';
- s.write('/// Helper for array $name in struct $structName\n');
+ s.write('/// Helper for array `$name` in struct `$structName`.\n');
- // Write class declaration.
- s.write('class $helperClassName{\n');
- s.write('final $structName _struct;\n');
- s.write('final int length;\n');
- s.write('$helperClassName(this._struct, this.length);\n');
+ // Write class declaration.
+ s.write('class ${helperClassName}{\n');
+ s.write('final $structName $structIdentifier;\n');
+ s.write('final List<int> $dimensionsIdentifier;\n');
+ s.write('final int $levelIdentifier;\n');
+ s.write('final int $absoluteIndexIdentifier;\n');
+ s.write(
+ 'int get $legthIdentifier => $dimensionsIdentifier[$levelIdentifier];\n');
- // Override []= operator.
- s.write('void operator []=(int index, $arrayType value) {\n');
- s.write('switch(index) {\n');
- for (var i = 0; i < length; i++) {
- s.write('case $i:\n');
- s.write(' _struct.${elementNamePrefix}$i = value;\n');
- s.write(' break;\n');
+ // Write class constructor.
+ s.write(
+ '$helperClassName(this.$structIdentifier, this.$dimensionsIdentifier, this.$levelIdentifier, this.$absoluteIndexIdentifier);\n');
+
+ // Write checkBoundsFunction.
+ s.write('''
+ void $checkBoundsFunctionIdentifier(int index) {
+ if (index >= $legthIdentifier || index < 0) {
+ throw RangeError('Dimension \$$levelIdentifier: index not in range 0..\${$legthIdentifier} exclusive.');
}
- s.write('default:\n');
- s.write(
- " throw RangeError('Index \$index must be in the range [0..${length - 1}].');");
- s.write('}\n');
- s.write('}\n');
-
- // Override [] operator.
- s.write('$arrayType operator [](int index) {\n');
- s.write('switch(index) {\n');
- for (var i = 0; i < length; i++) {
- s.write('case $i:\n');
- s.write(' return _struct.${elementNamePrefix}$i;\n');
+ }
+ ''');
+ // If this isn't the last level.
+ if (dim + 1 != dimensions.length) {
+ // Override [] operator.
+ s.write('''
+ ${helperClassGroupName}_level${dim + 1} operator [](int index) {
+ $checkBoundsFunctionIdentifier(index);
+ int offset = index;
+ for (int i = level + 1; i < $dimensionsIdentifier.length; i++) {
+ offset *= $dimensionsIdentifier[i];
}
- s.write('default:\n');
- s.write(
- " throw RangeError('Index \$index must be in the range [0..${length - 1}].');");
- s.write('}\n');
- s.write('}\n');
+ return ${helperClassGroupName}_level${dim + 1}(
+ $structIdentifier, $dimensionsIdentifier, $levelIdentifier + 1, $absoluteIndexIdentifier + offset);
+ }
+''');
+ } else {
+ // This is the last level, add switching logic here.
+ // Override [] operator.
+ s.write('$arrayType operator[](int index){\n');
+ s.write('$checkBoundsFunctionIdentifier(index);\n');
+ s.write('switch($absoluteIndexIdentifier+index){\n');
+ for (int i = 0; i < expandedArrayLength; i++) {
+ s.write('case $i:\n');
+ s.write(' return $structIdentifier.${elementNamePrefix}$i;\n');
+ }
+ s.write('default:\n');
+ s.write(" throw Exception('Invalid Array Helper generated.');");
+ s.write('}\n');
+ s.write('}\n');
- // Override toString().
- s.write('@override\n');
- s.write('String toString() {\n');
- s.write("if (length == 0) return '[]';\n");
- s.write("final sb = StringBuffer('[');\n");
- s.write('sb.write(this[0]);\n');
- s.write('for (var i = 1; i < length; i++) {\n');
- s.write(" sb.write(',');\n");
- s.write(' sb.write(this[i]);');
- s.write('}\n');
- s.write("sb.write(']');");
- s.write('return sb.toString();\n');
- s.write('}\n');
-
- s.write('}\n\n');
+ // Override []= operator.
+ s.write('void operator[]=(int index, $arrayType value){\n');
+ s.write('$checkBoundsFunctionIdentifier(index);\n');
+ s.write('switch($absoluteIndexIdentifier+index){\n');
+ for (int i = 0; i < expandedArrayLength; i++) {
+ s.write('case $i:\n');
+ s.write(' $structIdentifier.${elementNamePrefix}$i = value;\n');
+ s.write(' break;\n');
+ }
+ s.write('default:\n');
+ s.write(" throw Exception('Invalid Array Helper generated.');\n");
+ s.write('}\n');
+ s.write('}\n');
+ }
+ s.write('}\n');
+ }
return s.toString();
}
}
diff --git a/pkgs/ffigen/lib/src/code_generator/type.dart b/pkgs/ffigen/lib/src/code_generator/type.dart
index b393d34..dccdec3 100644
--- a/pkgs/ffigen/lib/src/code_generator/type.dart
+++ b/pkgs/ffigen/lib/src/code_generator/type.dart
@@ -38,6 +38,7 @@
/// Stores its element type in NativeType as only those are supported.
ConstantArray,
+ IncompleteArray,
/// Used as a marker, so that functions/structs having these can exclude them.
Unimplemented,
@@ -73,12 +74,11 @@
/// The BroadType of this Type.
final BroadType broadType;
- /// Child Type, e.g Pointer(Parent) to Int(Child).
+ /// Child Type, e.g Pointer(Parent) to Int(Child), or Child Type of an Array.
final Type child;
- /// For ConstantArray type.
- final int arrayLength;
- final Type elementType;
+ /// For ConstantArray and IncompleteArray type.
+ final int length;
/// For storing cursor type info for an unimplemented type.
String unimplementedReason;
@@ -89,8 +89,7 @@
this.structName,
this.nativeType,
this.nativeFuncName,
- this.arrayLength,
- this.elementType,
+ this.length,
this.unimplementedReason,
});
@@ -107,8 +106,18 @@
factory Type.nativeType(SupportedNativeType nativeType) {
return Type._(broadType: BroadType.NativeType, nativeType: nativeType);
}
- factory Type.constantArray(int arrayLength, Type elementType) {
- return Type._(broadType: BroadType.ConstantArray, elementType: elementType);
+ factory Type.constantArray(int length, Type elementType) {
+ return Type._(
+ broadType: BroadType.ConstantArray,
+ child: elementType,
+ length: length,
+ );
+ }
+ factory Type.incompleteArray(Type elementType) {
+ return Type._(
+ broadType: BroadType.ConstantArray,
+ child: elementType,
+ );
}
factory Type.unimplemented(String reason) {
return Type._(
@@ -117,15 +126,28 @@
/// Get base broad type for any type.
///
- /// E.g int** has base Broadtype as NativeType.
+ /// E.g int** has base Broadtype as NativeType,
+ /// double[2][3] has base broadtype as double.
BroadType getBaseBroadType() {
- if (broadType == BroadType.Pointer) {
+ if (child != null) {
return child.getBaseBroadType();
} else {
return broadType;
}
}
+ /// Get base Array type.
+ ///
+ /// Returns itself if it's not an Array Type.
+ Type getBaseArrayType() {
+ if (broadType == BroadType.ConstantArray ||
+ broadType == BroadType.IncompleteArray) {
+ return child.getBaseArrayType();
+ } else {
+ return this;
+ }
+ }
+
bool get isPrimitive => broadType == BroadType.NativeType;
String getCType(Writer w) {
@@ -138,6 +160,12 @@
return structName;
case BroadType.NativeFunction:
return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFuncName}>';
+ case BroadType
+ .IncompleteArray: // Array parameters are treated as Pointers in C.
+ return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
+ case BroadType
+ .ConstantArray: // Array parameters are treated as Pointers in C.
+ return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
default:
throw Exception('cType unknown');
}
@@ -153,6 +181,12 @@
return structName;
case BroadType.NativeFunction:
return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFuncName}>';
+ case BroadType
+ .IncompleteArray: // Array parameters are treated as Pointers in C.
+ return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
+ case BroadType
+ .ConstantArray: // Array parameters are treated as Pointers in C.
+ return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
default:
throw Exception('dart type unknown for ${broadType.toString()}');
}
diff --git a/pkgs/ffigen/lib/src/config_provider/config.dart b/pkgs/ffigen/lib/src/config_provider/config.dart
index 49cda0c..fbd2ae6 100644
--- a/pkgs/ffigen/lib/src/config_provider/config.dart
+++ b/pkgs/ffigen/lib/src/config_provider/config.dart
@@ -62,6 +62,11 @@
/// Extracted Doc comment type.
String comment;
+ /// If tool should generate array workarounds.
+ ///
+ /// If false(default), structs with inline array members will have all its members removed.
+ bool arrayWorkaround;
+
/// Manually creating configurations.
///
/// Use [Config.fromYaml] if extracting info from a yaml file.
@@ -251,6 +256,15 @@
defaultValue: strings.brief,
extractedResult: (dynamic result) => comment = result as String,
),
+ strings.arrayWorkaround: Specification<bool>(
+ description:
+ 'whether or not to generate workarounds for inline arrays in structures',
+ isRequired: false,
+ validator: booleanValidator,
+ extractor: booleanExtractor,
+ defaultValue: false,
+ extractedResult: (dynamic result) => arrayWorkaround = result as bool,
+ ),
};
}
}
diff --git a/pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart b/pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart
index 1cf40a3..546c8dc 100644
--- a/pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart
+++ b/pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart
@@ -39,17 +39,44 @@
ffi.Pointer<ffi.Void> _data_item_1;
ffi.Pointer<ffi.Void> _data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXCursor_data get data => _ArrayHelper_CXCursor_data(this, 3);
+ /// Helper for array `data`.
+ ArrayHelper_CXCursor_data_level0 get data =>
+ ArrayHelper_CXCursor_data_level0(this, [3], 0, 0);
}
-/// Helper for array data in struct CXCursor
-class _ArrayHelper_CXCursor_data {
+/// Helper for array `data` in struct `CXCursor`.
+class ArrayHelper_CXCursor_data_level0 {
final CXCursor _struct;
- final int length;
- _ArrayHelper_CXCursor_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXCursor_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ffi.Pointer<ffi.Void> operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._data_item_0;
+ case 1:
+ return _struct._data_item_1;
+ case 2:
+ return _struct._data_item_2;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, ffi.Pointer<ffi.Void> value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._data_item_0 = value;
break;
@@ -60,35 +87,9 @@
_struct._data_item_2 = value;
break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- ffi.Pointer<ffi.Void> operator [](int index) {
- switch (index) {
- case 0:
- return _struct._data_item_0;
- case 1:
- return _struct._data_item_1;
- case 2:
- return _struct._data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
/// Describes the kind of entity that a cursor refers to.
@@ -770,72 +771,65 @@
class CXSourceLocation extends ffi.Struct {
ffi.Pointer<ffi.Void> _ptr_data_item_0;
ffi.Pointer<ffi.Void> _ptr_data_item_1;
- ffi.Pointer<ffi.Void> _ptr_data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXSourceLocation_ptr_data get ptr_data =>
- _ArrayHelper_CXSourceLocation_ptr_data(this, 3);
+ /// Helper for array `ptr_data`.
+ ArrayHelper_CXSourceLocation_ptr_data_level0 get ptr_data =>
+ ArrayHelper_CXSourceLocation_ptr_data_level0(this, [2], 0, 0);
@ffi.Uint32()
int int_data;
}
-/// Helper for array ptr_data in struct CXSourceLocation
-class _ArrayHelper_CXSourceLocation_ptr_data {
+/// Helper for array `ptr_data` in struct `CXSourceLocation`.
+class ArrayHelper_CXSourceLocation_ptr_data_level0 {
final CXSourceLocation _struct;
- final int length;
- _ArrayHelper_CXSourceLocation_ptr_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXSourceLocation_ptr_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ffi.Pointer<ffi.Void> operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._ptr_data_item_0;
+ case 1:
+ return _struct._ptr_data_item_1;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, ffi.Pointer<ffi.Void> value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._ptr_data_item_0 = value;
break;
case 1:
_struct._ptr_data_item_1 = value;
break;
- case 2:
- _struct._ptr_data_item_2 = value;
- break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- ffi.Pointer<ffi.Void> operator [](int index) {
- switch (index) {
- case 0:
- return _struct._ptr_data_item_0;
- case 1:
- return _struct._ptr_data_item_1;
- case 2:
- return _struct._ptr_data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
/// Identifies a half-open character range in the source code.
class CXSourceRange extends ffi.Struct {
ffi.Pointer<ffi.Void> _ptr_data_item_0;
ffi.Pointer<ffi.Void> _ptr_data_item_1;
- ffi.Pointer<ffi.Void> _ptr_data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXSourceRange_ptr_data get ptr_data =>
- _ArrayHelper_CXSourceRange_ptr_data(this, 3);
+ /// Helper for array `ptr_data`.
+ ArrayHelper_CXSourceRange_ptr_data_level0 get ptr_data =>
+ ArrayHelper_CXSourceRange_ptr_data_level0(this, [2], 0, 0);
@ffi.Uint32()
int begin_int_data;
@@ -843,52 +837,47 @@
int end_int_data;
}
-/// Helper for array ptr_data in struct CXSourceRange
-class _ArrayHelper_CXSourceRange_ptr_data {
+/// Helper for array `ptr_data` in struct `CXSourceRange`.
+class ArrayHelper_CXSourceRange_ptr_data_level0 {
final CXSourceRange _struct;
- final int length;
- _ArrayHelper_CXSourceRange_ptr_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXSourceRange_ptr_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ffi.Pointer<ffi.Void> operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._ptr_data_item_0;
+ case 1:
+ return _struct._ptr_data_item_1;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, ffi.Pointer<ffi.Void> value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._ptr_data_item_0 = value;
break;
case 1:
_struct._ptr_data_item_1 = value;
break;
- case 2:
- _struct._ptr_data_item_2 = value;
- break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- ffi.Pointer<ffi.Void> operator [](int index) {
- switch (index) {
- case 0:
- return _struct._ptr_data_item_0;
- case 1:
- return _struct._ptr_data_item_1;
- case 2:
- return _struct._ptr_data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
/// A character string.
@@ -972,58 +961,53 @@
ffi.Pointer<ffi.Void> _data_item_0;
ffi.Pointer<ffi.Void> _data_item_1;
- ffi.Pointer<ffi.Void> _data_item_2;
- /// helper for array, supports `[]` operator
- _ArrayHelper_CXType_data get data => _ArrayHelper_CXType_data(this, 3);
+ /// Helper for array `data`.
+ ArrayHelper_CXType_data_level0 get data =>
+ ArrayHelper_CXType_data_level0(this, [2], 0, 0);
}
-/// Helper for array data in struct CXType
-class _ArrayHelper_CXType_data {
+/// Helper for array `data` in struct `CXType`.
+class ArrayHelper_CXType_data_level0 {
final CXType _struct;
- final int length;
- _ArrayHelper_CXType_data(this._struct, this.length);
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_CXType_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ffi.Pointer<ffi.Void> operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._data_item_0;
+ case 1:
+ return _struct._data_item_1;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
void operator []=(int index, ffi.Pointer<ffi.Void> value) {
- switch (index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
case 0:
_struct._data_item_0 = value;
break;
case 1:
_struct._data_item_1 = value;
break;
- case 2:
- _struct._data_item_2 = value;
- break;
default:
- throw RangeError('Index $index must be in the range [0..2].');
+ throw Exception('Invalid Array Helper generated.');
}
}
-
- ffi.Pointer<ffi.Void> operator [](int index) {
- switch (index) {
- case 0:
- return _struct._data_item_0;
- case 1:
- return _struct._data_item_1;
- case 2:
- return _struct._data_item_2;
- default:
- throw RangeError('Index $index must be in the range [0..2].');
- }
- }
-
- @override
- String toString() {
- if (length == 0) return '[]';
- final sb = StringBuffer('[');
- sb.write(this[0]);
- for (var i = 1; i < length; i++) {
- sb.write(',');
- sb.write(this[i]);
- }
- sb.write(']');
- return sb.toString();
- }
}
/// Describes the kind of type
diff --git a/pkgs/ffigen/lib/src/header_parser/sub_parsers/functiondecl_parser.dart b/pkgs/ffigen/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
index 62803f6..3afb7b7 100644
--- a/pkgs/ffigen/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
+++ b/pkgs/ffigen/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
@@ -21,7 +21,6 @@
_func = null;
structByValueParameter = false;
unimplementedParameterType = false;
- constantArrayParameterType = false;
final name = cursor.spelling();
if (shouldIncludeFunc(name)) {
@@ -39,14 +38,6 @@
return null; // Returning null so that [addToBindings] function excludes this.
}
- if (constantArrayParameterType) {
- _logger.fine(
- '---- Removed Function, reason: constant array passed to function parameter: ${cursor.completeStringRepr()}');
- _logger.warning(
- "Skipped Function '$name', constant array in function parameter not supported.");
- return null; // Returning null so that [addToBindings] function excludes this.
- }
-
if (rt.getBaseBroadType() == BroadType.Unimplemented ||
unimplementedParameterType) {
_logger.fine(
@@ -68,7 +59,6 @@
}
bool structByValueParameter = false;
-bool constantArrayParameterType = false;
bool unimplementedParameterType = false;
Type _getFunctionReturnType(Pointer<clang.CXCursor> cursor) {
return cursor.returnType().toCodeGenTypeAndDispose();
@@ -87,8 +77,6 @@
//TODO(3): Remove this when support for Structs by value arrives.
if (pt.broadType == BroadType.Struct) {
structByValueParameter = true;
- } else if (pt.broadType == BroadType.ConstantArray) {
- constantArrayParameterType = true;
} else if (pt.getBaseBroadType() == BroadType.Unimplemented) {
unimplementedParameterType = true;
}
diff --git a/pkgs/ffigen/lib/src/header_parser/sub_parsers/structdecl_parser.dart b/pkgs/ffigen/lib/src/header_parser/sub_parsers/structdecl_parser.dart
index 0c9dfa3..d7c9dc4 100644
--- a/pkgs/ffigen/lib/src/header_parser/sub_parsers/structdecl_parser.dart
+++ b/pkgs/ffigen/lib/src/header_parser/sub_parsers/structdecl_parser.dart
@@ -8,6 +8,7 @@
import 'package:logging/logging.dart';
import '../clang_bindings/clang_bindings.dart' as clang;
+import '../data.dart';
import '../includer.dart';
import '../utils.dart';
@@ -53,6 +54,7 @@
List<Member> _members;
List<Member> _getMembers(Pointer<clang.CXCursor> cursor, String structName) {
_members = [];
+ arrayMember = false;
nestedStructMember = false;
unimplementedMemberType = false;
@@ -65,7 +67,13 @@
visitChildrenResultChecker(resultCode);
// Returning null to exclude the struct members as it has a struct by value field.
- if (nestedStructMember) {
+ if (arrayMember && !config.arrayWorkaround) {
+ _logger.fine(
+ '---- Removed Struct members, reason: struct has array members ${cursor.completeStringRepr()}');
+ _logger.warning(
+ 'Removed All Struct Members from: $structName, Array members not supported');
+ return null;
+ } else if (nestedStructMember) {
_logger.fine(
'---- Removed Struct members, reason: struct has struct members ${cursor.completeStringRepr()}');
_logger.warning(
@@ -84,6 +92,7 @@
bool nestedStructMember = false;
bool unimplementedMemberType = false;
+bool arrayMember = false;
/// Visitor for the struct cursor [CXCursorKind.CXCursor_StructDecl].
///
@@ -98,11 +107,14 @@
//TODO(4): Remove these when support for Structs by value arrives.
if (mt.broadType == BroadType.Struct) {
- // Setting this flag will exclude adding members for this struct's bindings.
+ // Setting this flag will exclude adding members for this struct's
+ // bindings.
nestedStructMember = true;
} else if (mt.broadType == BroadType.ConstantArray) {
- if (mt.elementType.broadType == BroadType.Struct) {
- // Setting this flag will exclude adding members for this struct's bindings.
+ arrayMember = true;
+ if (mt.child.broadType == BroadType.Struct) {
+ // Setting this flag will exclude adding members for this struct's
+ // bindings.
nestedStructMember = true;
}
}
diff --git a/pkgs/ffigen/lib/src/header_parser/type_extractor/extractor.dart b/pkgs/ffigen/lib/src/header_parser/type_extractor/extractor.dart
index db37487..9584cea 100644
--- a/pkgs/ffigen/lib/src/header_parser/type_extractor/extractor.dart
+++ b/pkgs/ffigen/lib/src/header_parser/type_extractor/extractor.dart
@@ -66,6 +66,11 @@
clang.clang_getNumElements_wrap(cxtype),
clang.clang_getArrayElementType_wrap(cxtype).toCodeGenTypeAndDispose(),
);
+ case clang.CXTypeKind
+ .CXType_IncompleteArray: // Primarily used for incomplete array in function parameters.
+ return Type.incompleteArray(
+ clang.clang_getArrayElementType_wrap(cxtype).toCodeGenTypeAndDispose(),
+ );
default:
if (cxTypeKindToSupportedNativeTypes.containsKey(kind)) {
return Type.nativeType(
diff --git a/pkgs/ffigen/lib/src/header_parser/utils.dart b/pkgs/ffigen/lib/src/header_parser/utils.dart
index fbc4d31..c5b7f5f 100644
--- a/pkgs/ffigen/lib/src/header_parser/utils.dart
+++ b/pkgs/ffigen/lib/src/header_parser/utils.dart
@@ -129,7 +129,7 @@
/// Returns a cursor's associated comment.
///
/// The given string is wrapped at line width = 80 - [indent]. The [indent] is
-/// [commentPrefix.length] by default because a comment starts with
+/// [commentPrefix.dimensions] by default because a comment starts with
/// [commentPrefix].
String getCursorDocComment(Pointer<clang.CXCursor> cursor,
[int indent = commentPrefix.length]) {
diff --git a/pkgs/ffigen/lib/src/strings.dart b/pkgs/ffigen/lib/src/strings.dart
index e96ddc1..a03aa97 100644
--- a/pkgs/ffigen/lib/src/strings.dart
+++ b/pkgs/ffigen/lib/src/strings.dart
@@ -58,6 +58,7 @@
const sort = 'sort';
const useSupportedTypedefs = 'use-supported-typedefs';
const warnWhenRemoving = 'warn-when-removing';
+const arrayWorkaround = 'array-workaround';
const comments = 'comments';
// Comment type.
diff --git a/pkgs/ffigen/test/native_functions_test/native_functions_bindings.dart b/pkgs/ffigen/test/native_functions_test/native_functions_bindings.dart
deleted file mode 100644
index a9eb1e9..0000000
--- a/pkgs/ffigen/test/native_functions_test/native_functions_bindings.dart
+++ /dev/null
@@ -1,226 +0,0 @@
-/// AUTO GENERATED FILE, DO NOT EDIT.
-///
-/// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-/// Holds the Dynamic library.
-ffi.DynamicLibrary _dylib;
-
-/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
- _dylib = dylib;
-}
-
-double Function1Double(
- double x,
-) {
- return _Function1Double(
- x,
- );
-}
-
-final _dart_Function1Double _Function1Double =
- _dylib.lookupFunction<_c_Function1Double, _dart_Function1Double>(
- 'Function1Double');
-
-typedef _c_Function1Double = ffi.Double Function(
- ffi.Double x,
-);
-
-typedef _dart_Function1Double = double Function(
- double x,
-);
-
-double Function1Float(
- double x,
-) {
- return _Function1Float(
- x,
- );
-}
-
-final _dart_Function1Float _Function1Float = _dylib
- .lookupFunction<_c_Function1Float, _dart_Function1Float>('Function1Float');
-
-typedef _c_Function1Float = ffi.Float Function(
- ffi.Float x,
-);
-
-typedef _dart_Function1Float = double Function(
- double x,
-);
-
-int Function1Int16(
- int x,
-) {
- return _Function1Int16(
- x,
- );
-}
-
-final _dart_Function1Int16 _Function1Int16 = _dylib
- .lookupFunction<_c_Function1Int16, _dart_Function1Int16>('Function1Int16');
-
-typedef _c_Function1Int16 = ffi.Int16 Function(
- ffi.Int16 x,
-);
-
-typedef _dart_Function1Int16 = int Function(
- int x,
-);
-
-int Function1Int32(
- int x,
-) {
- return _Function1Int32(
- x,
- );
-}
-
-final _dart_Function1Int32 _Function1Int32 = _dylib
- .lookupFunction<_c_Function1Int32, _dart_Function1Int32>('Function1Int32');
-
-typedef _c_Function1Int32 = ffi.Int32 Function(
- ffi.Int32 x,
-);
-
-typedef _dart_Function1Int32 = int Function(
- int x,
-);
-
-int Function1Int64(
- int x,
-) {
- return _Function1Int64(
- x,
- );
-}
-
-final _dart_Function1Int64 _Function1Int64 = _dylib
- .lookupFunction<_c_Function1Int64, _dart_Function1Int64>('Function1Int64');
-
-typedef _c_Function1Int64 = ffi.Int64 Function(
- ffi.Int64 x,
-);
-
-typedef _dart_Function1Int64 = int Function(
- int x,
-);
-
-int Function1Int8(
- int x,
-) {
- return _Function1Int8(
- x,
- );
-}
-
-final _dart_Function1Int8 _Function1Int8 = _dylib
- .lookupFunction<_c_Function1Int8, _dart_Function1Int8>('Function1Int8');
-
-typedef _c_Function1Int8 = ffi.Int8 Function(
- ffi.Int8 x,
-);
-
-typedef _dart_Function1Int8 = int Function(
- int x,
-);
-
-int Function1IntPtr(
- int x,
-) {
- return _Function1IntPtr(
- x,
- );
-}
-
-final _dart_Function1IntPtr _Function1IntPtr =
- _dylib.lookupFunction<_c_Function1IntPtr, _dart_Function1IntPtr>(
- 'Function1IntPtr');
-
-typedef _c_Function1IntPtr = ffi.IntPtr Function(
- ffi.IntPtr x,
-);
-
-typedef _dart_Function1IntPtr = int Function(
- int x,
-);
-
-int Function1Uint16(
- int x,
-) {
- return _Function1Uint16(
- x,
- );
-}
-
-final _dart_Function1Uint16 _Function1Uint16 =
- _dylib.lookupFunction<_c_Function1Uint16, _dart_Function1Uint16>(
- 'Function1Uint16');
-
-typedef _c_Function1Uint16 = ffi.Uint16 Function(
- ffi.Uint16 x,
-);
-
-typedef _dart_Function1Uint16 = int Function(
- int x,
-);
-
-int Function1Uint32(
- int x,
-) {
- return _Function1Uint32(
- x,
- );
-}
-
-final _dart_Function1Uint32 _Function1Uint32 =
- _dylib.lookupFunction<_c_Function1Uint32, _dart_Function1Uint32>(
- 'Function1Uint32');
-
-typedef _c_Function1Uint32 = ffi.Uint32 Function(
- ffi.Uint32 x,
-);
-
-typedef _dart_Function1Uint32 = int Function(
- int x,
-);
-
-int Function1Uint64(
- int x,
-) {
- return _Function1Uint64(
- x,
- );
-}
-
-final _dart_Function1Uint64 _Function1Uint64 =
- _dylib.lookupFunction<_c_Function1Uint64, _dart_Function1Uint64>(
- 'Function1Uint64');
-
-typedef _c_Function1Uint64 = ffi.Uint64 Function(
- ffi.Uint64 x,
-);
-
-typedef _dart_Function1Uint64 = int Function(
- int x,
-);
-
-int Function1Uint8(
- int x,
-) {
- return _Function1Uint8(
- x,
- );
-}
-
-final _dart_Function1Uint8 _Function1Uint8 = _dylib
- .lookupFunction<_c_Function1Uint8, _dart_Function1Uint8>('Function1Uint8');
-
-typedef _c_Function1Uint8 = ffi.Uint8 Function(
- ffi.Uint8 x,
-);
-
-typedef _dart_Function1Uint8 = int Function(
- int x,
-);
diff --git a/pkgs/ffigen/test/native_functions_test/native_functions_test.dart b/pkgs/ffigen/test/native_functions_test/native_functions_test.dart
deleted file mode 100644
index b63fc35..0000000
--- a/pkgs/ffigen/test/native_functions_test/native_functions_test.dart
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:ffi';
-import 'dart:io';
-import 'dart:math';
-
-import 'package:test/test.dart';
-import 'native_functions_bindings.dart' as bindings;
-
-void main() {
- group('Tests for native functions', () {
- setUpAll(() {
- var dylibName = 'test/native_functions_test/native_functions.so';
- if (Platform.isMacOS) {
- dylibName = 'test/native_functions_test/native_functions.dylib';
- } else if (Platform.isWindows) {
- dylibName = r'test\native_functions_test\native_functions.dll';
- }
- bindings.init(DynamicLibrary.open(dylibName));
- });
- test('uint8_t', () {
- expect(bindings.Function1Uint8(pow(2, 8).toInt()), 42);
- });
- test('uint16_t', () {
- expect(bindings.Function1Uint16(pow(2, 16).toInt()), 42);
- });
- test('uint32_t', () {
- expect(bindings.Function1Uint32(pow(2, 32).toInt()), 42);
- });
- test('uint64_t', () {
- expect(bindings.Function1Uint64(pow(2, 64).toInt()), 42);
- });
- test('int8_t', () {
- expect(
- bindings.Function1Int8(pow(2, 7).toInt()), -pow(2, 7).toInt() + 42);
- });
- test('int16_t', () {
- expect(bindings.Function1Int16(pow(2, 15).toInt()),
- -pow(2, 15).toInt() + 42);
- });
- test('int32_t', () {
- expect(bindings.Function1Int32(pow(2, 31).toInt()),
- -pow(2, 31).toInt() + 42);
- });
- test('int64_t', () {
- expect(bindings.Function1Int64(pow(2, 63).toInt()),
- -pow(2, 63).toInt() + 42);
- });
- test('intptr_t', () {
- expect(bindings.Function1IntPtr(0), 42);
- });
- test('float', () {
- expect(bindings.Function1Float(0), 42.0);
- });
- test('double', () {
- expect(bindings.Function1Double(0), 42.0);
- });
- });
-}
diff --git a/pkgs/ffigen/test/native_functions_test/build_test_dylib.dart b/pkgs/ffigen/test/native_test/build_test_dylib.dart
similarity index 83%
rename from pkgs/ffigen/test/native_functions_test/build_test_dylib.dart
rename to pkgs/ffigen/test/native_test/build_test_dylib.dart
index 25258f0..2fd2c49 100644
--- a/pkgs/ffigen/test/native_functions_test/build_test_dylib.dart
+++ b/pkgs/ffigen/test/native_test/build_test_dylib.dart
@@ -10,17 +10,17 @@
///
/// Linux:
/// ```
-/// clang -shared -fpic native_functions.c -o native_functions.so
+/// clang -shared -fpic native_test.c -o native_test.so
/// ```
/// MacOS:
/// ```
-/// clang -shared -fpic native_functions.c -o native_functions.dylib
+/// clang -shared -fpic native_test.c -o native_test.dylib
/// ```
/// Windows:
/// ```
-/// call clang -shared native_functions.c -o native_functions.dll -Wl,"/DEF:native_functions.def"
-/// del native_functions.exp
-/// del native_functions.lib
+/// call clang -shared native_test.c -o native_test.dll -Wl,"/DEF:native_test.def"
+/// del native_test.exp
+/// del native_test.lib
/// ```
/// =======================================================================
/// =======================================================================
@@ -36,21 +36,21 @@
Map<String, Options> platformOptions = {
LINUX: Options(
- outputfilename: 'native_functions.so',
+ outputfilename: 'native_test.so',
sharedFlag: '-shared',
- inputHeader: 'native_functions.c',
+ inputHeader: 'native_test.c',
fPIC: '-fpic',
),
WINDOWS: Options(
- outputfilename: 'native_functions.dll',
+ outputfilename: 'native_test.dll',
sharedFlag: '-shared',
- inputHeader: 'native_functions.c',
- moduleDefPath: '-Wl,/DEF:native_functions.def',
+ inputHeader: 'native_test.c',
+ moduleDefPath: '-Wl,/DEF:native_test.def',
),
MACOS: Options(
- outputfilename: 'native_functions.dylib',
+ outputfilename: 'native_test.dylib',
sharedFlag: '-shared',
- inputHeader: 'native_functions.c',
+ inputHeader: 'native_test.c',
fPIC: '-fpic',
),
};
diff --git a/pkgs/ffigen/test/native_functions_test/config.yaml b/pkgs/ffigen/test/native_test/config.yaml
similarity index 82%
rename from pkgs/ffigen/test/native_functions_test/config.yaml
rename to pkgs/ffigen/test/native_test/config.yaml
index 3635c70..a25821a 100644
--- a/pkgs/ffigen/test/native_functions_test/config.yaml
+++ b/pkgs/ffigen/test/native_test/config.yaml
@@ -6,11 +6,12 @@
# dart ../../bin/ffigen.dart --config config.yaml
# ===============================================================
-output: 'native_functions_bindings.dart'
+output: 'native_test_bindings.dart'
libclang-dylib-folder: '../../tool/wrapped_libclang'
sort: true
headers:
- - 'native_functions.c'
+ - 'native_test.c'
header-filter:
include:
- - 'native_functions.c'
+ - 'native_test.c'
+array-workaround: true
diff --git a/pkgs/ffigen/test/native_functions_test/native_functions.c b/pkgs/ffigen/test/native_test/native_test.c
similarity index 67%
rename from pkgs/ffigen/test/native_functions_test/native_functions.c
rename to pkgs/ffigen/test/native_test/native_test.c
index 544357e..21c2f16 100644
--- a/pkgs/ffigen/test/native_functions_test/native_functions.c
+++ b/pkgs/ffigen/test/native_test/native_test.c
@@ -1,8 +1,10 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+#define aloc(T) ((T *)malloc(sizeof(T)))
#include <stdint.h>
+#include <stdlib.h>
uint8_t Function1Uint8(uint8_t x) { return x + 42; }
@@ -25,3 +27,22 @@
float Function1Float(float x) { return x + 42.0f; }
double Function1Double(double x) { return x + 42.0; }
+
+struct Struct1
+{
+ int8_t a;
+ int32_t data[3][1][2];
+};
+
+struct Struct1 *getStruct1()
+{
+ struct Struct1 *s = aloc(struct Struct1);
+ s->a = 0;
+ s->data[0][0][0] = 1;
+ s->data[0][0][1] = 2;
+ s->data[1][0][0] = 3;
+ s->data[1][0][1] = 4;
+ s->data[2][0][0] = 5;
+ s->data[2][0][1] = 6;
+ return s;
+}
diff --git a/pkgs/ffigen/test/native_test/native_test.dart b/pkgs/ffigen/test/native_test/native_test.dart
new file mode 100644
index 0000000..cc4fa22
--- /dev/null
+++ b/pkgs/ffigen/test/native_test/native_test.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:ffi';
+import 'dart:io';
+import 'dart:math';
+
+import 'package:test/test.dart';
+import 'native_test_bindings.dart' as bindings;
+
+void main() {
+ group('Tests for native functions', () {
+ setUpAll(() {
+ var dylibName = 'test/native_test/native_test.so';
+ if (Platform.isMacOS) {
+ dylibName = 'test/native_test/native_test.dylib';
+ } else if (Platform.isWindows) {
+ dylibName = r'test\native_test\native_test.dll';
+ }
+ bindings.init(DynamicLibrary.open(dylibName));
+ });
+ test('uint8_t', () {
+ expect(bindings.Function1Uint8(pow(2, 8).toInt()), 42);
+ });
+ test('uint16_t', () {
+ expect(bindings.Function1Uint16(pow(2, 16).toInt()), 42);
+ });
+ test('uint32_t', () {
+ expect(bindings.Function1Uint32(pow(2, 32).toInt()), 42);
+ });
+ test('uint64_t', () {
+ expect(bindings.Function1Uint64(pow(2, 64).toInt()), 42);
+ });
+ test('int8_t', () {
+ expect(
+ bindings.Function1Int8(pow(2, 7).toInt()), -pow(2, 7).toInt() + 42);
+ });
+ test('int16_t', () {
+ expect(bindings.Function1Int16(pow(2, 15).toInt()),
+ -pow(2, 15).toInt() + 42);
+ });
+ test('int32_t', () {
+ expect(bindings.Function1Int32(pow(2, 31).toInt()),
+ -pow(2, 31).toInt() + 42);
+ });
+ test('int64_t', () {
+ expect(bindings.Function1Int64(pow(2, 63).toInt()),
+ -pow(2, 63).toInt() + 42);
+ });
+ test('intptr_t', () {
+ expect(bindings.Function1IntPtr(0), 42);
+ });
+ test('float', () {
+ expect(bindings.Function1Float(0), 42.0);
+ });
+ test('double', () {
+ expect(bindings.Function1Double(0), 42.0);
+ });
+ test('array-workaround: Order of access', () {
+ final struct1 = bindings.getStruct1();
+ int expectedValue = 1;
+ for (int i = 0; i < struct1.ref.data.dimensions[0]; i++) {
+ for (int j = 0; j < struct1.ref.data.dimensions[1]; j++) {
+ for (int k = 0; k < struct1.ref.data.dimensions[2]; k++) {
+ expect(struct1.ref.data[i][j][k], expectedValue);
+ expectedValue++;
+ }
+ }
+ }
+ });
+ test('array-workaround: Range Errors', () {
+ final struct1 = bindings.getStruct1();
+ // Index (get) above range.
+ expect(
+ () => struct1.ref.data[4][0][0], throwsA(TypeMatcher<RangeError>()));
+ expect(
+ () => struct1.ref.data[0][2][0], throwsA(TypeMatcher<RangeError>()));
+ expect(
+ () => struct1.ref.data[0][0][3], throwsA(TypeMatcher<RangeError>()));
+ // Index (get) below range.
+ expect(
+ () => struct1.ref.data[-1][0][0], throwsA(TypeMatcher<RangeError>()));
+ expect(
+ () => struct1.ref.data[-1][0][0], throwsA(TypeMatcher<RangeError>()));
+ expect(
+ () => struct1.ref.data[0][0][-1], throwsA(TypeMatcher<RangeError>()));
+
+ // Index (set) above range.
+ expect(() => struct1.ref.data[4][0][0] = 0,
+ throwsA(TypeMatcher<RangeError>()));
+ expect(() => struct1.ref.data[0][2][0] = 0,
+ throwsA(TypeMatcher<RangeError>()));
+ expect(() => struct1.ref.data[0][0][3] = 0,
+ throwsA(TypeMatcher<RangeError>()));
+ // Index (get) below range.
+ expect(() => struct1.ref.data[-1][0][0] = 0,
+ throwsA(TypeMatcher<RangeError>()));
+ expect(() => struct1.ref.data[-1][0][0] = 0,
+ throwsA(TypeMatcher<RangeError>()));
+ expect(() => struct1.ref.data[0][0][-1] = 0,
+ throwsA(TypeMatcher<RangeError>()));
+ });
+ });
+}
diff --git a/pkgs/ffigen/test/native_functions_test/native_functions.def b/pkgs/ffigen/test/native_test/native_test.def
similarity index 100%
rename from pkgs/ffigen/test/native_functions_test/native_functions.def
rename to pkgs/ffigen/test/native_test/native_test.def
diff --git a/pkgs/ffigen/test/native_test/native_test_bindings.dart b/pkgs/ffigen/test/native_test/native_test_bindings.dart
new file mode 100644
index 0000000..a9c5309
--- /dev/null
+++ b/pkgs/ffigen/test/native_test/native_test_bindings.dart
@@ -0,0 +1,376 @@
+/// AUTO GENERATED FILE, DO NOT EDIT.
+///
+/// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+/// Holds the Dynamic library.
+ffi.DynamicLibrary _dylib;
+
+/// Initialises the Dynamic library.
+void init(ffi.DynamicLibrary dylib) {
+ _dylib = dylib;
+}
+
+double Function1Double(
+ double x,
+) {
+ return _Function1Double(
+ x,
+ );
+}
+
+final _dart_Function1Double _Function1Double =
+ _dylib.lookupFunction<_c_Function1Double, _dart_Function1Double>(
+ 'Function1Double');
+
+typedef _c_Function1Double = ffi.Double Function(
+ ffi.Double x,
+);
+
+typedef _dart_Function1Double = double Function(
+ double x,
+);
+
+double Function1Float(
+ double x,
+) {
+ return _Function1Float(
+ x,
+ );
+}
+
+final _dart_Function1Float _Function1Float = _dylib
+ .lookupFunction<_c_Function1Float, _dart_Function1Float>('Function1Float');
+
+typedef _c_Function1Float = ffi.Float Function(
+ ffi.Float x,
+);
+
+typedef _dart_Function1Float = double Function(
+ double x,
+);
+
+int Function1Int16(
+ int x,
+) {
+ return _Function1Int16(
+ x,
+ );
+}
+
+final _dart_Function1Int16 _Function1Int16 = _dylib
+ .lookupFunction<_c_Function1Int16, _dart_Function1Int16>('Function1Int16');
+
+typedef _c_Function1Int16 = ffi.Int16 Function(
+ ffi.Int16 x,
+);
+
+typedef _dart_Function1Int16 = int Function(
+ int x,
+);
+
+int Function1Int32(
+ int x,
+) {
+ return _Function1Int32(
+ x,
+ );
+}
+
+final _dart_Function1Int32 _Function1Int32 = _dylib
+ .lookupFunction<_c_Function1Int32, _dart_Function1Int32>('Function1Int32');
+
+typedef _c_Function1Int32 = ffi.Int32 Function(
+ ffi.Int32 x,
+);
+
+typedef _dart_Function1Int32 = int Function(
+ int x,
+);
+
+int Function1Int64(
+ int x,
+) {
+ return _Function1Int64(
+ x,
+ );
+}
+
+final _dart_Function1Int64 _Function1Int64 = _dylib
+ .lookupFunction<_c_Function1Int64, _dart_Function1Int64>('Function1Int64');
+
+typedef _c_Function1Int64 = ffi.Int64 Function(
+ ffi.Int64 x,
+);
+
+typedef _dart_Function1Int64 = int Function(
+ int x,
+);
+
+int Function1Int8(
+ int x,
+) {
+ return _Function1Int8(
+ x,
+ );
+}
+
+final _dart_Function1Int8 _Function1Int8 = _dylib
+ .lookupFunction<_c_Function1Int8, _dart_Function1Int8>('Function1Int8');
+
+typedef _c_Function1Int8 = ffi.Int8 Function(
+ ffi.Int8 x,
+);
+
+typedef _dart_Function1Int8 = int Function(
+ int x,
+);
+
+int Function1IntPtr(
+ int x,
+) {
+ return _Function1IntPtr(
+ x,
+ );
+}
+
+final _dart_Function1IntPtr _Function1IntPtr =
+ _dylib.lookupFunction<_c_Function1IntPtr, _dart_Function1IntPtr>(
+ 'Function1IntPtr');
+
+typedef _c_Function1IntPtr = ffi.IntPtr Function(
+ ffi.IntPtr x,
+);
+
+typedef _dart_Function1IntPtr = int Function(
+ int x,
+);
+
+int Function1Uint16(
+ int x,
+) {
+ return _Function1Uint16(
+ x,
+ );
+}
+
+final _dart_Function1Uint16 _Function1Uint16 =
+ _dylib.lookupFunction<_c_Function1Uint16, _dart_Function1Uint16>(
+ 'Function1Uint16');
+
+typedef _c_Function1Uint16 = ffi.Uint16 Function(
+ ffi.Uint16 x,
+);
+
+typedef _dart_Function1Uint16 = int Function(
+ int x,
+);
+
+int Function1Uint32(
+ int x,
+) {
+ return _Function1Uint32(
+ x,
+ );
+}
+
+final _dart_Function1Uint32 _Function1Uint32 =
+ _dylib.lookupFunction<_c_Function1Uint32, _dart_Function1Uint32>(
+ 'Function1Uint32');
+
+typedef _c_Function1Uint32 = ffi.Uint32 Function(
+ ffi.Uint32 x,
+);
+
+typedef _dart_Function1Uint32 = int Function(
+ int x,
+);
+
+int Function1Uint64(
+ int x,
+) {
+ return _Function1Uint64(
+ x,
+ );
+}
+
+final _dart_Function1Uint64 _Function1Uint64 =
+ _dylib.lookupFunction<_c_Function1Uint64, _dart_Function1Uint64>(
+ 'Function1Uint64');
+
+typedef _c_Function1Uint64 = ffi.Uint64 Function(
+ ffi.Uint64 x,
+);
+
+typedef _dart_Function1Uint64 = int Function(
+ int x,
+);
+
+int Function1Uint8(
+ int x,
+) {
+ return _Function1Uint8(
+ x,
+ );
+}
+
+final _dart_Function1Uint8 _Function1Uint8 = _dylib
+ .lookupFunction<_c_Function1Uint8, _dart_Function1Uint8>('Function1Uint8');
+
+typedef _c_Function1Uint8 = ffi.Uint8 Function(
+ ffi.Uint8 x,
+);
+
+typedef _dart_Function1Uint8 = int Function(
+ int x,
+);
+
+class Struct1 extends ffi.Struct {
+ @ffi.Int8()
+ int a;
+
+ @ffi.Int32()
+ int _data_item_0;
+ @ffi.Int32()
+ int _data_item_1;
+ @ffi.Int32()
+ int _data_item_2;
+ @ffi.Int32()
+ int _data_item_3;
+ @ffi.Int32()
+ int _data_item_4;
+ @ffi.Int32()
+ int _data_item_5;
+
+ /// Helper for array `data`.
+ ArrayHelper_Struct1_data_level0 get data =>
+ ArrayHelper_Struct1_data_level0(this, [3, 1, 2], 0, 0);
+}
+
+/// Helper for array `data` in struct `Struct1`.
+class ArrayHelper_Struct1_data_level0 {
+ final Struct1 _struct;
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_Struct1_data_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ArrayHelper_Struct1_data_level1 operator [](int index) {
+ _checkBounds(index);
+ int offset = index;
+ for (int i = level + 1; i < dimensions.length; i++) {
+ offset *= dimensions[i];
+ }
+ return ArrayHelper_Struct1_data_level1(
+ _struct, dimensions, level + 1, _absoluteIndex + offset);
+ }
+}
+
+/// Helper for array `data` in struct `Struct1`.
+class ArrayHelper_Struct1_data_level1 {
+ final Struct1 _struct;
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_Struct1_data_level1(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ ArrayHelper_Struct1_data_level2 operator [](int index) {
+ _checkBounds(index);
+ int offset = index;
+ for (int i = level + 1; i < dimensions.length; i++) {
+ offset *= dimensions[i];
+ }
+ return ArrayHelper_Struct1_data_level2(
+ _struct, dimensions, level + 1, _absoluteIndex + offset);
+ }
+}
+
+/// Helper for array `data` in struct `Struct1`.
+class ArrayHelper_Struct1_data_level2 {
+ final Struct1 _struct;
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper_Struct1_data_level2(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ int operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._data_item_0;
+ case 1:
+ return _struct._data_item_1;
+ case 2:
+ return _struct._data_item_2;
+ case 3:
+ return _struct._data_item_3;
+ case 4:
+ return _struct._data_item_4;
+ case 5:
+ return _struct._data_item_5;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
+ void operator []=(int index, int value) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ _struct._data_item_0 = value;
+ break;
+ case 1:
+ _struct._data_item_1 = value;
+ break;
+ case 2:
+ _struct._data_item_2 = value;
+ break;
+ case 3:
+ _struct._data_item_3 = value;
+ break;
+ case 4:
+ _struct._data_item_4 = value;
+ break;
+ case 5:
+ _struct._data_item_5 = value;
+ break;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+}
+
+ffi.Pointer<Struct1> getStruct1() {
+ return _getStruct1();
+}
+
+final _dart_getStruct1 _getStruct1 =
+ _dylib.lookupFunction<_c_getStruct1, _dart_getStruct1>('getStruct1');
+
+typedef _c_getStruct1 = ffi.Pointer<Struct1> Function();
+
+typedef _dart_getStruct1 = ffi.Pointer<Struct1> Function();
diff --git a/pkgs/ffigen/tool/libclang_config.yaml b/pkgs/ffigen/tool/libclang_config.yaml
index 3fe9bb2..9401a00 100644
--- a/pkgs/ffigen/tool/libclang_config.yaml
+++ b/pkgs/ffigen/tool/libclang_config.yaml
@@ -21,6 +21,8 @@
- Index.h
- CXString.h
+array-workaround: true
+
enums:
include:
names: