decodeFramesIntoBorrowed method

Future<void> decodeFramesIntoBorrowed(
  1. BorrowedBytesCodec codec,
  2. void onFrame(
    1. FrameBorrowedView frame
    ), {
  3. int capacity = 64 * 1024,
  4. bool allowTrailingBytesAtEof = false,
  5. bool cancelOnError = false,
})

Decode frames and deliver them to onFrame as a short-lived FrameBorrowedView.

This is an opt-in, extremely high-throughput integration point: it avoids allocating a fresh Uint8List per frame when the codec can expose bytes directly from the ring buffer.

NOTE: borrowed views are only valid during the callback. If you need to retain bytes, call FrameBorrowedView.toOwnedBytes.

The library fails fast with a StateError if you use the FrameBorrowedView object after the callback returns.

Note: if you store Uint8List views derived from the frame (e.g. frame.first), that retention generally cannot be detected and may observe mutated bytes later.

Implementation

Future<void> decodeFramesIntoBorrowed(
  BorrowedBytesCodec codec,
  void Function(FrameBorrowedView frame) onFrame, {
  int capacity = 64 * 1024,
  bool allowTrailingBytesAtEof = false,
  bool cancelOnError = false,
}) {
  final completer = Completer<void>();
  final framer = FramerBorrowedBytes(
    codec,
    capacity: capacity,
  );

  StreamSubscription<List<int>>? sub;

  void finishError(Object error, [StackTrace? st]) {
    if (completer.isCompleted) return;
    completer.completeError(error, st);
    sub?.cancel();
  }

  sub = listen(
    (chunk) {
      if (completer.isCompleted) return;
      try {
        framer.add(chunk, onFrame);
      } catch (e, st) {
        finishError(e, st);
      }
    },
    onError: (Object e, StackTrace st) {
      finishError(e, st);
    },
    onDone: () {
      if (completer.isCompleted) return;
      try {
        framer.close(
          onFrame,
          allowTrailingBytesAtEof: allowTrailingBytesAtEof,
        );
        completer.complete();
      } catch (e, st) {
        finishError(e, st);
      }
    },
    cancelOnError: cancelOnError,
  );

  return completer.future;
}