withCopiedBytes<T> method
T
withCopiedBytes<T>(})
Copies part and consumes the owned copy under a temporary native owner.
Use for metadata: a small, long-lived details map must not pin a large
payload. On new runtimes the whole message stays alive through consume,
allowing its other metadata strings to be copied synchronously. Neither
a borrowed view nor the native owner escapes to consume. Its returned
value may retain the Dart copy, but not other borrowed native pointers.
Legacy runtimes require the caller's handle to stay alive throughout.
Implementation
T withCopiedBytes<T>(
int handle,
NativeMessageBytePart part, {
required ffi.Pointer<ffi.Uint8> borrowed,
required int length,
required T Function(Uint8List copy) consume,
}) {
if (messageHandleAbi == NativeMessageHandleAbi.legacy) {
checkedLegacyMessageHandle(handle);
}
if (handle <= 0 || length < 0 || (length > 0 && borrowed == ffi.nullptr)) {
throw ArgumentError('Invalid native message byte view');
}
if (length == 0) return consume(Uint8List(0));
final export = _export;
if (export == null) {
return consume(Uint8List.fromList(borrowed.asTypedList(length)));
}
final output = calloc<_MessageByteView>();
try {
final status = export(handle, part.index, output);
if (status != 0) {
throw StateError('Native message byte export failed ($status)');
}
final view = output.ref;
if (view.owner == ffi.nullptr ||
view.data != borrowed ||
view.length != length) {
throw StateError(
'Native message byte export disagrees with message info',
);
}
return consume(Uint8List.fromList(view.data.asTypedList(view.length)));
} finally {
_free!(output.ref.owner);
calloc.free(output);
}
}