acquire method

Future<ChatImageDecodeReservation> acquire({
  1. required int decodedBytes,
  2. required ChatImageDecodeCancellation cancellation,
})

Implementation

Future<ChatImageDecodeReservation> acquire({
  required int decodedBytes,
  required ChatImageDecodeCancellation cancellation,
}) {
  final bool isCancelled;
  try {
    isCancelled = cancellation.isCancelled;
  } catch (error, stackTrace) {
    return Future<ChatImageDecodeReservation>.error(error, stackTrace);
  }
  if (isCancelled) {
    return Future<ChatImageDecodeReservation>.error(
      const ChatImageDecodeCancelled(),
    );
  }
  if (decodedBytes < 0) {
    return Future<ChatImageDecodeReservation>.error(
      RangeError.range(
        decodedBytes,
        0,
        _budget.maxEmbeddedMediaBytes,
        'decodedBytes',
      ),
    );
  }
  if (decodedBytes > _budget.maxEmbeddedMediaBytes) {
    return Future<ChatImageDecodeReservation>.error(
      ChatInputLimitExceeded(
        resource: 'ACP image decoded bytes',
        limit: _budget.maxEmbeddedMediaBytes,
        observedAtLeast: _budget.maxEmbeddedMediaBytes + 1,
      ),
    );
  }

  final previewPixels = _budget.maxImagePreviewPixels;
  final reservedBytes = decodedBytes + previewPixels * 4;
  if (previewPixels >
      _budget.maxImagePreviewPixelsGlobal - _reservedPreviewPixels) {
    return Future<ChatImageDecodeReservation>.error(
      ChatInputLimitExceeded(
        resource: 'ACP image preview pixels',
        limit: _budget.maxImagePreviewPixelsGlobal,
        observedAtLeast: _budget.maxImagePreviewPixelsGlobal + 1,
      ),
    );
  }
  if (reservedBytes > _budget.maxImageDecodeBytesGlobal - _reservedBytes) {
    return Future<ChatImageDecodeReservation>.error(
      ChatInputLimitExceeded(
        resource: 'ACP image decode bytes',
        limit: _budget.maxImageDecodeBytesGlobal,
        observedAtLeast: _budget.maxImageDecodeBytesGlobal + 1,
      ),
    );
  }

  _reservedPreviewPixels += previewPixels;
  _reservedBytes += reservedBytes;

  if (_activeDecodes < _budget.maxConcurrentImageDecodes) {
    _activeDecodes += 1;
    return Future<ChatImageDecodeReservation>.value(
      _ChatImageDecodeReservation(
        this,
        decodedBytes,
        previewPixels,
        reservedBytes,
      ),
    );
  }

  final waiter = _ChatImageDecodeWaiter(
    decodedBytes: decodedBytes,
    previewPixels: previewPixels,
    reservedBytes: reservedBytes,
    cancellation: cancellation,
  );
  _waiters.add(waiter);
  late void Function() cancelListener;
  cancelListener = () => _cancelWaiter(waiter);
  waiter.cancelListener = cancelListener;
  try {
    cancellation.addListener(cancelListener);
  } catch (error, stackTrace) {
    waiter.registrationInProgress = false;
    if (waiter.waiting) {
      waiter.waiting = false;
      waiter.unlink();
      _releaseInstalledCapacity(
        previewPixels: waiter.previewPixels,
        reservedBytes: waiter.reservedBytes,
      );
    }
    final removeError = _removeWaiterListener(waiter);
    _grantWaiters();
    if (removeError != null) {
      _reportChatImageDecodeCallbackError(
        removeError.error,
        removeError.stackTrace,
      );
    }
    return Future<ChatImageDecodeReservation>.error(error, stackTrace);
  }

  waiter.registrationInProgress = false;
  final completer = Completer<ChatImageDecodeReservation>();
  waiter.completer = completer;
  if (waiter.cancelledDuringRegistration) {
    completer.completeError(const ChatImageDecodeCancelled());
  } else {
    _grantWaiters();
  }
  return completer.future;
}