Last updated:
0 purchases
fling pickle
A lightweight, small footprint Dart library for Serialization and Deserialization (SerDes). Forget initializing complex
systems or annotating your classes - with Pickles, everything related to SerDes is visible in code and straightforward.
Serialize your objects into JSON for readability or binary to optimize artifact size.
Usage #
While Pickles are most frequently used to persist object state or structure, they can also be treated as heavyweight
Memento objects - capable of performing undo/redo operations, for instance.
Compared to a classic memento, which does not allow classes other than the originator of the memento to create or "look
inside" the memento itself, Pickles do provide a basic interface. The cost of this decision is that "counterfeit"
mementos (created by something other than the class being serialized) might be passed off as originals by nefarious
evildoers (or otherwise well-meaning developers working under a tight deadline). Further, since a Pickle must act as a
generic state record, it is not as type-safe as a true memento. Consider these costs before replacing the traditional
Memento pattern with Pickles in your classes.
Pickles do, however, provide some benefit as a lightweight serialization core for your non-sensitive classes. You can
quickly set up a class whose state can be stored in a file or database to be restored at a later time without any messy
initialization or Mirrors magic. This means better performance with a small footprint. If you later decide you need
something more heavyweight, it is easy to extract - Pickles do not require any changes to, or conventions on, the
classes themselves.
Pickles support serialization to and from binary and Dart's JSON representation. This means you can use them seamlessly
with a lot of the core libraries and add-ons, like dart:convert or Firestore. See the examples below for details.
Examples #
The simplest use case involves a class that wishes to save itself as a Pickle and be restored later. We'll work with a
class that acts as a counter:
class Counter {
int count;
Counter([final int start = 0]) : count = start;
int countUp() => count++;
}
copied to clipboard
Full Integration #
At a basic level, we only need to store the current count in order to restore the object's state. We have several
options for making this class Pickle-friendly depending on how intrusive we want to be. We'll start with an example of
full integration:
class Counter implements Pickleable {
int count;
Counter([final int start = 0]) : count = start;
int countUp() => count++;
@override
Pickle toPickle() => PickleBuilder().withInt('count', count).build();
static Counter fromPickle(final Pickle pickle) => Counter(pickle.readInt('count'));
}
copied to clipboard
The three differences are:
We implement the Pickleable interface
We implement toPickle() by producing a Pickle containing our object's state
We implement fromPickle() by producing a Counter based on a Pickle's values
With this, we have full integration with Pickles, and can do things like the following:
void main() {
var counter = Counter();
print(counter.countUp());
var pickle = counter.toPickle();
print(counter.countUp());
counter = Counter.fromPickle(pickle);
print(counter.countUp());
// Write our pickle to a file.
// We can use synchronous or asynchronous methods for this, as needed.
File('myCounter').writeAsBytesSync(Pickler().writeSync(pickle));
var pickleFromFile = Pickler().readSync(File('myCounter').readAsBytesSync());
counter = Counter.fromPickle(pickleFromFile);
print(counter.countUp());
}
// outputs: 0, 1, 1, 1
copied to clipboard
Furthermore, we have full support for nested Pickling. For example, a class that uses Counter to produce version
numbers can easily "pickle" itself and the internal state of its Counter:
class Version implements Pickleable {
final Counter _counter;
Version() : _counter = Counter();
Version._(final this.counter);
String nextVersion() => 'v${_counter.countUp()}';
@override
Pickle toPickle() => PickleBuilder().withPickleable('counter', _counter).build();
static Version fromPickle(final Pickle pickle) => Version._(pickle.readPickleable('counter'));
}
copied to clipboard
Serializing and deserializing a Version is no different than that for a Counter, including saving to a file or any
other means of persistence:
void main() {
var version = Version();
print(version.nextVersion());
var pickle = version.toPickle();
print(version.nextVersion());
version = Version.fromPickle(pickle);
print(version.nextVersion());
// save as a file
File('MyVersion.pickle').writeAsBytes(
BinaryPickler().writeSync(pickle));
// or to a database like Firestore
FirebaseFirestore.instance.collection('versions').add(
JsonPickler.writeSync(pickle));
}
// outputs: v0, v1, v1
copied to clipboard
Unintrusive Integration #
If we do not want to (or cannot) modify the class we want to persist, we can still make use of Pickles as long as we
have access to the information we need to restore its state. Take the original Counter class, for instance; we can
support basic "pickling" by writing a couple of methods outside of the class itself:
class Counter {
int count;
Counter([final int start = 0]) : count = start;
int countUp() => count++;
}
// ...Somewhere else...
Pickle counterToPickle(final Counter counter) => PickleBuilder().withInt('start', counter.count).build();
Counter counterFromPickle(final Pickle pickle) => Counter(pickle.readInt('start'));
copied to clipboard
With this, we won't have the nice integration support for nested Pickles, but we can still create Pickles and restore
a Counter to a previous state:
void main() {
var counter = Counter();
print(counter.countUp());
var pickle = counterToPickle(counter);
print(counter.countUp());
counter = counterFromPickle(pickle);
print(counter.countUp());
}
copied to clipboard
And, of course, we can still implement a Version class that makes use of these methods for nested Pickling:
class Version implements Pickleable {
final Counter _counter;
Version() : _counter = Counter();
Version._(final this.counter);
String nextVersion() => 'v${_counter.countUp()}';
@override
Pickle toPickle() => PickleBuilder().withPickle('counter', counterToPickle(_counter)).build();
static Version fromPickle(final Pickle pickle) => Version._(pickleToCounter(pickle.readPickle('counter')));
}
copied to clipboard
Choose the right level of integration for your project, and have fun!
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.