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