[ffigen] Use Opaque to represent empty Structs (#142, #143) (#166)
diff --git a/pkgs/ffigen/.github/workflows/test-package.yml b/pkgs/ffigen/.github/workflows/test-package.yml index a5cd11a..7de66eb 100644 --- a/pkgs/ffigen/.github/workflows/test-package.yml +++ b/pkgs/ffigen/.github/workflows/test-package.yml
@@ -20,7 +20,7 @@ strategy: fail-fast: false matrix: - sdk: [2.12.0-198.0.dev] # TODO(127): Revert to stable. + sdk: [2.12.0-237.0.dev] # TODO(127): Revert to stable. steps: - uses: actions/checkout@v2 - uses: dart-lang/setup-dart@v1.0 @@ -44,7 +44,7 @@ - uses: actions/checkout@v2 - uses: dart-lang/setup-dart@v1.0 with: - sdk: 2.12.0-198.0.dev # TODO(127): Revert to stable. + sdk: 2.12.0-237.0.dev # TODO(127): Revert to stable. - name: Install dependencies run: dart pub get - name: Install libclang-10-dev
diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md index 1e49bdc..e877eb7 100644 --- a/pkgs/ffigen/CHANGELOG.md +++ b/pkgs/ffigen/CHANGELOG.md
@@ -1,3 +1,6 @@ +# 2.0.0-dev.5 +- Use `Opaque` for representing empty `Struct`s. + # 2.0.0-dev.4 - Add support for parsing and generating globals.
diff --git a/pkgs/ffigen/example/c_json/pubspec.yaml b/pkgs/ffigen/example/c_json/pubspec.yaml index 931aaea..76e4198 100644 --- a/pkgs/ffigen/example/c_json/pubspec.yaml +++ b/pkgs/ffigen/example/c_json/pubspec.yaml
@@ -5,7 +5,7 @@ name: c_json_example environment: - sdk: '>=2.12.0-198.0.dev <3.0.0' + sdk: '>=2.12.0-237.0.dev <3.0.0' dependencies: ffi: ^0.2.0-nullsafety.1
diff --git a/pkgs/ffigen/example/libclang-example/generated_bindings.dart b/pkgs/ffigen/example/libclang-example/generated_bindings.dart index 0edbcb9..330c63f 100644 --- a/pkgs/ffigen/example/libclang-example/generated_bindings.dart +++ b/pkgs/ffigen/example/libclang-example/generated_bindings.dart
@@ -6250,9 +6250,9 @@ external int Count; } -class CXTargetInfoImpl extends ffi.Struct {} +class CXTargetInfoImpl extends ffi.Opaque {} -class CXTranslationUnitImpl extends ffi.Struct {} +class CXTranslationUnitImpl extends ffi.Opaque {} /// Provides the contents of a file that has not yet been saved to disk. /// @@ -6636,7 +6636,7 @@ external CXString Message; } -class CXCursorSetImpl extends ffi.Struct {} +class CXCursorSetImpl extends ffi.Opaque {} /// Describes the kind of type abstract class CXTypeKind {
diff --git a/pkgs/ffigen/example/libclang-example/pubspec.yaml b/pkgs/ffigen/example/libclang-example/pubspec.yaml index df66b0b..efce084 100644 --- a/pkgs/ffigen/example/libclang-example/pubspec.yaml +++ b/pkgs/ffigen/example/libclang-example/pubspec.yaml
@@ -5,7 +5,7 @@ name: libclang_example environment: - sdk: '>=2.12.0-198.0.dev <3.0.0' + sdk: '>=2.12.0-237.0.dev <3.0.0' dev_dependencies: ffigen:
diff --git a/pkgs/ffigen/example/simple/pubspec.yaml b/pkgs/ffigen/example/simple/pubspec.yaml index ce3aa5e..d3562ef 100644 --- a/pkgs/ffigen/example/simple/pubspec.yaml +++ b/pkgs/ffigen/example/simple/pubspec.yaml
@@ -5,7 +5,7 @@ name: simple_example environment: - sdk: '>=2.12.0-198.0.dev <3.0.0' + sdk: '>=2.12.0-237.0.dev <3.0.0' dev_dependencies: ffigen:
diff --git a/pkgs/ffigen/lib/src/code_generator/global.dart b/pkgs/ffigen/lib/src/code_generator/global.dart index d419e92..42db339 100644 --- a/pkgs/ffigen/lib/src/code_generator/global.dart +++ b/pkgs/ffigen/lib/src/code_generator/global.dart
@@ -61,12 +61,18 @@ final pointerName = w.wrapperLevelUniqueNamer.makeUnique('_$globalVarName'); final dartType = type.getDartType(w); final cType = type.getCType(w); - final refOrValue = type.broadType == BroadType.Struct ? 'ref' : 'value'; s.write( - "late final ${w.ffiLibraryPrefix}.Pointer<$dartType> $pointerName = ${w.dylibIdentifier}.lookup<$cType>('$originalName');\n\n"); - s.write('$dartType get $globalVarName => $pointerName.$refOrValue;\n\n'); - if (type.broadType != BroadType.Struct) { + "late final ${w.ffiLibraryPrefix}.Pointer<$cType> $pointerName = ${w.dylibIdentifier}.lookup<$cType>('$originalName');\n\n"); + if (type.broadType == BroadType.Struct) { + if (type.struc!.isOpaque) { + s.write( + '${w.ffiLibraryPrefix}.Pointer<$cType> get $globalVarName => $pointerName;\n\n'); + } else { + s.write('$dartType get $globalVarName => $pointerName.ref;\n\n'); + } + } else { + s.write('$dartType get $globalVarName => $pointerName.value;\n\n'); s.write( 'set $globalVarName($dartType value) => $pointerName.value = value;\n\n'); }
diff --git a/pkgs/ffigen/lib/src/code_generator/library.dart b/pkgs/ffigen/lib/src/code_generator/library.dart index 4ea8e65..139ef4f 100644 --- a/pkgs/ffigen/lib/src/code_generator/library.dart +++ b/pkgs/ffigen/lib/src/code_generator/library.dart
@@ -110,6 +110,7 @@ runInShell: Platform.isWindows); if (result.stderr.toString().isNotEmpty) { _logger.severe(result.stderr); + throw FormatException('Unable to format generated file: $path.'); } }
diff --git a/pkgs/ffigen/lib/src/code_generator/struc.dart b/pkgs/ffigen/lib/src/code_generator/struc.dart index 8958139..2a0aca5 100644 --- a/pkgs/ffigen/lib/src/code_generator/struc.dart +++ b/pkgs/ffigen/lib/src/code_generator/struc.dart
@@ -42,6 +42,8 @@ List<Member> members; + bool get isOpaque => members.isEmpty; + Struc({ String? usr, String? originalName, @@ -102,7 +104,7 @@ // Write class declaration. s.write( - 'class $enclosingClassName extends ${w.ffiLibraryPrefix}.Struct{\n'); + 'class $enclosingClassName extends ${w.ffiLibraryPrefix}.${isOpaque ? 'Opaque' : 'Struct'}{\n'); for (final m in members) { final memberName = localUniqueNamer.makeUnique(m.name); if (m.type.broadType == BroadType.ConstantArray) {
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 7e7ab7c..a68621e 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
@@ -920,7 +920,7 @@ external int private_flags; } -class CXTranslationUnitImpl extends ffi.Struct {} +class CXTranslationUnitImpl extends ffi.Opaque {} /// Provides the contents of a file that has not yet been saved to disk. ///
diff --git a/pkgs/ffigen/lib/src/header_parser/data.dart b/pkgs/ffigen/lib/src/header_parser/data.dart index c2b371e..ac16572 100644 --- a/pkgs/ffigen/lib/src/header_parser/data.dart +++ b/pkgs/ffigen/lib/src/header_parser/data.dart
@@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:ffi'; -import 'dart:isolate'; import 'package:ffigen/src/code_generator.dart' show Constant; import 'package:ffigen/src/config_provider.dart' show Config;
diff --git a/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml index 87663a2..cb13584 100644 --- a/pkgs/ffigen/pubspec.yaml +++ b/pkgs/ffigen/pubspec.yaml
@@ -3,12 +3,12 @@ # BSD-style license that can be found in the LICENSE file. name: ffigen -version: 2.0.0-dev.4 +version: 2.0.0-dev.5 homepage: https://github.com/dart-lang/ffigen description: Experimental generator for FFI bindings, using LibClang to parse C header files. environment: - sdk: '>=2.12.0-198.0.dev <3.0.0' + sdk: '>=2.12.0-237.0.dev <3.0.0' dependencies: ffi: ^0.2.0-nullsafety.1
diff --git a/pkgs/ffigen/test/code_generator_test.dart b/pkgs/ffigen/test/code_generator_test.dart deleted file mode 100644 index aae8b0f..0000000 --- a/pkgs/ffigen/test/code_generator_test.dart +++ /dev/null
@@ -1,921 +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:io'; - -import 'package:ffigen/src/code_generator.dart'; -import 'package:test/test.dart'; - -void main() { - group('code_generator: ', () { - test('Function Binding (primitives, pointers)', () { - final library = Library( - name: 'Bindings', - bindings: [ - Func( - name: 'noParam', - dartDoc: 'Just a test function\nheres another line', - returnType: Type.nativeType( - SupportedNativeType.Int32, - ), - ), - Func( - name: 'withPrimitiveParam', - parameters: [ - Parameter( - name: 'a', - type: Type.nativeType( - SupportedNativeType.Int32, - ), - ), - Parameter( - name: 'b', - type: Type.nativeType( - SupportedNativeType.Uint8, - ), - ), - ], - returnType: Type.nativeType( - SupportedNativeType.Char, - ), - ), - Func( - name: 'withPointerParam', - parameters: [ - Parameter( - name: 'a', - type: Type.pointer( - Type.nativeType( - SupportedNativeType.Int32, - ), - ), - ), - Parameter( - name: 'b', - type: Type.pointer( - Type.pointer( - Type.nativeType( - SupportedNativeType.Uint8, - ), - ), - ), - ), - ], - returnType: Type.pointer( - Type.nativeType( - SupportedNativeType.Double, - ), - ), - ), - ], - ); - - final gen = library.generate(); - - // Writing to file for debug purpose. - final file = File( - 'test/debug_generated/Function-Binding-test-output.dart', - ); - try { - expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -import 'dart:ffi' as ffi; - -class Bindings{ -/// Holds the Dynamic library. -final ffi.DynamicLibrary _dylib; - -/// The symbols are looked up in [dynamicLibrary]. -Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary; - -/// Just a test function -/// heres another line -int noParam( -) { -return (_noParam ??= _dylib.lookupFunction<_c_noParam,_dart_noParam>('noParam'))( - ); -} -_dart_noParam? _noParam; - -int withPrimitiveParam( - int a, - int b, -) { -return (_withPrimitiveParam ??= _dylib.lookupFunction<_c_withPrimitiveParam,_dart_withPrimitiveParam>('withPrimitiveParam'))( - a, - b, - ); -} -_dart_withPrimitiveParam? _withPrimitiveParam; - -ffi.Pointer<ffi.Double> withPointerParam( - ffi.Pointer<ffi.Int32> a, - ffi.Pointer<ffi.Pointer<ffi.Uint8>> b, -) { -return (_withPointerParam ??= _dylib.lookupFunction<_c_withPointerParam,_dart_withPointerParam>('withPointerParam'))( - a, - b, - ); -} -_dart_withPointerParam? _withPointerParam; - -} - -typedef _c_noParam = ffi.Int32 Function( -); - -typedef _dart_noParam = int Function( -); - -typedef _c_withPrimitiveParam = ffi.Uint8 Function( - ffi.Int32 a, - ffi.Uint8 b, -); - -typedef _dart_withPrimitiveParam = int Function( - int a, - int b, -); - -typedef _c_withPointerParam = ffi.Pointer<ffi.Double> Function( - ffi.Pointer<ffi.Int32> a, - ffi.Pointer<ffi.Pointer<ffi.Uint8>> b, -); - -typedef _dart_withPointerParam = ffi.Pointer<ffi.Double> Function( - ffi.Pointer<ffi.Int32> a, - ffi.Pointer<ffi.Pointer<ffi.Uint8>> b, -); - -'''); - if (file.existsSync()) { - file.delete(); - } - } catch (e) { - file.writeAsStringSync(gen); - print('Failed test, Debug output: ${file.absolute.path}'); - rethrow; - } - }); - - test('Struct Binding (primitives, pointers)', () { - final library = Library( - name: 'Bindings', - bindings: [ - Struc( - name: 'NoMember', - dartDoc: 'Just a test struct\nheres another line', - ), - Struc( - name: 'WithPrimitiveMember', - members: [ - Member( - name: 'a', - type: Type.nativeType( - SupportedNativeType.Int32, - ), - ), - Member( - name: 'b', - type: Type.nativeType( - SupportedNativeType.Double, - ), - ), - Member( - name: 'c', - type: Type.nativeType( - SupportedNativeType.Char, - ), - ), - ], - ), - Struc( - name: 'WithPointerMember', - members: [ - Member( - name: 'a', - type: Type.pointer( - Type.nativeType( - SupportedNativeType.Int32, - ), - ), - ), - Member( - name: 'b', - type: Type.pointer( - Type.pointer( - Type.nativeType( - SupportedNativeType.Double, - ), - ), - ), - ), - Member( - name: 'c', - type: Type.nativeType( - SupportedNativeType.Char, - ), - ), - ], - ), - ], - ); - - final gen = library.generate(); - - // Writing to file for debug purpose. - final file = File('test/debug_generated/Struct-Binding-test-output.dart'); - - try { - expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -import 'dart:ffi' as ffi; - -/// Just a test struct -/// heres another line -class NoMember extends ffi.Struct{ -} - -class WithPrimitiveMember extends ffi.Struct{ - @ffi.Int32() - external int a; - - @ffi.Double() - external double b; - - @ffi.Uint8() - external int c; - -} - -class WithPointerMember extends ffi.Struct{ - external ffi.Pointer<ffi.Int32> a; - - external ffi.Pointer<ffi.Pointer<ffi.Double>> b; - - @ffi.Uint8() - external int c; - -} - -'''); - if (file.existsSync()) { - file.delete(); - } - } catch (e) { - file.writeAsStringSync(gen); - print('Failed test, Debug output: ${file.absolute.path}'); - rethrow; - } - }); - - test('Function and Struct Binding (pointer to Struct)', () { - final struct_some = Struc( - name: 'SomeStruc', - members: [ - Member( - name: 'a', - type: Type.nativeType( - SupportedNativeType.Int32, - ), - ), - Member( - name: 'b', - type: Type.nativeType( - SupportedNativeType.Double, - ), - ), - Member( - name: 'c', - type: Type.nativeType( - SupportedNativeType.Char, - ), - ), - ], - ); - final library = Library( - name: 'Bindings', - bindings: [ - struct_some, - Func( - name: 'someFunc', - parameters: [ - Parameter( - name: 'some', - type: Type.pointer( - Type.pointer( - Type.struct( - struct_some, - ), - ), - ), - ), - ], - returnType: Type.pointer( - Type.struct( - struct_some, - ), - ), - ), - ], - ); - - final gen = library.generate(); - - // Writing to file for debug purpose. - final file = - File('test/debug_generated/Func-n-Struct-Binding-test-output.dart'); - try { - //expect - expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -import 'dart:ffi' as ffi; - -class Bindings{ -/// Holds the Dynamic library. -final ffi.DynamicLibrary _dylib; - -/// The symbols are looked up in [dynamicLibrary]. -Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary; - -ffi.Pointer<SomeStruc> someFunc( - ffi.Pointer<ffi.Pointer<SomeStruc>> some, -) { -return (_someFunc ??= _dylib.lookupFunction<_c_someFunc,_dart_someFunc>('someFunc'))( - some, - ); -} -_dart_someFunc? _someFunc; - -} - -class SomeStruc extends ffi.Struct{ - @ffi.Int32() - external int a; - - @ffi.Double() - external double b; - - @ffi.Uint8() - external int c; - -} - -typedef _c_someFunc = ffi.Pointer<SomeStruc> Function( - ffi.Pointer<ffi.Pointer<SomeStruc>> some, -); - -typedef _dart_someFunc = ffi.Pointer<SomeStruc> Function( - ffi.Pointer<ffi.Pointer<SomeStruc>> some, -); - -'''); - if (file.existsSync()) { - file.delete(); - } - } catch (e) { - file.writeAsStringSync(gen); - print('Failed test, Debug output: ${file.absolute.path}'); - rethrow; - } - }); - - test('global (primitives, pointers, pointer to struct)', () { - final struc_some = Struc( - name: 'Some', - ); - final library = Library( - name: 'Bindings', - bindings: [ - Global( - name: 'test1', - type: Type.nativeType( - SupportedNativeType.Int32, - ), - ), - Global( - name: 'test2', - type: Type.pointer( - Type.nativeType( - SupportedNativeType.Float, - ), - ), - ), - struc_some, - Global( - name: 'test5', - type: Type.pointer( - Type.struct( - struc_some, - ), - ), - ), - ], - ); - - final gen = library.generate(); - - // Writing to file for debug purpose. - final file = File( - 'test/debug_generated/Global-Binding-test-output.dart', - ); - try { - expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -import 'dart:ffi' as ffi; - -class Bindings{ -/// Holds the Dynamic library. -final ffi.DynamicLibrary _dylib; - -/// The symbols are looked up in [dynamicLibrary]. -Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary; - -late final ffi.Pointer<int> _test1 = _dylib.lookup<ffi.Int32>('test1'); - -int get test1 => _test1.value; - -set test1(int value) => _test1.value = value; - -late final ffi.Pointer<ffi.Pointer<ffi.Float>> _test2 = _dylib.lookup<ffi.Pointer<ffi.Float>>('test2'); - -ffi.Pointer<ffi.Float> get test2 => _test2.value; - -set test2(ffi.Pointer<ffi.Float> value) => _test2.value = value; - -late final ffi.Pointer<ffi.Pointer<Some>> _test5 = _dylib.lookup<ffi.Pointer<Some>>('test5'); - -ffi.Pointer<Some> get test5 => _test5.value; - -set test5(ffi.Pointer<Some> value) => _test5.value = value; - -} - -class Some extends ffi.Struct{ -} - -'''); - if (file.existsSync()) { - file.delete(); - } - } catch (e) { - file.writeAsStringSync(gen); - print('Failed test, Debug output: ${file.absolute.path}'); - rethrow; - } - }); - - test('constant', () { - final library = Library( - name: 'Bindings', - bindings: [ - Constant( - name: 'test1', - rawType: 'int', - rawValue: '20', - ), - Constant( - name: 'test2', - rawType: 'double', - rawValue: '20.0', - ), - ], - ); - - final gen = library.generate(); - - // Writing to file for debug purpose. - final file = File( - 'test/debug_generated/Constant-test-output.dart', - ); - try { - expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -import 'dart:ffi' as ffi; - -const int test1 = 20; - -const double test2 = 20.0; - -'''); - if (file.existsSync()) { - file.delete(); - } - } catch (e) { - file.writeAsStringSync(gen); - print('Failed test, Debug output: ${file.absolute.path}'); - rethrow; - } - }); - - test('enum_class', () { - final library = Library( - name: 'Bindings', - bindings: [ - EnumClass( - name: 'Constants', - dartDoc: 'test line 1\ntest line 2', - enumConstants: [ - EnumConstant( - name: 'a', - value: 10, - ), - EnumConstant(name: 'b', value: -1, dartDoc: 'negative'), - ], - ), - ], - ); - - final gen = library.generate(); - - // Writing to file for debug purpose. - final file = File( - 'test/debug_generated/enum-class-test-output.dart', - ); - try { - expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -import 'dart:ffi' as ffi; - -/// test line 1 -/// test line 2 -abstract class Constants { - static const int a = 10; - /// negative - static const int b = -1; -} - -'''); - if (file.existsSync()) { - file.delete(); - } - } catch (e) { - file.writeAsStringSync(gen); - print('Failed test, Debug output: ${file.absolute.path}'); - rethrow; - } - }); - test('Internal conflict resolution', () { - final library = Library( - name: 'init_dylib', - bindings: [ - Func( - name: 'test', - returnType: Type.nativeType(SupportedNativeType.Void), - ), - Func( - name: '_test', - returnType: Type.nativeType(SupportedNativeType.Void), - ), - Func( - name: '_c_test', - returnType: Type.nativeType(SupportedNativeType.Void), - ), - Func( - name: '_dart_test', - returnType: Type.nativeType(SupportedNativeType.Void), - ), - Struc( - name: '_Test', - members: [ - Member( - name: 'array', - type: Type.constantArray( - 2, - Type.nativeType( - SupportedNativeType.Int8, - ), - ), - ), - ], - ), - Struc(name: 'ArrayHelperPrefixCollisionTest'), - Func( - name: 'Test', - returnType: Type.nativeType(SupportedNativeType.Void), - ), - EnumClass(name: '_c_Test'), - EnumClass(name: 'init_dylib'), - ], - ); - - final gen = library.generate(); - - // Writing to file for debug purpose. - final file = File( - 'test/debug_generated/internal-conflict-resolution.dart', - ); - try { - expect(gen, r'''// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -import 'dart:ffi' as ffi; - -class init_dylib_1{ -/// Holds the Dynamic library. -final ffi.DynamicLibrary _dylib; - -/// The symbols are looked up in [dynamicLibrary]. -init_dylib_1(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary; - -void test( -) { -return (_test_1 ??= _dylib.lookupFunction<_c_test1,_dart_test1>('test'))( - ); -} -_dart_test1? _test_1; - -void _test( -) { -return (__test ??= _dylib.lookupFunction<_c__test,_dart__test>('_test'))( - ); -} -_dart__test? __test; - -void _c_test( -) { -return (__c_test ??= _dylib.lookupFunction<_c__c_test,_dart__c_test>('_c_test'))( - ); -} -_dart__c_test? __c_test; - -void _dart_test( -) { -return (__dart_test ??= _dylib.lookupFunction<_c__dart_test,_dart__dart_test>('_dart_test'))( - ); -} -_dart__dart_test? __dart_test; - -void Test( -) { -return (_Test ??= _dylib.lookupFunction<_c_Test1,_dart_Test>('Test'))( - ); -} -_dart_Test? _Test; - -} - -class _Test extends ffi.Struct{ - @ffi.Int8() - external int _unique_array_item_0; - @ffi.Int8() - external int _unique_array_item_1; -/// Helper for array `array`. -ArrayHelper1__Test_array_level0 get array => ArrayHelper1__Test_array_level0(this, [2], 0, 0); -} - -/// Helper for array `array` in struct `_Test`. -class ArrayHelper1__Test_array_level0{ -final _Test _struct; -final List<int> dimensions; -final int level; -final int _absoluteIndex; -int get length => dimensions[level]; -ArrayHelper1__Test_array_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._unique_array_item_0; -case 1: - return _struct._unique_array_item_1; -default: - throw Exception('Invalid Array Helper generated.');} -} -void operator[]=(int index, int value){ -_checkBounds(index); -switch(_absoluteIndex+index){ -case 0: - _struct._unique_array_item_0 = value; - break; -case 1: - _struct._unique_array_item_1 = value; - break; -default: - throw Exception('Invalid Array Helper generated.'); -} -} -} -class ArrayHelperPrefixCollisionTest extends ffi.Struct{ -} - -abstract class _c_Test { -} - -abstract class init_dylib { -} - -typedef _c_test1 = ffi.Void Function( -); - -typedef _dart_test1 = void Function( -); - -typedef _c__test = ffi.Void Function( -); - -typedef _dart__test = void Function( -); - -typedef _c__c_test = ffi.Void Function( -); - -typedef _dart__c_test = void Function( -); - -typedef _c__dart_test = ffi.Void Function( -); - -typedef _dart__dart_test = void Function( -); - -typedef _c_Test1 = ffi.Void Function( -); - -typedef _dart_Test = void Function( -); - -'''); - if (file.existsSync()) { - file.delete(); - } - } catch (e) { - file.writeAsStringSync(gen); - print('Failed test, Debug output: ${file.absolute.path}'); - rethrow; - } - }); - }); - test('boolean_dartBool', () { - final library = Library( - name: 'Bindings', - dartBool: true, - bindings: [ - Func( - name: 'test1', - returnType: Type.boolean(), - parameters: [ - Parameter(name: 'a', type: Type.boolean()), - Parameter(name: 'b', type: Type.pointer(Type.boolean())), - ], - ), - Struc( - name: 'test2', - members: [ - Member(name: 'a', type: Type.boolean()), - ], - ), - ], - ); - - final gen = library.generate(); - - // Writing to file for debug purpose. - final file = File( - 'test/debug_generated/boolean-dartbool-output.dart', - ); - try { - expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -import 'dart:ffi' as ffi; - -class Bindings{ -/// Holds the Dynamic library. -final ffi.DynamicLibrary _dylib; - -/// The symbols are looked up in [dynamicLibrary]. -Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary; - -bool test1( - bool a, - ffi.Pointer<ffi.Uint8> b, -) { -return (_test1 ??= _dylib.lookupFunction<_c_test1,_dart_test1>('test1'))( - a?1:0, - b, - )!=0; -} -_dart_test1? _test1; - -} - -class test2 extends ffi.Struct{ - @ffi.Uint8() - external int a; - -} - -typedef _c_test1 = ffi.Uint8 Function( - ffi.Uint8 a, - ffi.Pointer<ffi.Uint8> b, -); - -typedef _dart_test1 = int Function( - int a, - ffi.Pointer<ffi.Uint8> b, -); - -'''); - if (file.existsSync()) { - file.delete(); - } - } catch (e) { - file.writeAsStringSync(gen); - print('Failed test, Debug output: ${file.absolute.path}'); - rethrow; - } - }); - test('boolean_no_dartBool', () { - final library = Library( - name: 'Bindings', - dartBool: false, - bindings: [ - Func( - name: 'test1', - returnType: Type.boolean(), - parameters: [ - Parameter(name: 'a', type: Type.boolean()), - Parameter(name: 'b', type: Type.pointer(Type.boolean())), - ], - ), - Struc( - name: 'test2', - members: [ - Member(name: 'a', type: Type.boolean()), - ], - ), - ], - ); - - final gen = library.generate(); - - // Writing to file for debug purpose. - final file = File( - 'test/debug_generated/boolean-no-dartBool-output.dart', - ); - try { - expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -import 'dart:ffi' as ffi; - -class Bindings{ -/// Holds the Dynamic library. -final ffi.DynamicLibrary _dylib; - -/// The symbols are looked up in [dynamicLibrary]. -Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary; - -int test1( - int a, - ffi.Pointer<ffi.Uint8> b, -) { -return (_test1 ??= _dylib.lookupFunction<_c_test1,_dart_test1>('test1'))( - a, - b, - ); -} -_dart_test1? _test1; - -} - -class test2 extends ffi.Struct{ - @ffi.Uint8() - external int a; - -} - -typedef _c_test1 = ffi.Uint8 Function( - ffi.Uint8 a, - ffi.Pointer<ffi.Uint8> b, -); - -typedef _dart_test1 = int Function( - int a, - ffi.Pointer<ffi.Uint8> b, -); - -'''); - if (file.existsSync()) { - file.delete(); - } - } catch (e) { - file.writeAsStringSync(gen); - print('Failed test, Debug output: ${file.absolute.path}'); - rethrow; - } - }); -}
diff --git a/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart b/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart new file mode 100644 index 0000000..350b799 --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart
@@ -0,0 +1,382 @@ +// Copyright (c) 2021, 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 'package:ffigen/src/code_generator.dart'; +import 'package:test/test.dart'; +import '../test_utils.dart'; + +void main() { + group('code_generator: ', () { + test('Function Binding (primitives, pointers)', () { + final library = Library( + name: 'Bindings', + bindings: [ + Func( + name: 'noParam', + dartDoc: 'Just a test function\nheres another line', + returnType: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Func( + name: 'withPrimitiveParam', + parameters: [ + Parameter( + name: 'a', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Parameter( + name: 'b', + type: Type.nativeType( + SupportedNativeType.Uint8, + ), + ), + ], + returnType: Type.nativeType( + SupportedNativeType.Char, + ), + ), + Func( + name: 'withPointerParam', + parameters: [ + Parameter( + name: 'a', + type: Type.pointer( + Type.nativeType( + SupportedNativeType.Int32, + ), + ), + ), + Parameter( + name: 'b', + type: Type.pointer( + Type.pointer( + Type.nativeType( + SupportedNativeType.Uint8, + ), + ), + ), + ), + ], + returnType: Type.pointer( + Type.nativeType( + SupportedNativeType.Double, + ), + ), + ), + ], + ); + + _matchLib(library, 'function'); + }); + + test('Struct Binding (primitives, pointers)', () { + final library = Library( + name: 'Bindings', + bindings: [ + Struc( + name: 'NoMember', + dartDoc: 'Just a test struct\nheres another line', + ), + Struc( + name: 'WithPrimitiveMember', + members: [ + Member( + name: 'a', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Member( + name: 'b', + type: Type.nativeType( + SupportedNativeType.Double, + ), + ), + Member( + name: 'c', + type: Type.nativeType( + SupportedNativeType.Char, + ), + ), + ], + ), + Struc( + name: 'WithPointerMember', + members: [ + Member( + name: 'a', + type: Type.pointer( + Type.nativeType( + SupportedNativeType.Int32, + ), + ), + ), + Member( + name: 'b', + type: Type.pointer( + Type.pointer( + Type.nativeType( + SupportedNativeType.Double, + ), + ), + ), + ), + Member( + name: 'c', + type: Type.nativeType( + SupportedNativeType.Char, + ), + ), + ], + ), + ], + ); + + _matchLib(library, 'struct'); + }); + + test('Function and Struct Binding (pointer to Struct)', () { + final struct_some = Struc( + name: 'SomeStruc', + members: [ + Member( + name: 'a', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Member( + name: 'b', + type: Type.nativeType( + SupportedNativeType.Double, + ), + ), + Member( + name: 'c', + type: Type.nativeType( + SupportedNativeType.Char, + ), + ), + ], + ); + final library = Library( + name: 'Bindings', + bindings: [ + struct_some, + Func( + name: 'someFunc', + parameters: [ + Parameter( + name: 'some', + type: Type.pointer( + Type.pointer( + Type.struct( + struct_some, + ), + ), + ), + ), + ], + returnType: Type.pointer( + Type.struct( + struct_some, + ), + ), + ), + ], + ); + + _matchLib(library, 'function_n_struct'); + }); + + test('global (primitives, pointers, pointer to struct)', () { + final struc_some = Struc( + name: 'Some', + ); + final emptyGlobalStruc = Struc(name: 'EmptyStruct'); + + final library = Library( + name: 'Bindings', + bindings: [ + Global( + name: 'test1', + type: Type.nativeType( + SupportedNativeType.Int32, + ), + ), + Global( + name: 'test2', + type: Type.pointer( + Type.nativeType( + SupportedNativeType.Float, + ), + ), + ), + struc_some, + Global( + name: 'test5', + type: Type.pointer( + Type.struct( + struc_some, + ), + ), + ), + emptyGlobalStruc, + Global(name: 'globalStruct', type: Type.struct(emptyGlobalStruc)), + ], + ); + _matchLib(library, 'global'); + }); + + test('constant', () { + final library = Library( + name: 'Bindings', + header: '// ignore_for_file: unused_import\n', + bindings: [ + Constant( + name: 'test1', + rawType: 'int', + rawValue: '20', + ), + Constant( + name: 'test2', + rawType: 'double', + rawValue: '20.0', + ), + ], + ); + _matchLib(library, 'constant'); + }); + + test('enum_class', () { + final library = Library( + name: 'Bindings', + header: '// ignore_for_file: unused_import\n', + bindings: [ + EnumClass( + name: 'Constants', + dartDoc: 'test line 1\ntest line 2', + enumConstants: [ + EnumConstant( + name: 'a', + value: 10, + ), + EnumConstant(name: 'b', value: -1, dartDoc: 'negative'), + ], + ), + ], + ); + _matchLib(library, 'enumclass'); + }); + test('Internal conflict resolution', () { + final library = Library( + name: 'init_dylib', + header: '// ignore_for_file: unused_element\n', + bindings: [ + Func( + name: 'test', + returnType: Type.nativeType(SupportedNativeType.Void), + ), + Func( + name: '_test', + returnType: Type.nativeType(SupportedNativeType.Void), + ), + Func( + name: '_c_test', + returnType: Type.nativeType(SupportedNativeType.Void), + ), + Func( + name: '_dart_test', + returnType: Type.nativeType(SupportedNativeType.Void), + ), + Struc( + name: '_Test', + members: [ + Member( + name: 'array', + type: Type.constantArray( + 2, + Type.nativeType( + SupportedNativeType.Int8, + ), + ), + ), + ], + ), + Struc(name: 'ArrayHelperPrefixCollisionTest'), + Func( + name: 'Test', + returnType: Type.nativeType(SupportedNativeType.Void), + ), + EnumClass(name: '_c_Test'), + EnumClass(name: 'init_dylib'), + ], + ); + _matchLib(library, 'internal_conflict_resolution'); + }); + }); + test('boolean_dartBool', () { + final library = Library( + name: 'Bindings', + dartBool: true, + bindings: [ + Func( + name: 'test1', + returnType: Type.boolean(), + parameters: [ + Parameter(name: 'a', type: Type.boolean()), + Parameter(name: 'b', type: Type.pointer(Type.boolean())), + ], + ), + Struc( + name: 'test2', + members: [ + Member(name: 'a', type: Type.boolean()), + ], + ), + ], + ); + _matchLib(library, 'boolean_dartbool'); + }); + test('boolean_no_dartBool', () { + final library = Library( + name: 'Bindings', + dartBool: false, + bindings: [ + Func( + name: 'test1', + returnType: Type.boolean(), + parameters: [ + Parameter(name: 'a', type: Type.boolean()), + Parameter(name: 'b', type: Type.pointer(Type.boolean())), + ], + ), + Struc( + name: 'test2', + members: [ + Member(name: 'a', type: Type.boolean()), + ], + ), + ], + ); + _matchLib(library, 'boolean_no_dartbool'); + }); +} + +/// Utility to match expected bindings to the generated bindings. +void _matchLib(Library lib, String testName) { + matchLibraryWithExpected(lib, [ + 'test', + 'debug_generated', + 'code_generator_test_${testName}_output.dart' + ], [ + 'test', + 'code_generator_tests', + 'expected_bindings', + '_expected_${testName}_bindings.dart' + ]); +}
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_boolean_dartbool_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_boolean_dartbool_bindings.dart new file mode 100644 index 0000000..9e9d6ac --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_boolean_dartbool_bindings.dart
@@ -0,0 +1,40 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +class Bindings { + /// Holds the Dynamic library. + final ffi.DynamicLibrary _dylib; + + /// The symbols are looked up in [dynamicLibrary]. + Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary; + + bool test1( + bool a, + ffi.Pointer<ffi.Uint8> b, + ) { + return (_test1 ??= _dylib.lookupFunction<_c_test1, _dart_test1>('test1'))( + a ? 1 : 0, + b, + ) != + 0; + } + + _dart_test1? _test1; +} + +class test2 extends ffi.Struct { + @ffi.Uint8() + external int a; +} + +typedef _c_test1 = ffi.Uint8 Function( + ffi.Uint8 a, + ffi.Pointer<ffi.Uint8> b, +); + +typedef _dart_test1 = int Function( + int a, + ffi.Pointer<ffi.Uint8> b, +);
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_boolean_no_dartbool_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_boolean_no_dartbool_bindings.dart new file mode 100644 index 0000000..99ed563 --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_boolean_no_dartbool_bindings.dart
@@ -0,0 +1,39 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +class Bindings { + /// Holds the Dynamic library. + final ffi.DynamicLibrary _dylib; + + /// The symbols are looked up in [dynamicLibrary]. + Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary; + + int test1( + int a, + ffi.Pointer<ffi.Uint8> b, + ) { + return (_test1 ??= _dylib.lookupFunction<_c_test1, _dart_test1>('test1'))( + a, + b, + ); + } + + _dart_test1? _test1; +} + +class test2 extends ffi.Struct { + @ffi.Uint8() + external int a; +} + +typedef _c_test1 = ffi.Uint8 Function( + ffi.Uint8 a, + ffi.Pointer<ffi.Uint8> b, +); + +typedef _dart_test1 = int Function( + int a, + ffi.Pointer<ffi.Uint8> b, +);
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_constant_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_constant_bindings.dart new file mode 100644 index 0000000..d01f2b1 --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_constant_bindings.dart
@@ -0,0 +1,10 @@ +// ignore_for_file: unused_import + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +const int test1 = 20; + +const double test2 = 20.0;
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_enumclass_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_enumclass_bindings.dart new file mode 100644 index 0000000..0aa2dbb --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_enumclass_bindings.dart
@@ -0,0 +1,15 @@ +// ignore_for_file: unused_import + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// test line 1 +/// test line 2 +abstract class Constants { + static const int a = 10; + + /// negative + static const int b = -1; +}
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart new file mode 100644 index 0000000..82736d2 --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart
@@ -0,0 +1,73 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +class Bindings { + /// Holds the Dynamic library. + final ffi.DynamicLibrary _dylib; + + /// The symbols are looked up in [dynamicLibrary]. + Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary; + + /// Just a test function + /// heres another line + int noParam() { + return (_noParam ??= + _dylib.lookupFunction<_c_noParam, _dart_noParam>('noParam'))(); + } + + _dart_noParam? _noParam; + + int withPrimitiveParam( + int a, + int b, + ) { + return (_withPrimitiveParam ??= + _dylib.lookupFunction<_c_withPrimitiveParam, _dart_withPrimitiveParam>( + 'withPrimitiveParam'))( + a, + b, + ); + } + + _dart_withPrimitiveParam? _withPrimitiveParam; + + ffi.Pointer<ffi.Double> withPointerParam( + ffi.Pointer<ffi.Int32> a, + ffi.Pointer<ffi.Pointer<ffi.Uint8>> b, + ) { + return (_withPointerParam ??= + _dylib.lookupFunction<_c_withPointerParam, _dart_withPointerParam>( + 'withPointerParam'))( + a, + b, + ); + } + + _dart_withPointerParam? _withPointerParam; +} + +typedef _c_noParam = ffi.Int32 Function(); + +typedef _dart_noParam = int Function(); + +typedef _c_withPrimitiveParam = ffi.Uint8 Function( + ffi.Int32 a, + ffi.Uint8 b, +); + +typedef _dart_withPrimitiveParam = int Function( + int a, + int b, +); + +typedef _c_withPointerParam = ffi.Pointer<ffi.Double> Function( + ffi.Pointer<ffi.Int32> a, + ffi.Pointer<ffi.Pointer<ffi.Uint8>> b, +); + +typedef _dart_withPointerParam = ffi.Pointer<ffi.Double> Function( + ffi.Pointer<ffi.Int32> a, + ffi.Pointer<ffi.Pointer<ffi.Uint8>> b, +);
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_n_struct_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_n_struct_bindings.dart new file mode 100644 index 0000000..4f0ea46 --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_n_struct_bindings.dart
@@ -0,0 +1,42 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +class Bindings { + /// Holds the Dynamic library. + final ffi.DynamicLibrary _dylib; + + /// The symbols are looked up in [dynamicLibrary]. + Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary; + + ffi.Pointer<SomeStruc> someFunc( + ffi.Pointer<ffi.Pointer<SomeStruc>> some, + ) { + return (_someFunc ??= + _dylib.lookupFunction<_c_someFunc, _dart_someFunc>('someFunc'))( + some, + ); + } + + _dart_someFunc? _someFunc; +} + +class SomeStruc extends ffi.Struct { + @ffi.Int32() + external int a; + + @ffi.Double() + external double b; + + @ffi.Uint8() + external int c; +} + +typedef _c_someFunc = ffi.Pointer<SomeStruc> Function( + ffi.Pointer<ffi.Pointer<SomeStruc>> some, +); + +typedef _dart_someFunc = ffi.Pointer<SomeStruc> Function( + ffi.Pointer<ffi.Pointer<SomeStruc>> some, +);
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart new file mode 100644 index 0000000..215858b --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart
@@ -0,0 +1,41 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +class Bindings { + /// Holds the Dynamic library. + final ffi.DynamicLibrary _dylib; + + /// The symbols are looked up in [dynamicLibrary]. + Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary; + + late final ffi.Pointer<ffi.Int32> _test1 = _dylib.lookup<ffi.Int32>('test1'); + + int get test1 => _test1.value; + + set test1(int value) => _test1.value = value; + + late final ffi.Pointer<ffi.Pointer<ffi.Float>> _test2 = + _dylib.lookup<ffi.Pointer<ffi.Float>>('test2'); + + ffi.Pointer<ffi.Float> get test2 => _test2.value; + + set test2(ffi.Pointer<ffi.Float> value) => _test2.value = value; + + late final ffi.Pointer<ffi.Pointer<Some>> _test5 = + _dylib.lookup<ffi.Pointer<Some>>('test5'); + + ffi.Pointer<Some> get test5 => _test5.value; + + set test5(ffi.Pointer<Some> value) => _test5.value = value; + + late final ffi.Pointer<EmptyStruct> _globalStruct = + _dylib.lookup<EmptyStruct>('globalStruct'); + + ffi.Pointer<EmptyStruct> get globalStruct => _globalStruct; +} + +class Some extends ffi.Opaque {} + +class EmptyStruct extends ffi.Opaque {}
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_internal_conflict_resolution_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_internal_conflict_resolution_bindings.dart new file mode 100644 index 0000000..a6fbe60 --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_internal_conflict_resolution_bindings.dart
@@ -0,0 +1,126 @@ +// ignore_for_file: unused_element + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +class init_dylib_1 { + /// Holds the Dynamic library. + final ffi.DynamicLibrary _dylib; + + /// The symbols are looked up in [dynamicLibrary]. + init_dylib_1(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary; + + void test() { + return (_test_1 ??= _dylib.lookupFunction<_c_test1, _dart_test1>('test'))(); + } + + _dart_test1? _test_1; + + void _test() { + return (__test ??= _dylib.lookupFunction<_c__test, _dart__test>('_test'))(); + } + + _dart__test? __test; + + void _c_test() { + return (__c_test ??= + _dylib.lookupFunction<_c__c_test, _dart__c_test>('_c_test'))(); + } + + _dart__c_test? __c_test; + + void _dart_test() { + return (__dart_test ??= + _dylib.lookupFunction<_c__dart_test, _dart__dart_test>('_dart_test'))(); + } + + _dart__dart_test? __dart_test; + + void Test() { + return (_Test ??= _dylib.lookupFunction<_c_Test1, _dart_Test>('Test'))(); + } + + _dart_Test? _Test; +} + +class _Test extends ffi.Struct { + @ffi.Int8() + external int _unique_array_item_0; + @ffi.Int8() + external int _unique_array_item_1; + + /// Helper for array `array`. + ArrayHelper1__Test_array_level0 get array => + ArrayHelper1__Test_array_level0(this, [2], 0, 0); +} + +/// Helper for array `array` in struct `_Test`. +class ArrayHelper1__Test_array_level0 { + final _Test _struct; + final List<int> dimensions; + final int level; + final int _absoluteIndex; + int get length => dimensions[level]; + ArrayHelper1__Test_array_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._unique_array_item_0; + case 1: + return _struct._unique_array_item_1; + default: + throw Exception('Invalid Array Helper generated.'); + } + } + + void operator []=(int index, int value) { + _checkBounds(index); + switch (_absoluteIndex + index) { + case 0: + _struct._unique_array_item_0 = value; + break; + case 1: + _struct._unique_array_item_1 = value; + break; + default: + throw Exception('Invalid Array Helper generated.'); + } + } +} + +class ArrayHelperPrefixCollisionTest extends ffi.Opaque {} + +abstract class _c_Test {} + +abstract class init_dylib {} + +typedef _c_test1 = ffi.Void Function(); + +typedef _dart_test1 = void Function(); + +typedef _c__test = ffi.Void Function(); + +typedef _dart__test = void Function(); + +typedef _c__c_test = ffi.Void Function(); + +typedef _dart__c_test = void Function(); + +typedef _c__dart_test = ffi.Void Function(); + +typedef _dart__dart_test = void Function(); + +typedef _c_Test1 = ffi.Void Function(); + +typedef _dart_Test = void Function();
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_struct_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_struct_bindings.dart new file mode 100644 index 0000000..f84642b --- /dev/null +++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_struct_bindings.dart
@@ -0,0 +1,28 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Just a test struct +/// heres another line +class NoMember extends ffi.Opaque {} + +class WithPrimitiveMember extends ffi.Struct { + @ffi.Int32() + external int a; + + @ffi.Double() + external double b; + + @ffi.Uint8() + external int c; +} + +class WithPointerMember extends ffi.Struct { + external ffi.Pointer<ffi.Int32> a; + + external ffi.Pointer<ffi.Pointer<ffi.Double>> b; + + @ffi.Uint8() + external int c; +}
diff --git a/pkgs/ffigen/test/header_parser_tests/globals.h b/pkgs/ffigen/test/header_parser_tests/globals.h index f0f464f..80da2b0 100644 --- a/pkgs/ffigen/test/header_parser_tests/globals.h +++ b/pkgs/ffigen/test/header_parser_tests/globals.h
@@ -13,3 +13,9 @@ // This should be ignored int GlobalIgnore; + +struct EmptyStruct +{ +}; + +struct EmptyStruct globalStruct;
diff --git a/pkgs/ffigen/test/header_parser_tests/globals_test.dart b/pkgs/ffigen/test/header_parser_tests/globals_test.dart index 7184792..832b89d 100644 --- a/pkgs/ffigen/test/header_parser_tests/globals_test.dart +++ b/pkgs/ffigen/test/header_parser_tests/globals_test.dart
@@ -62,6 +62,7 @@ } Library expectedLibrary() { + final globalStruc = Struc(name: 'EmptyStruct'); return Library( name: 'Bindings', bindings: [ @@ -70,6 +71,8 @@ Global( type: Type.pointer(Type.nativeType(SupportedNativeType.Int32)), name: 'aGlobalPointer'), + globalStruc, + Global(name: 'globalStruct', type: Type.struct(globalStruc)), ], ); }
diff --git a/pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart b/pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart index e0abce7..9d4c52d 100644 --- a/pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart +++ b/pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart
@@ -5045,13 +5045,13 @@ external int Count; } -class CXVirtualFileOverlayImpl extends ffi.Struct {} +class CXVirtualFileOverlayImpl extends ffi.Opaque {} -class CXModuleMapDescriptorImpl extends ffi.Struct {} +class CXModuleMapDescriptorImpl extends ffi.Opaque {} -class CXTargetInfoImpl extends ffi.Struct {} +class CXTargetInfoImpl extends ffi.Opaque {} -class CXTranslationUnitImpl extends ffi.Struct {} +class CXTranslationUnitImpl extends ffi.Opaque {} /// Provides the contents of a file that has not yet been saved to disk. class CXUnsavedFile extends ffi.Struct { @@ -6333,7 +6333,7 @@ static const int CXTLS_Static = 2; } -class CXCursorSetImpl extends ffi.Struct {} +class CXCursorSetImpl extends ffi.Opaque {} /// Describes the kind of type abstract class CXTypeKind {
diff --git a/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart b/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart index 6abdd48..fa67d48 100644 --- a/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart +++ b/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart
@@ -8984,9 +8984,9 @@ _dart_sqlite3_rtree_query_callback? _sqlite3_rtree_query_callback; } -class sqlite3 extends ffi.Struct {} +class sqlite3 extends ffi.Opaque {} -class sqlite3_file extends ffi.Struct {} +class sqlite3_file extends ffi.Opaque {} class sqlite3_io_methods extends ffi.Struct { @ffi.Int32() @@ -9031,19 +9031,19 @@ external ffi.Pointer<ffi.NativeFunction<_typedefC_19>> xUnfetch; } -class sqlite3_mutex extends ffi.Struct {} +class sqlite3_mutex extends ffi.Opaque {} -class sqlite3_api_routines extends ffi.Struct {} +class sqlite3_api_routines extends ffi.Opaque {} -class sqlite3_vfs extends ffi.Struct {} +class sqlite3_vfs extends ffi.Opaque {} -class sqlite3_mem_methods extends ffi.Struct {} +class sqlite3_mem_methods extends ffi.Opaque {} -class sqlite3_stmt extends ffi.Struct {} +class sqlite3_stmt extends ffi.Opaque {} -class sqlite3_value extends ffi.Struct {} +class sqlite3_value extends ffi.Opaque {} -class sqlite3_context extends ffi.Struct {} +class sqlite3_context extends ffi.Opaque {} /// CAPI3REF: Virtual Table Instance Object /// KEYWORDS: sqlite3_vtab @@ -9061,7 +9061,7 @@ /// prior to assigning a new string to zErrMsg. ^After the error message /// is delivered up to the client application, the string will be automatically /// freed by sqlite3_free() and the zErrMsg field will be zeroed. -class sqlite3_vtab extends ffi.Struct {} +class sqlite3_vtab extends ffi.Opaque {} /// CAPI3REF: Virtual Table Indexing Information /// KEYWORDS: sqlite3_index_info @@ -9163,7 +9163,7 @@ /// It may therefore only be used if /// sqlite3_libversion_number() returns a value greater than or equal to /// 3009000. -class sqlite3_index_info extends ffi.Struct {} +class sqlite3_index_info extends ffi.Opaque {} /// CAPI3REF: Virtual Table Cursor Object /// KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} @@ -9180,7 +9180,7 @@ /// /// This superclass exists in order to define fields of the cursor that /// are common to all implementations. -class sqlite3_vtab_cursor extends ffi.Struct {} +class sqlite3_vtab_cursor extends ffi.Opaque {} /// CAPI3REF: Virtual Table Object /// KEYWORDS: sqlite3_module {virtual table module} @@ -9196,23 +9196,23 @@ /// module or until the [database connection] closes. The content /// of this structure must not change while it is registered with /// any database connection. -class sqlite3_module extends ffi.Struct {} +class sqlite3_module extends ffi.Opaque {} -class sqlite3_blob extends ffi.Struct {} +class sqlite3_blob extends ffi.Opaque {} -class sqlite3_mutex_methods extends ffi.Struct {} +class sqlite3_mutex_methods extends ffi.Opaque {} -class sqlite3_str extends ffi.Struct {} +class sqlite3_str extends ffi.Opaque {} -class sqlite3_pcache extends ffi.Struct {} +class sqlite3_pcache extends ffi.Opaque {} -class sqlite3_pcache_page extends ffi.Struct {} +class sqlite3_pcache_page extends ffi.Opaque {} -class sqlite3_pcache_methods2 extends ffi.Struct {} +class sqlite3_pcache_methods2 extends ffi.Opaque {} -class sqlite3_pcache_methods extends ffi.Struct {} +class sqlite3_pcache_methods extends ffi.Opaque {} -class sqlite3_backup extends ffi.Struct {} +class sqlite3_backup extends ffi.Opaque {} /// CAPI3REF: Database Snapshot /// KEYWORDS: {snapshot} {sqlite3_snapshot} @@ -9610,7 +9610,7 @@ /// A pointer to a structure of the following type is passed as the first /// argument to callbacks registered using rtree_geometry_callback(). -class sqlite3_rtree_geometry extends ffi.Struct {} +class sqlite3_rtree_geometry extends ffi.Opaque {} /// A pointer to a structure of the following type is passed as the /// argument to scored geometry callback registered using @@ -9619,7 +9619,7 @@ /// Note that the first 5 fields of this structure are identical to /// sqlite3_rtree_geometry. This structure is a subclass of /// sqlite3_rtree_geometry. -class sqlite3_rtree_query_info extends ffi.Struct {} +class sqlite3_rtree_query_info extends ffi.Opaque {} /// EXTENSION API FUNCTIONS /// @@ -9830,17 +9830,17 @@ /// /// xPhraseNextColumn() /// See xPhraseFirstColumn above. -class Fts5ExtensionApi extends ffi.Struct {} +class Fts5ExtensionApi extends ffi.Opaque {} -class Fts5Context extends ffi.Struct {} +class Fts5Context extends ffi.Opaque {} -class Fts5PhraseIter extends ffi.Struct {} +class Fts5PhraseIter extends ffi.Opaque {} -class Fts5Tokenizer extends ffi.Struct {} +class Fts5Tokenizer extends ffi.Opaque {} -class fts5_tokenizer extends ffi.Struct {} +class fts5_tokenizer extends ffi.Opaque {} -class fts5_api extends ffi.Struct {} +class fts5_api extends ffi.Opaque {} const String SQLITE_VERSION = '3.32.3';
diff --git a/pkgs/ffigen/test/test_coverage.dart b/pkgs/ffigen/test/test_coverage.dart index ede39f3..9f61cde 100644 --- a/pkgs/ffigen/test/test_coverage.dart +++ b/pkgs/ffigen/test/test_coverage.dart
@@ -2,7 +2,7 @@ // 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 'code_generator_test.dart' as code_generator_test; +import 'code_generator_tests/code_generator_test.dart' as code_generator_test; import 'collision_tests/decl_decl_collision_test.dart' as collision_tests_decl_decl_collision_test; import 'collision_tests/reserved_keyword_collision_test.dart' @@ -19,6 +19,8 @@ as header_parser_tests_function_n_struct_test; import 'header_parser_tests/functions_test.dart' as header_parser_tests_functions_test; +import 'header_parser_tests/globals_test.dart' + as header_parser_tests_globals_test; import 'header_parser_tests/macros_test.dart' as header_parser_tests_macros_test; import 'header_parser_tests/native_func_typedef_test.dart' @@ -43,6 +45,7 @@ collision_tests_reserved_keyword_collision_test.main(); header_parser_tests_dart_handle_test.main(); header_parser_tests_functions_test.main(); + header_parser_tests_globals_test.main(); header_parser_tests_macros_test.main(); header_parser_tests_function_n_struct_test.main(); header_parser_tests_native_func_typedef_test.main();
diff --git a/pkgs/ffigen/test/test_utils.dart b/pkgs/ffigen/test/test_utils.dart index c2d95f0..a967f66 100644 --- a/pkgs/ffigen/test/test_utils.dart +++ b/pkgs/ffigen/test/test_utils.dart
@@ -9,8 +9,6 @@ import 'package:path/path.dart' as path; import 'package:test/test.dart'; -/// Extracts a binding's string from a library. - extension LibraryTestExt on Library { /// Get a [Binding]'s generated string with a given name. String getBindingAsString(String name) {