deepCopy method
Returns a new List or Set that contains a deep copy of every element from this.
IMPORTANT: Creating a deep copy of List<Map<String, int>>,
Set<Map<String, int>> or any other Iterable<Map<String, int>> only
works with MyUtilityExtensionDeepCopyIterable.deepCopyDynamic.
This is because of a restriction in how generic type information can be preserved when copying a Map.
Implementation
Iterable<T> deepCopy({bool growable = true}) {
final copy = _SetOrList<T>.copy(this);
// Clear the copied list.
copy.clear();
// Deep copy every item and add it to [copy].
for (final item in this) {
final copiedItem = _deepCopy<T>(item);
try {
copy.add(copiedItem);
} catch (e) {
if (e is! TypeError) rethrow;
final msg = e.toString();
final prefix =
"type '${copiedItem.runtimeType}' is not a subtype of type 'Map";
if (!msg.startsWith(prefix)) rethrow;
// Extract expected type information from error message.
final mapTypesMatch = RegExp(r"'Map<(.+),\s*(.+)>'").firstMatch(msg)!;
final mapTypeKey = mapTypesMatch[1]!;
final mapTypeValue = mapTypesMatch[2]!;
// TODO(obemu): Somehow preserve generic types when copying maps.
//
// Preserving generic type information with [Map.of] or any other [Map]
// constructor is currently **only possible** if the constructor is used
// in the **same scope where the source object** has been declared,
// which means we loose generic type information in nested calls to
// deepCopy.
//
// Sadly there is no native `Map.toMap()` method, like the
// `Iterable.toList()` method that preserves generic type information.
// There also is no native `Map.clone` method. There is a hack to
// simulate `Map.toMap()`, but it depends on 'dart:isolate', is async
// and quite smelly:
//
// ```dart
// import 'dart:isolate';
//
// extension MapCloning<K,V> on Map<K,V> {
// Future<Map<K,V>> toMap()() {
// final port = ReceivePort();
// try {
// port.sendPort.send(this);
// return port.first as T;
// } finally {
// port.close();
// }
// }
// }
// ```
//
// There also seems to be no incentive on the side of the Dart team to
// introduce a proper way for this, see:
//
// * https://github.com/dart-lang/sdk/issues/50634
// * https://github.com/dart-lang/sdk/issues/45033
// * https://github.com/dart-lang/sdk/issues/50634
throw UnsupportedError(
"Cannot create a deep copy of a nested "
"Map<$mapTypeKey, $mapTypeValue>, without a user provided "
"DeepCopyFactory<Map<$mapTypeKey, $mapTypeValue>>.\n"
"\n"
"Copying nested maps without a user provided [DeepCopyFactory] is "
"currently not supported,\n"
"because of how the Dart SDK implements the [Map.of] and [Map.from] "
"constructors. The\n"
"current implementation makes it impossible to preserve "
"generic type information when\n"
"copying a Map. This causes issues when trying to add the "
"copied Map to an Iterable\n"
"that has preserved its generic type information.\n"
"\n"
"Error from dart:core lib:\n$msg",
);
}
}
return growable ? copy.inner : copy.toUnmodifiable();
}