Overhaul serialization/deserialization mechanism

Instead of writing tons of `from_channel` and `to_channel` code, still
leaving room for programming errors, use an interpreted system, where
for every `('req, 'res) t` in a `Protocol`, a value-level representation
of `'req` and `'res` must be provided, and an interpreter for such
values.