Skip to content
This repository has been archived by the owner on Jan 28, 2024. It is now read-only.

Typedefs for Dart types #625

Merged
merged 24 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/c_json/cjson_generated_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,7 @@ final class cJSON_Hooks extends ffi.Struct {
}

typedef cJSON_bool = ffi.Int;
typedef DartcJSON_bool = int;

const int CJSON_VERSION_MAJOR = 1;

Expand Down
21 changes: 15 additions & 6 deletions example/libclang-example/generated_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9748,8 +9748,10 @@ typedef DartClang_getIBOutletCollectionType = CXType Function(CXCursor arg0);
/// The visitor should return one of the \c CXChildVisitResult values
/// to direct clang_visitCursorChildren().
typedef CXCursorVisitor
= ffi.Pointer<ffi.NativeFunction<CXCursorVisitor_function>>;
typedef CXCursorVisitor_function = ffi.Int32 Function(
= ffi.Pointer<ffi.NativeFunction<CXCursorVisitorFunction>>;
typedef CXCursorVisitorFunction = ffi.Int32 Function(
CXCursor cursor, CXCursor parent, CXClientData client_data);
typedef DartCXCursorVisitorFunction = int Function(
CXCursor cursor, CXCursor parent, CXClientData client_data);

/// Describes how the traversal of the children of a particular
Expand Down Expand Up @@ -10426,12 +10428,17 @@ typedef DartClang_toggleCrashRecovery = void Function(int isEnabled);
/// array is sorted in order of immediate inclusion. For example,
/// the first element refers to the location that included 'included_file'.
typedef CXInclusionVisitor
= ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor_function>>;
typedef CXInclusionVisitor_function = ffi.Void Function(
= ffi.Pointer<ffi.NativeFunction<CXInclusionVisitorFunction>>;
typedef CXInclusionVisitorFunction = ffi.Void Function(
CXFile included_file,
ffi.Pointer<CXSourceLocation> inclusion_stack,
ffi.UnsignedInt include_len,
CXClientData client_data);
typedef DartCXInclusionVisitorFunction = void Function(
CXFile included_file,
ffi.Pointer<CXSourceLocation> inclusion_stack,
int include_len,
CXClientData client_data);
typedef NativeClang_getInclusions = ffi.Void Function(
CXTranslationUnit tu, CXInclusionVisitor visitor, CXClientData client_data);
typedef DartClang_getInclusions = void Function(
Expand Down Expand Up @@ -11104,8 +11111,10 @@ typedef DartClang_indexLoc_getCXSourceLocation = CXSourceLocation Function(
/// The visitor should return one of the \c CXVisitorResult values
/// to direct \c clang_Type_visitFields.
typedef CXFieldVisitor
= ffi.Pointer<ffi.NativeFunction<CXFieldVisitor_function>>;
typedef CXFieldVisitor_function = ffi.Int32 Function(
= ffi.Pointer<ffi.NativeFunction<CXFieldVisitorFunction>>;
typedef CXFieldVisitorFunction = ffi.Int32 Function(
CXCursor C, CXClientData client_data);
typedef DartCXFieldVisitorFunction = int Function(
CXCursor C, CXClientData client_data);
typedef NativeClang_Type_visitFields = ffi.UnsignedInt Function(
CXType T, CXFieldVisitor visitor, CXClientData client_data);
Expand Down
27 changes: 9 additions & 18 deletions lib/src/code_generator/func.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ class Func extends LookUpBinding {
late final String funcPointerName;

/// Contains typealias for function type if [exposeFunctionTypedefs] is true.
Typealias? _exposedCFunctionTypealias;
Typealias? _exposedDartFunctionTypealias;
Typealias? _exposedFunctionTypealias;

/// [originalName] is looked up in dynamic library, if not
/// provided, takes the value of [name].
Expand Down Expand Up @@ -85,15 +84,10 @@ class Func extends LookUpBinding {
// Get function name with first letter in upper case.
final upperCaseName = name[0].toUpperCase() + name.substring(1);
if (exposeFunctionTypedefs) {
_exposedCFunctionTypealias = Typealias(
name: 'Native$upperCaseName',
_exposedFunctionTypealias = Typealias(
name: upperCaseName,
type: functionType,
isInternal: true,
);
_exposedDartFunctionTypealias = Typealias(
name: 'Dart$upperCaseName',
type: functionType,
useDartType: true,
genFfiDartType: true,
isInternal: true,
);
}
Expand All @@ -115,12 +109,10 @@ class Func extends LookUpBinding {
p.name = paramNamer.makeUnique(p.name);
}

final cType = exposeFunctionTypedefs
? _exposedCFunctionTypealias!.name
: functionType.getCType(w, writeArgumentNames: false);
final dartType = exposeFunctionTypedefs
? _exposedDartFunctionTypealias!.name
: functionType.getFfiDartType(w, writeArgumentNames: false);
final cType = _exposedFunctionTypealias?.getCType(w) ??
functionType.getCType(w, writeArgumentNames: false);
final dartType = _exposedFunctionTypealias?.getFfiDartType(w) ??
functionType.getFfiDartType(w, writeArgumentNames: false);

if (ffiNativeConfig.enabled) {
final assetString = ffiNativeConfig.asset != null
Expand Down Expand Up @@ -180,8 +172,7 @@ class Func extends LookUpBinding {
dependencies.add(this);
functionType.addDependencies(dependencies);
if (exposeFunctionTypedefs) {
_exposedCFunctionTypealias!.addDependencies(dependencies);
_exposedDartFunctionTypealias!.addDependencies(dependencies);
_exposedFunctionTypealias!.addDependencies(dependencies);
}
}
}
Expand Down
52 changes: 29 additions & 23 deletions lib/src/code_generator/objc_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,11 @@ class $name extends ${superType?.name ?? '_ObjCWrapper'} {
}
}

static bool _isInstanceType(Type type) =>
type is ObjCInstanceType ||
(type is ObjCNullable && type.child is ObjCInstanceType);
static bool _isInstanceType(Type type) {
if (type is ObjCInstanceType) return true;
final baseType = type.typealiasType;
return baseType is ObjCNullable && baseType.child is ObjCInstanceType;
}

void addMethod(ObjCMethod method) {
final oldMethod = methods[method.originalName];
Expand Down Expand Up @@ -400,27 +402,29 @@ class $name extends ${superType?.name ?? '_ObjCWrapper'} {
// passed to native as Pointer<ObjCObject>, but the user sees the Dart wrapper
// class. These methods need to be kept in sync.
bool _needsConverting(Type type) =>
type is ObjCInterface ||
type is ObjCBlock ||
type is ObjCObjectPointer ||
type is ObjCInstanceType ||
type is ObjCNullable;
type.typealiasType is ObjCInterface ||
type.typealiasType is ObjCBlock ||
type.typealiasType is ObjCObjectPointer ||
type.typealiasType is ObjCNullable;

String _getConvertedType(Type type, Writer w, String enclosingClass) {
if (type is ObjCInstanceType) return enclosingClass;
if (type is ObjCNullable && type.child is ObjCInstanceType) {
final baseType = type.typealiasType;
if (baseType is ObjCNullable && baseType.child is ObjCInstanceType) {
return '$enclosingClass?';
}
return type.getDartType(w);
}

String _doArgConversion(ObjCMethodParam arg) {
if (arg.type is ObjCNullable) {
final baseType = arg.type.typealiasType;
if (baseType is ObjCNullable) {
return '${arg.name}?._id ?? ffi.nullptr';
} else if (arg.type is ObjCInterface ||
arg.type is ObjCObjectPointer ||
arg.type is ObjCInstanceType ||
arg.type is ObjCBlock) {
} else if (arg.type is ObjCInstanceType ||
baseType is ObjCInterface ||
baseType is ObjCObjectPointer ||
baseType is ObjCBlock) {
return '${arg.name}._id';
}
return arg.name;
Expand All @@ -429,22 +433,24 @@ class $name extends ${superType?.name ?? '_ObjCWrapper'} {
String _doReturnConversion(Type type, String value, String enclosingClass,
String library, bool isOwnedReturn) {
var prefix = '';
if (type is ObjCNullable) {
var baseType = type.typealiasType;
if (baseType is ObjCNullable) {
prefix = '$value.address == 0 ? null : ';
type = type.child;
type = baseType.child;
baseType = type.typealiasType;
}
final ownerFlags = 'retain: ${!isOwnedReturn}, release: true';
if (type is ObjCInterface) {
return '$prefix${type.name}._($value, $library, $ownerFlags)';
if (type is ObjCInstanceType) {
return '$prefix$enclosingClass._($value, $library, $ownerFlags)';
}
if (type is ObjCBlock) {
return '$prefix${type.name}._($value, $library)';
if (baseType is ObjCInterface) {
return '$prefix${baseType.name}._($value, $library, $ownerFlags)';
}
if (type is ObjCObjectPointer) {
return '${prefix}NSObject._($value, $library, $ownerFlags)';
if (baseType is ObjCBlock) {
return '$prefix${baseType.name}._($value, $library)';
}
if (type is ObjCInstanceType) {
return '$prefix$enclosingClass._($value, $library, $ownerFlags)';
if (baseType is ObjCObjectPointer) {
return '${prefix}NSObject._($value, $library, $ownerFlags)';
}
return prefix + value;
}
Expand Down
64 changes: 40 additions & 24 deletions lib/src/code_generator/typealias.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,28 @@ import 'writer.dart';
/// ```
class Typealias extends BindingType {
final Type type;
final bool _useDartType;
String? _ffiDartAliasName;
String? _dartAliasName;

/// Creates a Typealias.
///
/// If [genFfiDartType] is true, a binding is generated for the Ffi Dart type
/// in addition to the C type. See [Type.getFfiDartType].
factory Typealias({
String? usr,
String? originalName,
String? dartDoc,
required String name,
required Type type,

/// If true, the binding string uses Dart type instead of C type.
///
/// E.g if C type is ffi.Void func(ffi.Int32), Dart type is void func(int).
bool useDartType = false,
bool genFfiDartType = false,
bool isInternal = false,
}) {
final funcType = _getFunctionTypeFromPointer(type);
if (funcType != null) {
type = PointerType(NativeFunc(Typealias._(
name: '${name}_function',
name: '${name}Function',
type: funcType,
useDartType: useDartType,
genFfiDartType: genFfiDartType,
isInternal: isInternal,
)));
}
Expand All @@ -49,7 +50,7 @@ class Typealias extends BindingType {
dartDoc: dartDoc,
name: name,
type: type,
useDartType: useDartType,
genFfiDartType: genFfiDartType,
isInternal: isInternal,
);
}
Expand All @@ -59,7 +60,7 @@ class Typealias extends BindingType {
dartDoc: dartDoc,
name: name,
type: type,
useDartType: useDartType,
genFfiDartType: genFfiDartType,
isInternal: isInternal,
);
}
Expand All @@ -70,12 +71,16 @@ class Typealias extends BindingType {
String? dartDoc,
required String name,
required this.type,
bool useDartType = false,
bool genFfiDartType = false,
bool isInternal = false,
}) : _useDartType = useDartType,
}) : _ffiDartAliasName = genFfiDartType ? 'Dart$name' : null,
_dartAliasName =
(!genFfiDartType && type is! Typealias && !type.sameDartAndCType)
? 'Dart$name'
: null,
super(
usr: usr,
name: name,
name: genFfiDartType ? 'Native$name' : name,
dartDoc: dartDoc,
originalName: originalName,
isInternal: isInternal,
Expand All @@ -98,12 +103,24 @@ class Typealias extends BindingType {

@override
BindingString toBindingString(Writer w) {
if (_ffiDartAliasName != null) {
_ffiDartAliasName = w.topLevelUniqueNamer.makeUnique(_ffiDartAliasName!);
}
if (_dartAliasName != null) {
_dartAliasName = w.topLevelUniqueNamer.makeUnique(_dartAliasName!);
}

final sb = StringBuffer();
if (dartDoc != null) {
sb.write(makeDartDoc(dartDoc!));
}
sb.write('typedef $name = ');
sb.write('${_useDartType ? type.getFfiDartType(w) : type.getCType(w)};\n');
sb.write('typedef $name = ${type.getCType(w)};\n');
if (_ffiDartAliasName != null) {
sb.write('typedef $_ffiDartAliasName = ${type.getFfiDartType(w)};\n');
}
if (_dartAliasName != null) {
sb.write('typedef $_dartAliasName = ${type.getDartType(w)};\n');
}
return BindingString(
type: BindingStringType.typeDef, string: sb.toString());
}
Expand All @@ -119,15 +136,18 @@ class Typealias extends BindingType {

@override
String getFfiDartType(Writer w) {
// Typealias cannot be used by name in Dart types unless both the C and Dart
// type of the underlying types are same.
if (type.sameFfiDartAndCType) {
if (_ffiDartAliasName != null) {
return _ffiDartAliasName!;
} else if (type.sameFfiDartAndCType) {
return name;
} else {
return type.getFfiDartType(w);
}
}

@override
String getDartType(Writer w) => _dartAliasName ?? type.getDartType(w);

@override
bool get sameFfiDartAndCType => type.sameFfiDartAndCType;

Expand All @@ -154,19 +174,15 @@ class ObjCInstanceType extends Typealias {
String? dartDoc,
required String name,
required Type type,

/// If true, the binding string uses Dart type instead of C type.
///
/// E.g if C type is ffi.Void func(ffi.Int32), Dart type is void func(int).
bool useDartType = false,
bool genFfiDartType = false,
bool isInternal = false,
}) : super._(
usr: usr,
originalName: originalName,
dartDoc: dartDoc,
name: name,
type: type,
useDartType: useDartType,
genFfiDartType: genFfiDartType,
isInternal: isInternal,
);
}
Loading