From a897c1b31b289cef037b47145324dd875c38241d Mon Sep 17 00:00:00 2001 From: Sergey Penkovsky Date: Mon, 18 Aug 2025 18:40:07 +0300 Subject: [PATCH] feat(benchmark_di): add Kiwi DI adapter and CLI integration --- benchmark_di/lib/cli/benchmark_cli.dart | 35 ++++- .../lib/di_adapters/kiwi_adapter.dart | 128 ++++++++++++++++++ benchmark_di/pubspec.lock | 10 +- benchmark_di/pubspec.yaml | 1 + 4 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 benchmark_di/lib/di_adapters/kiwi_adapter.dart diff --git a/benchmark_di/lib/cli/benchmark_cli.dart b/benchmark_di/lib/cli/benchmark_cli.dart index 0c68cdc..6d81137 100644 --- a/benchmark_di/lib/cli/benchmark_cli.dart +++ b/benchmark_di/lib/cli/benchmark_cli.dart @@ -16,6 +16,8 @@ import 'package:benchmark_di/benchmarks/universal_chain_async_benchmark.dart'; import 'package:benchmark_di/di_adapters/cherrypick_adapter.dart'; import 'package:benchmark_di/di_adapters/get_it_adapter.dart'; import 'package:benchmark_di/di_adapters/riverpod_adapter.dart'; +import 'package:benchmark_di/di_adapters/kiwi_adapter.dart'; +import 'package:kiwi/kiwi.dart'; /// Command-line interface (CLI) runner for benchmarks. /// @@ -61,11 +63,40 @@ class BenchmarkCliRunner { repeats: config.repeats, ); } + } else if (config.di == 'kiwi') { + final di = KiwiAdapter(); + if (scenario == UniversalScenario.asyncChain) { + // UnsupportedError будет выброшен адаптером, но если дойдёт — вызывать async benchmark + 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 if (config.di == 'riverpod') { final di = RiverpodAdapter(); if (scenario == UniversalScenario.asyncChain) { final benchAsync = UniversalChainAsyncBenchmark< - Map>>( + Map>> ( di, chainCount: c, nestingDepth: d, @@ -78,7 +109,7 @@ class BenchmarkCliRunner { ); } else { final benchSync = UniversalChainBenchmark< - Map>>( + Map>> ( di, chainCount: c, nestingDepth: d, diff --git a/benchmark_di/lib/di_adapters/kiwi_adapter.dart b/benchmark_di/lib/di_adapters/kiwi_adapter.dart new file mode 100644 index 0000000..56c6f42 --- /dev/null +++ b/benchmark_di/lib/di_adapters/kiwi_adapter.dart @@ -0,0 +1,128 @@ +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:kiwi/kiwi.dart'; +import 'di_adapter.dart'; + +/// DIAdapter-для KiwiContainer с поддержкой universal benchmark сценариев. +class KiwiAdapter extends DIAdapter { + late KiwiContainer _container; + final bool _isSubScope; + + KiwiAdapter({KiwiContainer? container, bool isSubScope = false}) + : _isSubScope = isSubScope { + _container = container ?? KiwiContainer(); + } + + @override + void setupDependencies(void Function(KiwiContainer container) registration) { + registration(_container); + } + +@override +Registration universalRegistration({ + required S scenario, + required int chainCount, + required int nestingDepth, + required UniversalBindingMode bindingMode, +}) { + if (scenario is UniversalScenario) { + if (scenario == UniversalScenario.asyncChain || + bindingMode == UniversalBindingMode.asyncStrategy) { + throw UnsupportedError('Kiwi does not support async dependencies or async binding scenarios.'); + } + return (container) { + switch (scenario) { + case UniversalScenario.asyncChain: + break; + case UniversalScenario.register: + container.registerSingleton( + (c) => UniversalServiceImpl(value: 'reg', dependency: null), + ); + break; + case UniversalScenario.named: + container.registerFactory( + (c) => UniversalServiceImpl(value: 'impl1'), name: 'impl1'); + container.registerFactory( + (c) => UniversalServiceImpl(value: 'impl2'), 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'; + switch (bindingMode) { + case UniversalBindingMode.singletonStrategy: + container.registerSingleton( + (c) => UniversalServiceImpl( + value: depName, + dependency: level > 1 + ? c.resolve(prevDepName) + : null), + name: depName); + break; + case UniversalBindingMode.factoryStrategy: + container.registerFactory( + (c) => UniversalServiceImpl( + value: depName, + dependency: level > 1 + ? c.resolve(prevDepName) + : null), + name: depName); + break; + case UniversalBindingMode.asyncStrategy: + // Не поддерживается + break; + } + } + } + final depName = '${chainCount}_$nestingDepth'; + container.registerSingleton( + (c) => c.resolve(depName)); + break; + case UniversalScenario.override: + final depName = '${chainCount}_$nestingDepth'; + container.registerSingleton( + (c) => c.resolve(depName)); + break; + } + }; + } + throw UnsupportedError('Scenario $scenario not supported by KiwiAdapter'); +} + + @override + T resolve({String? named}) { + // Для asyncChain нужен resolve> + if (T.toString().startsWith('Future<')) { + return _container.resolve(named); + } else { + return _container.resolve(named); + } + } + + @override + Future resolveAsync({String? named}) async { + if (T.toString().startsWith('Future<')) { + // resolve>, unwrap result + return Future.value(_container.resolve(named)); + } else { + // Для совместимости с chain/override + return Future.value(_container.resolve(named)); + } + } + + @override + void teardown() { + _container.clear(); + } + + @override + KiwiAdapter openSubScope(String name) { + // Возвращаем новый scoped контейнер (отдельный). Наследование не реализовано. + return KiwiAdapter(container: KiwiContainer.scoped(), isSubScope: true); + } + + @override + Future waitForAsyncReady() async {} +} diff --git a/benchmark_di/pubspec.lock b/benchmark_di/pubspec.lock index 1fc8da8..c821796 100644 --- a/benchmark_di/pubspec.lock +++ b/benchmark_di/pubspec.lock @@ -47,7 +47,7 @@ packages: path: "../cherrypick" relative: true source: path - version: "3.0.0-dev.9" + version: "3.0.0-dev.10" collection: dependency: transitive description: @@ -72,6 +72,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.2.0" + kiwi: + dependency: "direct main" + description: + name: kiwi + sha256: d078364a90fb1b93852bb74468efdf4aaae35c036c538c1cf4f9c74a19df9a61 + url: "https://pub.dev" + source: hosted + version: "5.0.1" lazy_memo: dependency: transitive description: diff --git a/benchmark_di/pubspec.yaml b/benchmark_di/pubspec.yaml index 87d2865..dcb4404 100644 --- a/benchmark_di/pubspec.yaml +++ b/benchmark_di/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: args: ^2.7.0 get_it: ^8.2.0 riverpod: ^2.6.1 + kiwi: ^5.0.1 dev_dependencies: lints: ^5.0.0