diff --git a/benchmark_di/lib/cli/benchmark_cli.dart b/benchmark_di/lib/cli/benchmark_cli.dart index 6d81137..ba0be2a 100644 --- a/benchmark_di/lib/cli/benchmark_cli.dart +++ b/benchmark_di/lib/cli/benchmark_cli.dart @@ -1,6 +1,8 @@ import 'dart:math'; import 'package:benchmark_di/cli/report/markdown_report.dart'; +import 'package:benchmark_di/di_adapters/yx_scope_adapter.dart'; +import 'package:benchmark_di/di_adapters/yx_scope_universal_container.dart'; import 'package:benchmark_di/scenarios/universal_scenario.dart'; import 'package:cherrypick/cherrypick.dart'; import 'package:get_it/get_it.dart'; @@ -122,6 +124,34 @@ class BenchmarkCliRunner { repeats: config.repeats, ); } + } else if (config.di == 'yx_scope') { + final di = YxScopeAdapter(); + if (scenario == UniversalScenario.asyncChain) { + final benchAsync = UniversalChainAsyncBenchmark( + di, + chainCount: c, + nestingDepth: d, + mode: mode, + ); + benchResult = await BenchmarkRunner.runAsync( + benchmark: benchAsync, + warmups: config.warmups, + repeats: config.repeats, + ); + } else { + final benchSync = UniversalChainBenchmark( + di, + chainCount: c, + nestingDepth: d, + mode: mode, + scenario: scenario, + ); + benchResult = await BenchmarkRunner.runSync( + benchmark: benchSync, + warmups: config.warmups, + repeats: config.repeats, + ); + } } else { final di = CherrypickDIAdapter(); if (scenario == UniversalScenario.asyncChain) { diff --git a/benchmark_di/lib/di_adapters/yx_scope_adapter.dart b/benchmark_di/lib/di_adapters/yx_scope_adapter.dart new file mode 100644 index 0000000..ad0e936 --- /dev/null +++ b/benchmark_di/lib/di_adapters/yx_scope_adapter.dart @@ -0,0 +1,126 @@ +// ignore_for_file: invalid_use_of_protected_member + +import 'package:benchmark_di/di_adapters/di_adapter.dart'; +import 'package:benchmark_di/scenarios/universal_binding_mode.dart'; +import 'package:benchmark_di/scenarios/universal_scenario.dart'; +import 'package:benchmark_di/scenarios/universal_service.dart'; +import 'package:benchmark_di/di_adapters/yx_scope_universal_container.dart'; + +/// DIAdapter для yx_scope UniversalYxScopeContainer +class YxScopeAdapter extends DIAdapter { + late UniversalYxScopeContainer _scope; + + @override + void setupDependencies(void Function(UniversalYxScopeContainer container) registration) { + _scope = UniversalYxScopeContainer(); + registration(_scope); + } + + @override + T resolve({String? named}) { + return _scope.depFor(name: named).get; + } + + @override + Future resolveAsync({String? named}) async { + return resolve(named: named); + } + + @override + void teardown() { + // У yx_scope нет явного dispose на ScopeContainer, но можно добавить очистку Map/Deps если потребуется + // Ничего не делаем + } + + @override + YxScopeAdapter openSubScope(String name) { + // Для простоты всегда возвращаем новый контейнер, сабскоупы не реализованы явно + return YxScopeAdapter(); + } + + @override + Future waitForAsyncReady() async { + // Все зависимости синхронны + return; + } + + @override + Registration universalRegistration({ + required S scenario, + required int chainCount, + required int nestingDepth, + required UniversalBindingMode bindingMode, + }) { + if (scenario is UniversalScenario) { + return (scope) { + switch (scenario) { + 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'; + final dep = scope.dep( + () => UniversalServiceImpl( + value: depName, + dependency: level > 1 + ? scope.depFor(name: prevDepName).get + : null, + ), + name: depName, + ); + scope.register(dep, name: depName); + } + } + break; + case UniversalScenario.register: + final dep = scope.dep( + () => UniversalServiceImpl(value: 'reg', dependency: null), + ); + scope.register(dep); + break; + case UniversalScenario.named: + final dep1 = scope.dep( + () => UniversalServiceImpl(value: 'impl1'), + name: 'impl1', + ); + final dep2 = scope.dep( + () => UniversalServiceImpl(value: 'impl2'), + name: 'impl2', + ); + scope.register(dep1, name: 'impl1'); + scope.register(dep2, name: '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'; + final dep = scope.dep( + () => UniversalServiceImpl( + value: depName, + dependency: level > 1 + ? scope.depFor(name: prevDepName).get + : null, + ), + name: depName, + ); + scope.register(dep, name: depName); + } + } + break; + case UniversalScenario.override: + // handled at benchmark level + break; + } + if (scenario == UniversalScenario.chain || scenario == UniversalScenario.override) { + final depName = '${chainCount}_$nestingDepth'; + final lastDep = scope.dep( + () => scope.depFor(name: depName).get, + ); + scope.register(lastDep); + } + }; + } + throw UnsupportedError('Scenario $scenario not supported by YxScopeAdapter'); + } +} diff --git a/benchmark_di/lib/di_adapters/yx_scope_universal_container.dart b/benchmark_di/lib/di_adapters/yx_scope_universal_container.dart new file mode 100644 index 0000000..6855a01 --- /dev/null +++ b/benchmark_di/lib/di_adapters/yx_scope_universal_container.dart @@ -0,0 +1,30 @@ +import 'package:yx_scope/yx_scope.dart'; + +/// Universal container for dynamic DI registration in yx_scope (for benchmarks). +/// Allows to register and resolve deps by name/type at runtime. +class UniversalYxScopeContainer extends ScopeContainer { + final Map> _namedDeps = {}; + final Map> _typedDeps = {}; + + void register(Dep dep, {String? name}) { + if (name != null) { + _namedDeps[_depKey(name)] = dep; + } else { + _typedDeps[T] = dep; + } + } + + Dep depFor({String? name}) { + if (name != null) { + final dep = _namedDeps[_depKey(name)]; + if (dep is Dep) return dep; + throw Exception('No dep for type $T/$name'); + } else { + final dep = _typedDeps[T]; + if (dep is Dep) return dep; + throw Exception('No dep for type $T'); + } + } + + static String _depKey(String name) => '$T@$name'; +} diff --git a/benchmark_di/pubspec.lock b/benchmark_di/pubspec.lock index c821796..e50d513 100644 --- a/benchmark_di/pubspec.lock +++ b/benchmark_di/pubspec.lock @@ -136,5 +136,13 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + yx_scope: + dependency: "direct main" + description: + name: yx_scope + sha256: "9ba98b442261596311363bf7361622e5ccc67189705b8d042ca23c9de366f8bf" + url: "https://pub.dev" + source: hosted + version: "1.1.2" sdks: dart: ">=3.6.0 <4.0.0" diff --git a/benchmark_di/pubspec.yaml b/benchmark_di/pubspec.yaml index dcb4404..26745a9 100644 --- a/benchmark_di/pubspec.yaml +++ b/benchmark_di/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: get_it: ^8.2.0 riverpod: ^2.6.1 kiwi: ^5.0.1 + yx_scope: ^1.1.2 dev_dependencies: lints: ^5.0.0