Files
cherrypick/benchmark_di/lib/di_adapters/riverpod_adapter.dart
Sergey Penkovsky 56bdb3946e refactor: full generic DIAdapter workflow & universalRegistration abstraction
- Made UniversalChainBenchmark and UniversalChainAsyncBenchmark fully generic with strong typing for DIAdapter<TContainer>
- Moved all universalRegistration logic inside adapters; removed global function and typedef
- Replaced dynamic/object-based registration with type-safe generic contracts end-to-end
- Updated CLI and usage: all DI and scenarios are invoked via type-safe generics
- Fixed all analysis errors, Riverpod async/future usages, and imports for full Dart 3 compatibility
- All benchmarks fully pass for Cherrypick, GetIt, and Riverpod adapters
2025-08-07 14:11:29 +03:00

139 lines
5.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:benchmark_di/scenarios/universal_chain_module.dart';
import 'package:benchmark_di/scenarios/universal_service.dart';
import 'package:riverpod/riverpod.dart' as rp;
import 'di_adapter.dart';
/// Унифицированный DIAdapter для Riverpod с поддержкой scopes и строгой типизацией.
class RiverpodAdapter extends DIAdapter<Map<String, rp.ProviderBase<Object?>>> {
rp.ProviderContainer? _container;
final Map<String, rp.ProviderBase<Object?>> _namedProviders;
final rp.ProviderContainer? _parent;
final bool _isSubScope;
RiverpodAdapter({
rp.ProviderContainer? container,
Map<String, rp.ProviderBase<Object?>>? providers,
rp.ProviderContainer? parent,
bool isSubScope = false,
}) : _container = container,
_namedProviders = providers ?? <String, rp.ProviderBase<Object?>>{},
_parent = parent,
_isSubScope = isSubScope;
@override
void setupDependencies(void Function(Map<String, rp.ProviderBase<Object?>> container) registration) {
_container ??= _parent == null
? rp.ProviderContainer()
: rp.ProviderContainer(parent: _parent);
registration(_namedProviders);
}
@override
T resolve<T extends Object>({String? named}) {
final key = named ?? T.toString();
final provider = _namedProviders[key];
if (provider == null) {
throw Exception('Provider not found for $key');
}
return _container!.read(provider) as T;
}
@override
Future<T> resolveAsync<T extends Object>({String? named}) async {
final key = named ?? T.toString();
final provider = _namedProviders[key];
if (provider == null) {
throw Exception('Provider not found for $key');
}
// Если это FutureProvider — используем .future
if (provider.runtimeType.toString().contains('FutureProvider')) {
return await _container!.read((provider as dynamic).future) as T;
}
return resolve<T>(named: named);
}
@override
void teardown() {
_container?.dispose();
_container = null;
_namedProviders.clear();
}
@override
RiverpodAdapter openSubScope(String name) {
final newContainer = rp.ProviderContainer(parent: _container);
return RiverpodAdapter(
container: newContainer,
providers: Map.of(_namedProviders),
parent: _container,
isSubScope: true,
);
}
@override
Future<void> waitForAsyncReady() async {
// Riverpod синхронный по умолчанию.
return;
}
@override
Registration<Map<String, rp.ProviderBase<Object?>>> universalRegistration<S extends Enum>({
required S scenario,
required int chainCount,
required int nestingDepth,
required UniversalBindingMode bindingMode,
}) {
if (scenario is UniversalScenario) {
return (providers) {
switch (scenario) {
case UniversalScenario.register:
providers['UniversalService'] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(value: 'reg', dependency: null));
break;
case UniversalScenario.named:
providers['impl1'] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(value: 'impl1'));
providers['impl2'] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(value: 'impl2'));
break;
case UniversalScenario.chain:
for (int chain = 1; chain <= chainCount; chain++) {
for (int level = 1; level <= nestingDepth; level++) {
final prevDepName = '${chain}_${level - 1}';
final depName = '${chain}_$level';
providers[depName] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(
value: depName,
dependency: level > 1 ? ref.watch(providers[prevDepName] as rp.ProviderBase<UniversalService>) : null,
));
}
}
final depName = '${chainCount}_$nestingDepth';
providers['UniversalService'] = rp.Provider<UniversalService>((ref) => ref.watch(providers[depName] as rp.ProviderBase<UniversalService>));
break;
case UniversalScenario.override:
// handled at benchmark level
break;
case UniversalScenario.asyncChain:
for (int chain = 1; chain <= chainCount; chain++) {
for (int level = 1; level <= nestingDepth; level++) {
final prevDepName = '${chain}_${level - 1}';
final depName = '${chain}_$level';
providers[depName] = rp.FutureProvider<UniversalService>((ref) async {
return UniversalServiceImpl(
value: depName,
dependency: level > 1
? await ref.watch((providers[prevDepName] as rp.FutureProvider<UniversalService>).future) as UniversalService?
: null,
);
});
}
}
final depName = '${chainCount}_$nestingDepth';
providers['UniversalService'] = rp.FutureProvider<UniversalService>((ref) async {
return await ref.watch((providers[depName] as rp.FutureProvider<UniversalService>).future);
});
break;
}
};
}
throw UnsupportedError('Scenario $scenario not supported by RiverpodAdapter');
}
}