cloner 1.0.3
cloner: ^1.0.3 copied to clipboard
Utilities for deep cloning collections and custom types with flexible extension points and optional circular reference detection.
example/cloner_example.dart
import 'package:cloner/cloner.dart';
/// Showcase for core [Cloner] functionality and collection extensions.
void main() {
// --- ICloneable – custom types with deep-clone support ---
final original = Person('Alice', Address('Main St', 42));
final cloned = original.clone();
cloned.name = 'Bob';
cloned.address.street = 'Oak Ave';
print(
'Original: ${original.name}, ${original.address.street}',
); // Alice, Main St
print('Cloned: ${cloned.name}, ${cloned.address.street}'); // Bob, Oak Ave
// --- Cloner.cloneValue – type-dispatching clone (typed) ---
final list = [1, 2, 3];
final clonedList = Cloner.instance().cloneValue(list);
clonedList[0] = 99;
print('Original list: $list'); // [1, 2, 3]
print('Cloned list: $clonedList'); // [99, 2, 3]
// --- List cloning extensions ---
final people = [Person('Eve', Address('Elm St', 7))];
final peopleClone = people.clone();
peopleClone.first.name = 'Zoe';
print('Original person: ${people.first.name}'); // Eve
print('Cloned person: ${peopleClone.first.name}'); // Zoe
// Dynamic clone – handles nested maps and objects
final mixed = [
{'key': 'value'},
Person('Dan', Address('Pine Rd', 5)),
];
final mixedClone = mixed.cloneDynamic();
(mixedClone[0] as Map)['key'] = 'changed';
print('Original map: ${mixed[0]}'); // {key: value}
print('Cloned map: ${mixedClone[0]}'); // {key: changed}
// --- Map cloning ---
final scores = {'alice': 100, 'bob': 95};
try {
final scoresClone = scores.clone();
scoresClone['alice'] = 0;
print('Cloned scores: $scoresClone'); // {alice: 0, bob: 95}
} on UnsupportedTypedCloneException catch (exc) {
print(exc);
}
print('Original scores: $scores'); // {alice: 100, bob: 95}
// --- MapClone – typed wrapper for nested map cloning ---
final config = MapClone<String, MapClone<String, int>>.ofMap({
'limits': MapClone.ofMap({'maxRetries': 3, 'timeout': 30}),
});
final configClone = config.clone();
configClone['limits']!['maxRetries'] = 10;
print('Original maxRetries: ${config['limits']!['maxRetries']}'); // 3
print('Cloned maxRetries: ${configClone['limits']!['maxRetries']}'); // 10
}
// --- Example ICloneable implementations ---
class Address implements ICloneable<Address> {
String street;
int number;
Address(this.street, this.number);
@override
Address clone([ICloning? cloner]) => Address(street, number);
}
class Person implements ICloneable<Person> {
String name;
Address address;
Person(this.name, this.address);
@override
Person clone([ICloning? cloner]) => Person(name, address.clone(cloner));
}