-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for deep collection casting in the generator (#95)
* add support for deep casting nested collection types in the generator * add deep cast test * regenerate
- Loading branch information
Showing
6 changed files
with
214 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'dart:collection'; | ||
|
||
extension DeepCastMap<SK, SV> on Map<SK, SV> { | ||
/// A lazy deep cast map for `this`, where the values are deeply cast using | ||
/// the provided [castValue] function, and they keys are normally cast. | ||
Map<K, V> deepCast<K, V>(V Function(SV) castValue) => | ||
_DeepCastMap(this, castValue); | ||
} | ||
|
||
/// Like a `CastMap`, except it can perform deep casts on values using a | ||
/// provided conversion function. | ||
class _DeepCastMap<SK, SV, K, V> extends MapBase<K, V> { | ||
final Map<SK, SV> _source; | ||
|
||
final V Function(SV) _castValue; | ||
|
||
_DeepCastMap(this._source, this._castValue); | ||
|
||
@override | ||
bool containsValue(Object? value) => _source.containsValue(value); | ||
|
||
@override | ||
bool containsKey(Object? key) => _source.containsKey(key); | ||
|
||
@override | ||
V? operator [](Object? key) { | ||
final value = _source[key]; | ||
if (value == null) return null; | ||
return _castValue(value); | ||
} | ||
|
||
@override | ||
void operator []=(K key, V value) { | ||
_source[key as SK] = value as SV; | ||
} | ||
|
||
@override | ||
V putIfAbsent(K key, V Function() ifAbsent) => | ||
_castValue(_source.putIfAbsent(key as SK, () => ifAbsent() as SV)); | ||
|
||
@override | ||
V? remove(Object? key) { | ||
final removed = _source.remove(key); | ||
if (removed == null) return null; | ||
return _castValue(removed); | ||
} | ||
|
||
@override | ||
void clear() { | ||
_source.clear(); | ||
} | ||
|
||
@override | ||
void forEach(void Function(K key, V value) f) { | ||
_source.forEach((SK key, SV value) { | ||
f(key as K, _castValue(value)); | ||
}); | ||
} | ||
|
||
@override | ||
Iterable<K> get keys => _source.keys.cast(); | ||
|
||
@override | ||
Iterable<V> get values => _source.values.map(_castValue); | ||
|
||
@override | ||
int get length => _source.length; | ||
|
||
@override | ||
bool get isEmpty => _source.isEmpty; | ||
|
||
@override | ||
bool get isNotEmpty => _source.isNotEmpty; | ||
|
||
@override | ||
V update(K key, V Function(V value) update, {V Function()? ifAbsent}) { | ||
return _castValue(_source.update( | ||
key as SK, (SV value) => update(_castValue(value)) as SV, | ||
ifAbsent: (ifAbsent == null) ? null : () => ifAbsent() as SV)); | ||
} | ||
|
||
@override | ||
void updateAll(V Function(K key, V value) update) { | ||
_source.updateAll( | ||
(SK key, SV value) => update(key as K, _castValue(value)) as SV); | ||
} | ||
|
||
@override | ||
Iterable<MapEntry<K, V>> get entries { | ||
return _source.entries.map<MapEntry<K, V>>((MapEntry<SK, SV> e) => | ||
MapEntry<K, V>(e.key as K, _castValue(e.value))); | ||
} | ||
|
||
@override | ||
void addEntries(Iterable<MapEntry<K, V>> entries) { | ||
for (var entry in entries) { | ||
_source[entry.key as SK] = entry.value as SV; | ||
} | ||
} | ||
|
||
@override | ||
void removeWhere(bool Function(K key, V value) test) { | ||
_source | ||
.removeWhere((SK key, SV value) => test(key as K, _castValue(value))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'package:dart_model/src/deep_cast_map.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
void main() { | ||
test('can perform deep casts on maps', () { | ||
final initial = <dynamic, dynamic>{ | ||
'x': <dynamic>[1, 2, 3] | ||
}; | ||
expect(initial, isNot(isA<Map<String, List<int>>>())); | ||
final typed = | ||
initial.deepCast<String, List<int>>((v) => (v as List).cast<int>()); | ||
expect(typed, isA<Map<String, List<int>>>()); | ||
expect(typed['x']!, isA<List<int>>()); | ||
expect(typed['x']!, [1, 2, 3]); | ||
}); | ||
|
||
test('can perform really deep casts on maps', () { | ||
final initial = <dynamic, dynamic>{ | ||
'x': <dynamic, dynamic>{ | ||
'y': <dynamic>[1, 2, 3] | ||
}, | ||
}; | ||
expect(initial, isNot(isA<Map<String, Map<String, List<int>>>>())); | ||
|
||
final typed = initial.deepCast<String, Map<String, List<int>>>((v) => | ||
(v as Map).deepCast<String, List<int>>((v) => (v as List).cast())); | ||
expect(typed, isA<Map<String, Map<String, List<int>>>>()); | ||
|
||
expect(initial['x'], isNot(isA<Map<String, List<int>>>())); | ||
final x = typed['x']!; | ||
expect(x, isA<Map<String, List<int>>>()); | ||
|
||
expect((initial['x'] as Map)['y'], isNot(isA<List<int>>())); | ||
final y = x['y']!; | ||
expect(y, isA<List<int>>()); | ||
expect(y, [1, 2, 3]); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters