blob: ffc1509ea4d160106dc4feced66abd834fbf99fa [file] [log] [blame]
// 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 'package:meta/meta.dart';
import 'binding.dart';
import 'binding_string.dart';
import 'type.dart';
import 'writer.dart';
/// A binding for C function.
///
/// For a C function -
/// ```c
/// int sum(int a, int b);
/// ```
/// The Generated dart code is -
/// ```dart
/// int sum(int a, int b) {
/// return _sum(a, b);
/// }
///
/// final _dart_sum _sum = _dylib.lookupFunction<_c_sum, _dart_sum>('sum');
///
/// typedef _c_sum = ffi.Int32 Function(ffi.Int32 a, ffi.Int32 b);
///
/// typedef _dart_sum = int Function(int a, int b);
/// ```
class Func extends Binding {
final String lookupSymbolName;
final Type returnType;
final List<Parameter> parameters;
/// [lookupSymbolName], if not provided, takes the value of [name].
Func({
@required String name,
String lookupSymbolName,
String dartDoc,
@required this.returnType,
List<Parameter> parameters,
}) : parameters = parameters ?? [],
lookupSymbolName = lookupSymbolName ?? name,
super(name: name, dartDoc: dartDoc) {
for (var i = 0; i < this.parameters.length; i++) {
if (this.parameters[i].name == null ||
this.parameters[i].name.trim() == '') {
this.parameters[i].name = 'arg$i';
}
}
}
@override
BindingString toBindingString(Writer w) {
final s = StringBuffer();
final enclosingFuncName = name;
// Ensure name conflicts are resolved for typedefs generated.
final funcVarName = w.uniqueNamer.makeUnique('_$name');
final typedefC = w.uniqueNamer.makeUnique('_c_$name');
final typedefDart = w.uniqueNamer.makeUnique('_dart_$name');
// Write typedef's required by parameters and resolve name conflicts.
for (final p in parameters) {
final base = p.type.getBaseType();
if (base.broadType == BroadType.NativeFunction) {
base.nativeFunc.name =
w.uniqueNamer.makeUnique(base.nativeFunc.name);
s.write(base.nativeFunc.toTypedefString(w));
}
}
if (dartDoc != null) {
s.write('/// ');
s.writeAll(dartDoc.split('\n'), '\n/// ');
s.write('\n');
}
// Write enclosing function.
s.write('${returnType.getDartType(w)} $enclosingFuncName(\n');
for (final p in parameters) {
s.write(' ${p.type.getDartType(w)} ${p.name},\n');
}
s.write(') {\n');
s.write(' return $funcVarName(\n');
for (final p in parameters) {
s.write(' ${p.name},\n');
}
s.write(' );\n');
s.write('}\n\n');
// Write function with dylib lookup.
s.write(
"final $typedefDart $funcVarName = ${w.dylibIdentifier}.lookupFunction<$typedefC,$typedefDart>('$lookupSymbolName');\n\n");
// Write typdef for C.
s.write('typedef $typedefC = ${returnType.getCType(w)} Function(\n');
for (final p in parameters) {
s.write(' ${p.type.getCType(w)} ${p.name},\n');
}
s.write(');\n\n');
// Write typdef for dart.
s.write('typedef $typedefDart = ${returnType.getDartType(w)} Function(\n');
for (final p in parameters) {
s.write(' ${p.type.getDartType(w)} ${p.name},\n');
}
s.write(');\n\n');
return BindingString(type: BindingStringType.func, string: s.toString());
}
}
/// Represents a Function's parameter.
class Parameter {
String name;
final Type type;
Parameter({this.name, @required this.type});
}