style: reformat codebase using melos format

Applied consistent code formatting across all packages using \$ melos format
  └> dart format .
     └> RUNNING (in 8 packages)

--------------------------------------------------------------------------------
benchmark_di:
Formatted 18 files (0 changed) in 0.30 seconds.
benchmark_di: SUCCESS
--------------------------------------------------------------------------------
cherrypick:
Formatted 24 files (0 changed) in 0.34 seconds.
cherrypick: SUCCESS
--------------------------------------------------------------------------------
cherrypick_annotations:
Formatted 11 files (0 changed) in 0.14 seconds.
cherrypick_annotations: SUCCESS
--------------------------------------------------------------------------------
cherrypick_flutter:
Formatted 3 files (0 changed) in 0.15 seconds.
cherrypick_flutter: SUCCESS
--------------------------------------------------------------------------------
cherrypick_generator:
Formatted 17 files (0 changed) in 0.27 seconds.
cherrypick_generator: SUCCESS
--------------------------------------------------------------------------------
client_app:
Formatted 4 files (0 changed) in 0.14 seconds.
client_app: SUCCESS
--------------------------------------------------------------------------------
postly:
Formatted lib/router/app_router.gr.dart
Formatted 23 files (1 changed) in 0.33 seconds.
postly: SUCCESS
--------------------------------------------------------------------------------
talker_cherrypick_logger:
Formatted 4 files (0 changed) in 0.18 seconds.
talker_cherrypick_logger: SUCCESS
--------------------------------------------------------------------------------

$ melos format
  └> dart format .
     └> SUCCESS. No functional or logic changes included.
This commit is contained in:
Sergey Penkovsky
2025-08-13 15:38:44 +03:00
parent 99e662124f
commit c91e15319b
46 changed files with 739 additions and 465 deletions

View File

@@ -2,4 +2,4 @@ import 'package:benchmark_di/cli/benchmark_cli.dart';
Future<void> main(List<String> args) async {
await BenchmarkCliRunner().run(args);
}
}

View File

@@ -73,7 +73,8 @@ class UniversalChainBenchmark<TContainer> extends BenchmarkBase {
_childDi!.resolve<UniversalService>();
break;
case UniversalScenario.asyncChain:
throw UnsupportedError('asyncChain supported only in UniversalChainAsyncBenchmark');
throw UnsupportedError(
'asyncChain supported only in UniversalChainAsyncBenchmark');
}
}
}

View File

@@ -36,8 +36,11 @@ class BenchmarkCliRunner {
if (config.di == 'getit') {
final di = GetItAdapter();
if (scenario == UniversalScenario.asyncChain) {
final benchAsync = UniversalChainAsyncBenchmark<GetIt>(di,
chainCount: c, nestingDepth: d, mode: mode,
final benchAsync = UniversalChainAsyncBenchmark<GetIt>(
di,
chainCount: c,
nestingDepth: d,
mode: mode,
);
benchResult = await BenchmarkRunner.runAsync(
benchmark: benchAsync,
@@ -45,8 +48,12 @@ class BenchmarkCliRunner {
repeats: config.repeats,
);
} else {
final benchSync = UniversalChainBenchmark<GetIt>(di,
chainCount: c, nestingDepth: d, mode: mode, scenario: scenario,
final benchSync = UniversalChainBenchmark<GetIt>(
di,
chainCount: c,
nestingDepth: d,
mode: mode,
scenario: scenario,
);
benchResult = await BenchmarkRunner.runSync(
benchmark: benchSync,
@@ -57,8 +64,12 @@ class BenchmarkCliRunner {
} else if (config.di == 'riverpod') {
final di = RiverpodAdapter();
if (scenario == UniversalScenario.asyncChain) {
final benchAsync = UniversalChainAsyncBenchmark<Map<String, rp.ProviderBase<Object?>>>(di,
chainCount: c, nestingDepth: d, mode: mode,
final benchAsync = UniversalChainAsyncBenchmark<
Map<String, rp.ProviderBase<Object?>>>(
di,
chainCount: c,
nestingDepth: d,
mode: mode,
);
benchResult = await BenchmarkRunner.runAsync(
benchmark: benchAsync,
@@ -66,8 +77,13 @@ class BenchmarkCliRunner {
repeats: config.repeats,
);
} else {
final benchSync = UniversalChainBenchmark<Map<String, rp.ProviderBase<Object?>>>(di,
chainCount: c, nestingDepth: d, mode: mode, scenario: scenario,
final benchSync = UniversalChainBenchmark<
Map<String, rp.ProviderBase<Object?>>>(
di,
chainCount: c,
nestingDepth: d,
mode: mode,
scenario: scenario,
);
benchResult = await BenchmarkRunner.runSync(
benchmark: benchSync,
@@ -78,8 +94,11 @@ class BenchmarkCliRunner {
} else {
final di = CherrypickDIAdapter();
if (scenario == UniversalScenario.asyncChain) {
final benchAsync = UniversalChainAsyncBenchmark<Scope>(di,
chainCount: c, nestingDepth: d, mode: mode,
final benchAsync = UniversalChainAsyncBenchmark<Scope>(
di,
chainCount: c,
nestingDepth: d,
mode: mode,
);
benchResult = await BenchmarkRunner.runAsync(
benchmark: benchAsync,
@@ -87,8 +106,12 @@ class BenchmarkCliRunner {
repeats: config.repeats,
);
} else {
final benchSync = UniversalChainBenchmark<Scope>(di,
chainCount: c, nestingDepth: d, mode: mode, scenario: scenario,
final benchSync = UniversalChainBenchmark<Scope>(
di,
chainCount: c,
nestingDepth: d,
mode: mode,
scenario: scenario,
);
benchResult = await BenchmarkRunner.runSync(
benchmark: benchSync,
@@ -103,7 +126,11 @@ class BenchmarkCliRunner {
var median = timings[timings.length ~/ 2];
var minVal = timings.first;
var maxVal = timings.last;
var stddev = timings.isEmpty ? 0 : sqrt(timings.map((x) => pow(x - mean, 2)).reduce((a, b) => a + b) / timings.length);
var stddev = timings.isEmpty
? 0
: sqrt(
timings.map((x) => pow(x - mean, 2)).reduce((a, b) => a + b) /
timings.length);
results.add({
'benchmark': 'Universal_$bench',
'chainCount': c,
@@ -128,6 +155,7 @@ class BenchmarkCliRunner {
'json': JsonReport(),
'markdown': MarkdownReport(),
};
print(reportGenerators[config.format]?.render(results) ?? PrettyReport().render(results));
print(reportGenerators[config.format]?.render(results) ??
PrettyReport().render(results));
}
}
}

View File

@@ -8,14 +8,19 @@ import 'package:benchmark_di/scenarios/universal_scenario.dart';
enum UniversalBenchmark {
/// Simple singleton registration benchmark
registerSingleton,
/// Chain of singleton dependencies
chainSingleton,
/// Chain using factories
chainFactory,
/// Async chain resolution
chainAsync,
/// Named registration benchmark
named,
/// Override/child-scope benchmark
override,
}
@@ -65,23 +70,32 @@ T parseEnum<T>(String value, List<T> values, T defaultValue) {
}
/// Parses comma-separated integer list from [s].
List<int> parseIntList(String s) =>
s.split(',').map((e) => int.tryParse(e.trim()) ?? 0).where((x) => x > 0).toList();
List<int> parseIntList(String s) => s
.split(',')
.map((e) => int.tryParse(e.trim()) ?? 0)
.where((x) => x > 0)
.toList();
/// CLI config describing what and how to benchmark.
class BenchmarkCliConfig {
/// Benchmarks enabled to run (scenarios).
final List<UniversalBenchmark> benchesToRun;
/// List of chain counts (parallel, per test).
final List<int> chainCounts;
/// List of nesting depths (max chain length, per test).
final List<int> nestDepths;
/// How many times to repeat each trial.
final int repeats;
/// How many times to warm-up before measuring.
final int warmups;
/// Output report format.
final String format;
/// Name of DI implementation ("cherrypick" or "getit")
final String di;
BenchmarkCliConfig({
@@ -105,7 +119,9 @@ BenchmarkCliConfig parseBenchmarkCli(List<String> args) {
..addOption('repeat', abbr: 'r', defaultsTo: '2')
..addOption('warmup', abbr: 'w', defaultsTo: '1')
..addOption('format', abbr: 'f', defaultsTo: 'pretty')
..addOption('di', defaultsTo: 'cherrypick', help: 'DI implementation: cherrypick, getit or riverpod')
..addOption('di',
defaultsTo: 'cherrypick',
help: 'DI implementation: cherrypick, getit or riverpod')
..addFlag('help', abbr: 'h', negatable: false, help: 'Show help');
final result = parser.parse(args);
if (result['help'] == true) {
@@ -127,4 +143,4 @@ BenchmarkCliConfig parseBenchmarkCli(List<String> args) {
format: result['format'] as String,
di: result['di'] as String? ?? 'cherrypick',
);
}
}

View File

@@ -5,20 +5,32 @@ class CsvReport extends ReportGenerator {
/// List of all keys/columns to include in the CSV output.
@override
final List<String> keys = [
'benchmark','chainCount','nestingDepth','mean_us','median_us','stddev_us',
'min_us','max_us','trials','timings_us','memory_diff_kb','delta_peak_kb','peak_rss_kb'
'benchmark',
'chainCount',
'nestingDepth',
'mean_us',
'median_us',
'stddev_us',
'min_us',
'max_us',
'trials',
'timings_us',
'memory_diff_kb',
'delta_peak_kb',
'peak_rss_kb'
];
/// Renders rows as a CSV table string.
@override
String render(List<Map<String, dynamic>> rows) {
final header = keys.join(',');
final lines = rows.map((r) =>
keys.map((k) {
final v = r[k];
if (v is List) return '"${v.join(';')}"';
return (v ?? '').toString();
}).join(',')
).toList();
final lines = rows
.map((r) => keys.map((k) {
final v = r[k];
if (v is List) return '"${v.join(';')}"';
return (v ?? '').toString();
}).join(','))
.toList();
return ([header] + lines).join('\n');
}
}
}

View File

@@ -5,9 +5,10 @@ class JsonReport extends ReportGenerator {
/// No specific keys; outputs all fields in raw map.
@override
List<String> get keys => [];
/// Renders all result rows as a pretty-printed JSON array.
@override
String render(List<Map<String, dynamic>> rows) {
return '[\n${rows.map((r) => ' $r').join(',\n')}\n]';
}
}
}

View File

@@ -7,25 +7,46 @@ class MarkdownReport extends ReportGenerator {
/// List of columns (keys) to show in the Markdown table.
@override
final List<String> keys = [
'benchmark','chainCount','nestingDepth','mean_us','median_us','stddev_us',
'min_us','max_us','trials','memory_diff_kb','delta_peak_kb','peak_rss_kb'
'benchmark',
'chainCount',
'nestingDepth',
'mean_us',
'median_us',
'stddev_us',
'min_us',
'max_us',
'trials',
'memory_diff_kb',
'delta_peak_kb',
'peak_rss_kb'
];
/// Friendly display names for each benchmark type.
static const nameMap = {
'Universal_UniversalBenchmark.registerSingleton':'RegisterSingleton',
'Universal_UniversalBenchmark.chainSingleton':'ChainSingleton',
'Universal_UniversalBenchmark.chainFactory':'ChainFactory',
'Universal_UniversalBenchmark.chainAsync':'AsyncChain',
'Universal_UniversalBenchmark.named':'Named',
'Universal_UniversalBenchmark.override':'Override',
'Universal_UniversalBenchmark.registerSingleton': 'RegisterSingleton',
'Universal_UniversalBenchmark.chainSingleton': 'ChainSingleton',
'Universal_UniversalBenchmark.chainFactory': 'ChainFactory',
'Universal_UniversalBenchmark.chainAsync': 'AsyncChain',
'Universal_UniversalBenchmark.named': 'Named',
'Universal_UniversalBenchmark.override': 'Override',
};
/// Renders all results as a formatted Markdown table with aligned columns and a legend.
@override
String render(List<Map<String, dynamic>> rows) {
final headers = [
'Benchmark', 'Chain Count', 'Depth', 'Mean (us)', 'Median', 'Stddev', 'Min', 'Max', 'N', 'ΔRSS(KB)', 'ΔPeak(KB)', 'PeakRSS(KB)'
'Benchmark',
'Chain Count',
'Depth',
'Mean (us)',
'Median',
'Stddev',
'Min',
'Max',
'N',
'ΔRSS(KB)',
'ΔPeak(KB)',
'PeakRSS(KB)'
];
final dataRows = rows.map((r) {
final readableName = nameMap[r['benchmark']] ?? r['benchmark'];
@@ -73,6 +94,6 @@ class MarkdownReport extends ReportGenerator {
> `PeakRSS(KB)` Max observed RSS memory (KB)
''';
return '$legend\n\n${([headerLine, divider] + lines).join('\n')}' ;
return '$legend\n\n${([headerLine, divider] + lines).join('\n')}';
}
}
}

View File

@@ -7,25 +7,46 @@ class PrettyReport extends ReportGenerator {
/// List of columns to output in the pretty report.
@override
final List<String> keys = [
'benchmark','chainCount','nestingDepth','mean_us','median_us','stddev_us',
'min_us','max_us','trials','memory_diff_kb','delta_peak_kb','peak_rss_kb'
'benchmark',
'chainCount',
'nestingDepth',
'mean_us',
'median_us',
'stddev_us',
'min_us',
'max_us',
'trials',
'memory_diff_kb',
'delta_peak_kb',
'peak_rss_kb'
];
/// Mappings from internal benchmark IDs to display names.
static const nameMap = {
'Universal_UniversalBenchmark.registerSingleton': 'RegisterSingleton',
'Universal_UniversalBenchmark.chainSingleton': 'ChainSingleton',
'Universal_UniversalBenchmark.chainFactory': 'ChainFactory',
'Universal_UniversalBenchmark.chainAsync': 'AsyncChain',
'Universal_UniversalBenchmark.named': 'Named',
'Universal_UniversalBenchmark.override': 'Override',
'Universal_UniversalBenchmark.registerSingleton': 'RegisterSingleton',
'Universal_UniversalBenchmark.chainSingleton': 'ChainSingleton',
'Universal_UniversalBenchmark.chainFactory': 'ChainFactory',
'Universal_UniversalBenchmark.chainAsync': 'AsyncChain',
'Universal_UniversalBenchmark.named': 'Named',
'Universal_UniversalBenchmark.override': 'Override',
};
/// Renders the results as a header + tab-separated value table.
@override
String render(List<Map<String, dynamic>> rows) {
final headers = [
'Benchmark', 'Chain Count', 'Depth', 'Mean (us)', 'Median', 'Stddev', 'Min', 'Max', 'N', 'ΔRSS(KB)', 'ΔPeak(KB)', 'PeakRSS(KB)'
'Benchmark',
'Chain Count',
'Depth',
'Mean (us)',
'Median',
'Stddev',
'Min',
'Max',
'N',
'ΔRSS(KB)',
'ΔPeak(KB)',
'PeakRSS(KB)'
];
final header = headers.join('\t');
final lines = rows.map((r) {

View File

@@ -4,6 +4,7 @@
abstract class ReportGenerator {
/// Renders the given [results] as a formatted string (table, markdown, csv, etc).
String render(List<Map<String, dynamic>> results);
/// List of output columns/keys included in the export (or [] for auto/all).
List<String> get keys;
}
}

View File

@@ -7,10 +7,13 @@ import 'package:benchmark_di/benchmarks/universal_chain_async_benchmark.dart';
class BenchmarkResult {
/// List of timings for each run (in microseconds).
final List<num> timings;
/// Difference in memory (RSS, in KB) after running.
final int memoryDiffKb;
/// Difference between peak RSS and initial RSS (in KB).
final int deltaPeakKb;
/// Peak RSS memory observed (in KB).
final int peakRssKb;
BenchmarkResult({
@@ -19,6 +22,7 @@ class BenchmarkResult {
required this.deltaPeakKb,
required this.peakRssKb,
});
/// Computes a BenchmarkResult instance from run timings and memory data.
factory BenchmarkResult.collect({
required List<num> timings,
@@ -64,7 +68,8 @@ class BenchmarkRunner {
rssValues.add(ProcessInfo.currentRss);
benchmark.teardown();
}
return BenchmarkResult.collect(timings: timings, rssValues: rssValues, memBefore: memBefore);
return BenchmarkResult.collect(
timings: timings, rssValues: rssValues, memBefore: memBefore);
}
/// Runs an asynchronous benchmark ([UniversalChainAsyncBenchmark]) for a given number of [warmups] and [repeats].
@@ -91,6 +96,7 @@ class BenchmarkRunner {
rssValues.add(ProcessInfo.currentRss);
await benchmark.teardown();
}
return BenchmarkResult.collect(timings: timings, rssValues: rssValues, memBefore: memBefore);
return BenchmarkResult.collect(
timings: timings, rssValues: rssValues, memBefore: memBefore);
}
}
}

View File

@@ -4,7 +4,6 @@ import 'package:benchmark_di/scenarios/universal_service.dart';
import 'package:cherrypick/cherrypick.dart';
import 'di_adapter.dart';
/// Test module that generates a chain of service bindings for benchmarking.
///
/// Configurable by chain count, nesting depth, binding mode, and scenario
@@ -12,10 +11,13 @@ import 'di_adapter.dart';
class UniversalChainModule extends Module {
/// Number of chains to create.
final int chainCount;
/// Depth of each chain.
final int nestingDepth;
/// How modules are registered (factory/singleton/async).
final UniversalBindingMode bindingMode;
/// Which di scenario to generate (chained, named, etc).
final UniversalScenario scenario;
@@ -38,17 +40,18 @@ class UniversalChainModule extends Module {
final prevDepName = '${chain}_${level - 1}';
final depName = '${chain}_$level';
bind<UniversalService>()
.toProvideAsync(() async {
final prev = level > 1
? await currentScope.resolveAsync<UniversalService>(named: prevDepName)
: null;
return UniversalServiceImpl(
value: depName,
dependency: prev,
);
})
.withName(depName)
.singleton();
.toProvideAsync(() async {
final prev = level > 1
? await currentScope.resolveAsync<UniversalService>(
named: prevDepName)
: null;
return UniversalServiceImpl(
value: depName,
dependency: prev,
);
})
.withName(depName)
.singleton();
}
}
return;
@@ -58,13 +61,18 @@ class UniversalChainModule extends Module {
case UniversalScenario.register:
// Simple singleton registration.
bind<UniversalService>()
.toProvide(() => UniversalServiceImpl(value: 'reg', dependency: null))
.toProvide(
() => UniversalServiceImpl(value: 'reg', dependency: null))
.singleton();
break;
case UniversalScenario.named:
// Named factory registration for two distinct objects.
bind<UniversalService>().toProvide(() => UniversalServiceImpl(value: 'impl1')).withName('impl1');
bind<UniversalService>().toProvide(() => UniversalServiceImpl(value: 'impl2')).withName('impl2');
bind<UniversalService>()
.toProvide(() => UniversalServiceImpl(value: 'impl1'))
.withName('impl1');
bind<UniversalService>()
.toProvide(() => UniversalServiceImpl(value: 'impl2'))
.withName('impl2');
break;
case UniversalScenario.chain:
// Chain of nested services, with dependency on previous level by name.
@@ -79,7 +87,8 @@ class UniversalChainModule extends Module {
bind<UniversalService>()
.toProvide(() => UniversalServiceImpl(
value: depName,
dependency: currentScope.tryResolve<UniversalService>(named: prevDepName),
dependency: currentScope.tryResolve<UniversalService>(
named: prevDepName),
))
.withName(depName)
.singleton();
@@ -88,7 +97,8 @@ class UniversalChainModule extends Module {
bind<UniversalService>()
.toProvide(() => UniversalServiceImpl(
value: depName,
dependency: currentScope.tryResolve<UniversalService>(named: prevDepName),
dependency: currentScope.tryResolve<UniversalService>(
named: prevDepName),
))
.withName(depName);
break;
@@ -96,7 +106,9 @@ class UniversalChainModule extends Module {
bind<UniversalService>()
.toProvideAsync(() async => UniversalServiceImpl(
value: depName,
dependency: await currentScope.resolveAsync<UniversalService>(named: prevDepName),
dependency:
await currentScope.resolveAsync<UniversalService>(
named: prevDepName),
))
.withName(depName)
.singleton();
@@ -107,14 +119,16 @@ class UniversalChainModule extends Module {
// Регистрация алиаса без имени (на последний элемент цепочки)
final depName = '${chainCount}_$nestingDepth';
bind<UniversalService>()
.toProvide(() => currentScope.resolve<UniversalService>(named: depName))
.toProvide(
() => currentScope.resolve<UniversalService>(named: depName))
.singleton();
break;
case UniversalScenario.override:
// handled at benchmark level, но алиас нужен прямо в этом scope!
final depName = '${chainCount}_$nestingDepth';
bind<UniversalService>()
.toProvide(() => currentScope.resolve<UniversalService>(named: depName))
.toProvide(
() => currentScope.resolve<UniversalService>(named: depName))
.singleton();
break;
case UniversalScenario.asyncChain:
@@ -124,7 +138,6 @@ class UniversalChainModule extends Module {
}
}
class CherrypickDIAdapter extends DIAdapter<Scope> {
Scope? _scope;
final bool _isSubScope;
@@ -158,7 +171,8 @@ class CherrypickDIAdapter extends DIAdapter<Scope> {
]);
};
}
throw UnsupportedError('Scenario $scenario not supported by CherrypickDIAdapter');
throw UnsupportedError(
'Scenario $scenario not supported by CherrypickDIAdapter');
}
@override

View File

@@ -1,4 +1,5 @@
import 'package:benchmark_di/scenarios/universal_binding_mode.dart';
/// Универсальная абстракция для DI-адаптера с унифицированной функцией регистрации.
/// Теперь для каждого адаптера задаём строгий generic тип контейнера.
typedef Registration<TContainer> = void Function(TContainer);

View File

@@ -80,9 +80,11 @@ class GetItAdapter extends DIAdapter<GetIt> {
getIt.registerSingletonAsync<UniversalService>(
() async {
final prev = level > 1
? await getIt.getAsync<UniversalService>(instanceName: prevDepName)
? await getIt.getAsync<UniversalService>(
instanceName: prevDepName)
: null;
return UniversalServiceImpl(value: depName, dependency: prev);
return UniversalServiceImpl(
value: depName, dependency: prev);
},
instanceName: depName,
);
@@ -90,11 +92,16 @@ class GetItAdapter extends DIAdapter<GetIt> {
}
break;
case UniversalScenario.register:
getIt.registerSingleton<UniversalService>(UniversalServiceImpl(value: 'reg', dependency: null));
getIt.registerSingleton<UniversalService>(
UniversalServiceImpl(value: 'reg', dependency: null));
break;
case UniversalScenario.named:
getIt.registerFactory<UniversalService>(() => UniversalServiceImpl(value: 'impl1'), instanceName: 'impl1');
getIt.registerFactory<UniversalService>(() => UniversalServiceImpl(value: 'impl2'), instanceName: 'impl2');
getIt.registerFactory<UniversalService>(
() => UniversalServiceImpl(value: 'impl1'),
instanceName: 'impl1');
getIt.registerFactory<UniversalService>(
() => UniversalServiceImpl(value: 'impl2'),
instanceName: 'impl2');
break;
case UniversalScenario.chain:
for (int chain = 1; chain <= chainCount; chain++) {
@@ -107,8 +114,8 @@ class GetItAdapter extends DIAdapter<GetIt> {
UniversalServiceImpl(
value: depName,
dependency: level > 1
? getIt<UniversalService>(instanceName: prevDepName)
: null,
? getIt<UniversalService>(instanceName: prevDepName)
: null,
),
instanceName: depName,
);
@@ -129,8 +136,9 @@ class GetItAdapter extends DIAdapter<GetIt> {
() async => UniversalServiceImpl(
value: depName,
dependency: level > 1
? await getIt.getAsync<UniversalService>(instanceName: prevDepName)
: null,
? await getIt.getAsync<UniversalService>(
instanceName: prevDepName)
: null,
),
instanceName: depName,
);
@@ -143,7 +151,8 @@ class GetItAdapter extends DIAdapter<GetIt> {
// handled at benchmark level
break;
}
if (scenario == UniversalScenario.chain || scenario == UniversalScenario.override) {
if (scenario == UniversalScenario.chain ||
scenario == UniversalScenario.override) {
final depName = '${chainCount}_$nestingDepth';
getIt.registerSingleton<UniversalService>(
getIt<UniversalService>(instanceName: depName),

View File

@@ -20,7 +20,9 @@ class RiverpodAdapter extends DIAdapter<Map<String, rp.ProviderBase<Object?>>> {
_parent = parent;
@override
void setupDependencies(void Function(Map<String, rp.ProviderBase<Object?>> container) registration) {
void setupDependencies(
void Function(Map<String, rp.ProviderBase<Object?>> container)
registration) {
_container ??= _parent == null
? rp.ProviderContainer()
: rp.ProviderContainer(parent: _parent);
@@ -76,7 +78,8 @@ class RiverpodAdapter extends DIAdapter<Map<String, rp.ProviderBase<Object?>>> {
}
@override
Registration<Map<String, rp.ProviderBase<Object?>>> universalRegistration<S extends Enum>({
Registration<Map<String, rp.ProviderBase<Object?>>>
universalRegistration<S extends Enum>({
required S scenario,
required int chainCount,
required int nestingDepth,
@@ -86,25 +89,34 @@ class RiverpodAdapter extends DIAdapter<Map<String, rp.ProviderBase<Object?>>> {
return (providers) {
switch (scenario) {
case UniversalScenario.register:
providers['UniversalService'] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(value: 'reg', dependency: null));
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'));
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,
));
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>));
providers['UniversalService'] = rp.Provider<UniversalService>(
(ref) => ref.watch(
providers[depName] as rp.ProviderBase<UniversalService>));
break;
case UniversalScenario.override:
// handled at benchmark level
@@ -114,24 +126,31 @@ class RiverpodAdapter extends DIAdapter<Map<String, rp.ProviderBase<Object?>>> {
for (int level = 1; level <= nestingDepth; level++) {
final prevDepName = '${chain}_${level - 1}';
final depName = '${chain}_$level';
providers[depName] = rp.FutureProvider<UniversalService>((ref) async {
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?
? 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);
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');
throw UnsupportedError(
'Scenario $scenario not supported by RiverpodAdapter');
}
}

View File

@@ -2,12 +2,16 @@
enum UniversalScenario {
/// Single registration.
register,
/// Chain of dependencies.
chain,
/// Named registrations.
named,
/// Child-scope override scenario.
override,
/// Asynchronous chain scenario.
asyncChain,
}

View File

@@ -1,4 +1,3 @@
/// Base interface for any universal service in the benchmarks.
///
/// Represents an object in the dependency chain with an identifiable value
@@ -6,6 +5,7 @@
abstract class UniversalService {
/// String ID for this service instance (e.g. chain/level info).
final String value;
/// Optional reference to dependency service in the chain.
final UniversalService? dependency;
UniversalService({required this.value, this.dependency});
@@ -14,4 +14,4 @@ abstract class UniversalService {
/// Default implementation for [UniversalService] used in service chains.
class UniversalServiceImpl extends UniversalService {
UniversalServiceImpl({required super.value, super.dependency});
}
}

View File

@@ -47,7 +47,7 @@ packages:
path: "../cherrypick"
relative: true
source: path
version: "3.0.0-dev.8"
version: "3.0.0-dev.9"
collection:
dependency: transitive
description: