I also had to bring packet serialization/deserialization
back out of PacketFormat so that I could make it a trait object
in the connection (before it was generic over PacketMap).
However, now that Connection abstracts over PacketFormat,
it actually reduced code duplication to do so.
I also reorganized the hierarchy a bit, moving packet formats
under the connection module and most other things under the
protocol module.
* Fixed cli.yml, which was blatently broken previously.
* Split PacketData into PacketReadable and PacketWritable,
which allows implementing PacketWritable for un-owned types
(for example, &str and &[u8]).
* Added impl_packet_data_for_num! and impl_varnum!
which makes defining packet serialization
for the numbers very concise.
* Added define_packet! macro which
makes defining packets easy and much less tedious.
* Added ProtocolState macro which encapsulates
packet enums and packet ids into a single unit.
* Added define_packet! macro which makes
defining protocol states trivial
(it's just a simple id/packet mapping).
* Made packet serialization/deserialization part of PacketFormat,
which massively simplifies the API.
It took a while to get the hang of this all,
but the more I use Rust, the more I love it.
* Packet header/stream stuff is now defined by a PacketFormat.
* Actual packet serialization/deserialization is handled by
PacketSerializer/PacketDeserializer.
* The end API is still awkaward, so more work is needed.