blob: 0b8f4b2e6d46462adc445b10f4de32c1577a9cd8 [file] [log] [blame] [edit]
// Copyright (c) 2023, 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:convert';
import 'dart:io';
import 'package:path/path.dart' as p;
import 'pointer.dart';
import 'type.dart';
import 'unique_namer.dart';
import 'writer.dart';
/// Converts [text] to a dart doc comment(`///`).
///
/// Comment is split on new lines only.
String makeDartDoc(String? text) {
if (text == null) return '';
final s = StringBuffer();
s.write('/// ');
s.writeAll(text.split('\n'), '\n/// ');
s.write('\n');
return s.toString();
}
/// Converts [text] to a dart comment (`//`).
///
/// Comment is split on new lines only.
String makeDoc(String text) {
final s = StringBuffer();
s.write('// ');
s.writeAll(text.split('\n'), '\n// ');
s.write('\n');
return s.toString();
}
String makeNativeAnnotation(
Writer w, {
required String? nativeType,
required String dartName,
required String nativeSymbolName,
bool isLeaf = false,
}) {
final args = <(String, String)>[];
if (dartName != nativeSymbolName) {
args.add(('symbol', "'${UniqueNamer.stringLiteral(nativeSymbolName)}'"));
}
if (isLeaf) {
args.add(('isLeaf', 'true'));
}
final combinedArgs = args.map((e) => '${e.$1}: ${e.$2}').join(', ');
return '@${w.ffiLibraryPrefix}.Native<$nativeType>($combinedArgs)';
}
String makeArrayAnnotation(Writer w, ConstantArray arrayType) {
final dimensions = <int>[];
Type type = arrayType;
while (type is ConstantArray) {
dimensions.add(type.length);
type = type.child;
}
return '@${w.ffiLibraryPrefix}.Array.multi([${dimensions.join(', ')}])';
}
/// 32-bit FNV-1a hash function.
int fnvHash32(String input) {
var hash = 0x811c9dc5;
for (final byte in utf8.encode(input)) {
hash = ((hash ^ byte) * 0x1000193) & 0xFFFFFFFF;
}
return hash;
}
/// The path to the Dart executable.
///
/// This is usually just Platform.resolvedExecutable. But when running flutter
/// tests, the resolvedExecutable will be flutter_tester, and Dart will be in a
/// directory a few levels up from it.
String findDart() {
var path = Platform.resolvedExecutable;
if (p.basenameWithoutExtension(path) == 'dart') return path;
final dartExe = 'dart${p.extension(path)}';
while (path.isNotEmpty) {
path = p.dirname(path);
final dartPath = p.normalize(p.join(path, dartExe));
if (File(dartPath).existsSync()) return dartPath;
}
throw Exception(
"Couldn't find Dart executable near ${Platform.resolvedExecutable}");
}
/// Attempts to parse an absolute path to an ObjC framework header. Returns an
/// importable path if successful, otherwise returns null.
String? parseObjCFrameworkHeader(String path) {
final match = _frameworkHeaderRegex.firstMatch(path);
if (match == null) {
return null;
}
return '${match[1]}/${match[2]}';
}
final _frameworkHeaderRegex = RegExp(
r'.*/Library(?:/.*/|/)Frameworks/([^/]+)\.framework(?:/.*/|/)Headers/(.*)');