blob: 89398db6652361c4555abd52b6ab22fcd993549b [file] [log] [blame] [edit]
// Copyright (c) 2019, 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.
//
// Tests the sizes of c types from https://dartbug.com/36140.
//
// SharedObjects=ffi_test_functions
import 'dart:ffi';
import 'dart:io' show Platform;
import 'package:expect/expect.dart';
import 'package:ffi/ffi.dart';
import 'ffi_test_helpers.dart';
void main() {
printSizes();
testSizes();
testIntAssumptions();
testSizeTAssumptions();
testLongAssumptions();
testWCharTAssumptions();
}
class CType {
final int ffiSize;
final int Function(Pointer)? ffiLoad;
final String modifier;
final String type;
final String type2;
CType(
this.ffiSize,
this.type, {
this.type2 = '',
this.modifier = '',
this.ffiLoad,
});
String get cRepresentation => '$modifier $type $type2'.trim();
String get _getSizeName => 'FfiSizeOf_$modifier\_$type\_$type2';
String get _getSignName => 'FfiSignOf_$modifier\_$type\_$type2';
int Function() get sizeFunction => ffiTestFunctions
.lookupFunction<Uint64 Function(), int Function()>(_getSizeName);
int Function() get signFunction => ffiTestFunctions
.lookupFunction<Uint64 Function(), int Function()>(_getSignName);
int get size => sizeFunction();
bool get isSigned => signFunction() != 0;
bool? get ffiIsSigned {
final ffiLoad_ = ffiLoad;
if (ffiLoad_ == null) {
return null;
}
assert(size < 8);
return using((Arena arena) {
final p = arena<Int64>()..value = -1;
return ffiLoad_(p) < 0;
});
}
String toString() => cRepresentation;
}
final char = CType(
sizeOf<Char>(),
'char',
ffiLoad: (Pointer p) => p.cast<Char>().value,
);
final uchar = CType(
sizeOf<UnsignedChar>(),
'char',
modifier: 'unsigned',
ffiLoad: (Pointer p) => p.cast<UnsignedChar>().value,
);
final schar = CType(
sizeOf<SignedChar>(),
'char',
modifier: 'signed',
ffiLoad: (Pointer p) => p.cast<SignedChar>().value,
);
final short = CType(
sizeOf<Short>(),
'short',
ffiLoad: (Pointer p) => p.cast<Short>().value,
);
final ushort = CType(
sizeOf<UnsignedShort>(),
'short',
modifier: 'unsigned',
ffiLoad: (Pointer p) => p.cast<UnsignedShort>().value,
);
final int_ = CType(
sizeOf<Int>(),
'int',
ffiLoad: (Pointer p) => p.cast<Int>().value,
);
final uint = CType(
sizeOf<UnsignedInt>(),
'int',
modifier: 'unsigned',
ffiLoad: (Pointer p) => p.cast<UnsignedInt>().value,
);
final long = CType(sizeOf<Long>(), 'long');
final ulong = CType(sizeOf<UnsignedLong>(), 'long', modifier: 'unsigned');
final longlong = CType(sizeOf<LongLong>(), 'long', type2: 'long');
final ulonglong = CType(
sizeOf<UnsignedLongLong>(),
'long',
type2: 'long',
modifier: 'unsigned',
);
final intptr_t = CType(sizeOf<IntPtr>(), 'intptr_t');
final uintptr_t = CType(sizeOf<UintPtr>(), 'uintptr_t');
final size_t = CType(sizeOf<Size>(), 'size_t');
final wchar_t = CType(
sizeOf<WChar>(),
'wchar_t',
ffiLoad: (Pointer p) => p.cast<WChar>().value,
);
final cTypes = [
char,
uchar,
schar,
short,
ushort,
int_,
uint,
long,
ulong,
longlong,
ulonglong,
intptr_t,
uintptr_t,
size_t,
wchar_t,
];
void printSizes() {
cTypes.forEach((element) {
final cName = element.cRepresentation.padRight(20);
final size = element.size;
final signed = element.isSigned ? 'signed' : 'unsigned';
print('$cName: $size $signed');
});
}
void testSizes() {
cTypes.forEach((element) {
print(element);
Expect.equals(element.size, element.ffiSize);
final ffiIsSigned = element.ffiIsSigned;
if (ffiIsSigned != null) {
Expect.equals(element.isSigned, ffiIsSigned);
}
});
}
void testIntAssumptions() {
Expect.equals(4, int_.size);
Expect.equals(4, uint.size);
}
void testSizeTAssumptions() {
Expect.equals(intptr_t.size, size_t.size);
}
void testLongAssumptions() {
if (Platform.isWindows) {
Expect.equals(4, long.size);
Expect.equals(4, ulong.size);
} else {
Expect.equals(intptr_t.size, long.size);
Expect.equals(intptr_t.size, ulong.size);
}
}
void testWCharTAssumptions() {
final bool isSigned = wchar_t.isSigned;
print('wchar_t isSigned $isSigned');
if (Platform.isWindows) {
Expect.equals(2, wchar_t.size);
if (isSigned) {
Expect.equals(-0x8000, wCharMinValue());
Expect.equals(0x7fff, wCharMaxValue());
} else {
Expect.equals(0, wCharMinValue());
Expect.equals(0xffff, wCharMaxValue());
}
} else {
Expect.equals(4, wchar_t.size);
if (isSigned) {
Expect.equals(-0x80000000, wCharMinValue());
Expect.equals(0x7fffffff, wCharMaxValue());
} else {
Expect.equals(0, wCharMinValue());
Expect.equals(0xffffffff, wCharMaxValue());
}
}
}
int Function() wCharMinValue = ffiTestFunctions
.lookupFunction<Uint64 Function(), int Function()>('WCharMinValue');
int Function() wCharMaxValue = ffiTestFunctions
.lookupFunction<Uint64 Function(), int Function()>('WCharMaxValue');