Open ethanblake4 opened 4 years ago
We do not have support for that yet, but it's a good suggestion.
The current workaround would be to write a wrapper in Dart that does the bit-masking:
const _boldMask = 0x1;
const _underlineOffset = 1;
const _underlineMask = 0x6;
class ScreenCellAttrs extends Struct {
@Int16()
int bits;
int get bold => bits & _boldMask;
void set bold(int value) {
bits = (bits & ~_boldMask) | (value & _boldMask);
}
int get underline => (bits & _underlineMask) >> _underlineOffset;
void set underline(int value) {
bits = (bits & ~_underlineMask) |
((value << _underlineOffset) & _underlineMask);
}
}
main() {
final p = allocate<ScreenCellAttrs>();
p.ref.bold = 1;
p.ref.underline = 2;
print(p.ref.bold);
print(p.ref.underline);
free(p);
}
Thanks!
For anyone else who comes across this issue, here's a simple mixin I made to make it easier:
mixin Bitfield16 on Struct {
@Int16()
int bits;
int extract(int offset, int size) => (bits & (((math.pow(2, size) as int) - 1) << offset)) >> offset;
}
I've added a full example in the commit above. It uses bit shifts instead of math functions, so it should be a bit faster.
We could make writing these bit fields by hand a bit more ergonomic by exposing the int extension, and a predefined set of fixed-size bit field mixins in package:ffi
.
/// Extension to use a 64-bit integer as bit field.
extension IntBitField on int {
static int _bitMask(int offset, int lenght) => ((1 << lenght) - 1) << offset;
/// Read `length` bits at `offset`.
///
/// Truncates everything.
int getBits(int offset, int length) {
final mask = _bitMask(offset, length);
return (this & mask) >> offset;
}
/// Returns a new integer value in which `length` bits are overwritten at
/// `offset`.
///
/// Truncates everything.
int setBits(int offset, int length, int value) {
final mask = _bitMask(offset, length);
return (this & ~mask) | ((value << offset) & mask);
}
}
mixin BitField16 on Struct {
@Int16()
int bits;
int getBits(int offset, int length) => bits.getBits(offset, length);
void setBits(int offset, int length, int value) {
bits = bits.setBits(offset, length, value);
}
}
In the end we probably would like to have support for bitfields in a .h
-to-.dart
bindings generator as the most ergonomic option (#35843).
From that perspective, we do not need to add support for bit fields in dart:ffi
directly.
The landed sample is a decent solution. If anyone has problems using that solution, please reopen this issue.
This needs to be supported in the VM for fully platform agnostic bitfield definitions, see https://github.com/dart-lang/native/issues/406.
How do we support bit fields in dart:ffi? Something like:
what would be the correct way to represent this from within Dart?