initializeFfiRuntime<T> function

Future<({PreferredBackend activeBackend, T client})> initializeFfiRuntime<T>({
  1. required PreferredBackend? preferredBackend,
  2. required String logTag,
  3. required T createClient(),
  4. required Future<void> initializeClient(
    1. T client,
    2. PreferredBackend backend
    ),
  5. required void shutdownClient(
    1. T client
    ),
})

Implementation

Future<({T client, PreferredBackend activeBackend})> initializeFfiRuntime<T>({
  required PreferredBackend? preferredBackend,
  required String logTag,
  required T Function() createClient,
  required Future<void> Function(T client, PreferredBackend backend)
      initializeClient,
  required void Function(T client) shutdownClient,
}) async {
  final attempts = <BackendInitAttemptFailure>[];
  final backends = ffiBackendFallbackOrder(preferredBackend);

  if (backends.isEmpty) {
    throw StateError('No FFI backend candidates are available.');
  }

  for (final backend in backends) {
    final client = createClient();
    try {
      await initializeClient(client, backend);
      return (client: client, activeBackend: backend);
    } on Exception catch (error, stackTrace) {
      attempts.add(
        BackendInitAttemptFailure(
          backend: backend,
          error: error,
          stackTrace: stackTrace,
        ),
      );
      shutdownClient(client);
      developer.log(
        '$logTag ${ffiBackendWireName(backend)} backend failed: $error',
        name: 'flutter_gemma',
        level: 900,
        error: error,
        stackTrace: stackTrace,
      );
    }
  }

  if (attempts.isEmpty) {
    throw StateError('No FFI backend candidates were attempted.');
  }

  final exception = BackendInitException(attempts: attempts);
  Error.throwWithStackTrace(exception, exception.lastAttempt.stackTrace);
}