X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fser.rs;h=6a52e5e1c898230c0d31a4cb9ce20c6acc236076;hb=f49662caa4a9cb845ae1451b0baf85b80b8dc711;hp=1d24e26408fba830603cb3f95b9b4bbd20354d57;hpb=75d71cead386cac3c42a6c4d4f204869ec8dacc5;p=rust-lightning diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index 1d24e264..6a52e5e1 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -10,76 +10,72 @@ //! A very simple serialization framework which is used to serialize/deserialize messages as well //! as ChannelsManagers and ChannelMonitors. -use std::io::{Read, Write}; -use std::collections::HashMap; -use std::hash::Hash; -use std::sync::Mutex; -use std::cmp; +use prelude::*; +use io::{self, Read, Write}; +use io_extras::{copy, sink}; +use core::hash::Hash; +use sync::Mutex; +use core::cmp; use bitcoin::secp256k1::Signature; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; +use bitcoin::secp256k1::constants::{PUBLIC_KEY_SIZE, SECRET_KEY_SIZE, COMPACT_SIGNATURE_SIZE}; use bitcoin::blockdata::script::Script; use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut}; use bitcoin::consensus; use bitcoin::consensus::Encodable; use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hash_types::{Txid, BlockHash}; -use std::marker::Sized; +use core::marker::Sized; +use core::time::Duration; use ln::msgs::DecodeError; -use ln::channelmanager::{PaymentPreimage, PaymentHash, PaymentSecret}; -use util::byte_utils; +use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; -use util::byte_utils::{be64_to_array, be48_to_array, be32_to_array, be16_to_array, slice_to_be16, slice_to_be32, slice_to_be48, slice_to_be64}; +use util::byte_utils::{be48_to_array, slice_to_be48}; /// serialization buffer size pub const MAX_BUF_SIZE: usize = 64 * 1024; -/// A trait that is similar to std::io::Write but has one extra function which can be used to size -/// buffers being written into. -/// An impl is provided for any type that also impls std::io::Write which simply ignores size -/// hints. +/// A simplified version of std::io::Write that exists largely for backwards compatibility. +/// An impl is provided for any type that also impls std::io::Write. /// /// (C-not exported) as we only export serialization to/from byte arrays instead pub trait Writer { /// Writes the given buf out. See std::io::Write::write_all for more - fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error>; - /// Hints that data of the given size is about the be written. This may not always be called - /// prior to data being written and may be safely ignored. - fn size_hint(&mut self, size: usize); + fn write_all(&mut self, buf: &[u8]) -> Result<(), io::Error>; } impl Writer for W { #[inline] - fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> { - ::write_all(self, buf) + fn write_all(&mut self, buf: &[u8]) -> Result<(), io::Error> { + ::write_all(self, buf) } - #[inline] - fn size_hint(&mut self, _size: usize) { } } pub(crate) struct WriterWriteAdaptor<'a, W: Writer + 'a>(pub &'a mut W); impl<'a, W: Writer + 'a> Write for WriterWriteAdaptor<'a, W> { - fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> { + #[inline] + fn write_all(&mut self, buf: &[u8]) -> Result<(), io::Error> { self.0.write_all(buf) } - fn write(&mut self, buf: &[u8]) -> Result { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { self.0.write_all(buf)?; Ok(buf.len()) } - fn flush(&mut self) -> Result<(), ::std::io::Error> { + #[inline] + fn flush(&mut self) -> Result<(), io::Error> { Ok(()) } } pub(crate) struct VecWriter(pub Vec); impl Writer for VecWriter { - fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> { + #[inline] + fn write_all(&mut self, buf: &[u8]) -> Result<(), io::Error> { self.0.extend_from_slice(buf); Ok(()) } - fn size_hint(&mut self, size: usize) { - self.0.reserve_exact(size); - } } /// Writer that only tracks the amount of data written - useful if you need to calculate the length @@ -87,12 +83,10 @@ impl Writer for VecWriter { pub(crate) struct LengthCalculatingWriter(pub usize); impl Writer for LengthCalculatingWriter { #[inline] - fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> { + fn write_all(&mut self, buf: &[u8]) -> Result<(), io::Error> { self.0 += buf.len(); Ok(()) } - #[inline] - fn size_hint(&mut self, _size: usize) {} } /// Essentially std::io::Take but a bit simpler and with a method to walk the underlying stream @@ -107,12 +101,14 @@ impl FixedLengthReader { Self { read, bytes_read: 0, total_bytes } } + #[inline] pub fn bytes_remain(&mut self) -> bool { self.bytes_read != self.total_bytes } + #[inline] pub fn eat_remaining(&mut self) -> Result<(), DecodeError> { - ::std::io::copy(self, &mut ::std::io::sink()).unwrap(); + copy(self, &mut sink()).unwrap(); if self.bytes_read != self.total_bytes { Err(DecodeError::ShortRead) } else { @@ -121,7 +117,8 @@ impl FixedLengthReader { } } impl Read for FixedLengthReader { - fn read(&mut self, dest: &mut [u8]) -> Result { + #[inline] + fn read(&mut self, dest: &mut [u8]) -> Result { if self.total_bytes == self.bytes_read { Ok(0) } else { @@ -149,7 +146,8 @@ impl ReadTrackingReader { } } impl Read for ReadTrackingReader { - fn read(&mut self, dest: &mut [u8]) -> Result { + #[inline] + fn read(&mut self, dest: &mut [u8]) -> Result { match self.read.read(dest) { Ok(0) => Ok(0), Ok(len) => { @@ -166,7 +164,7 @@ impl Read for ReadTrackingReader { /// (C-not exported) as we only export serialization to/from byte arrays instead pub trait Writeable { /// Writes self out to the given Writer - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error>; + fn write(&self, writer: &mut W) -> Result<(), io::Error>; /// Writes self out to a Vec fn encode(&self) -> Vec { @@ -181,13 +179,23 @@ pub trait Writeable { 0u16.write(&mut msg).unwrap(); self.write(&mut msg).unwrap(); let len = msg.0.len(); - msg.0[..2].copy_from_slice(&byte_utils::be16_to_array(len as u16 - 2)); + msg.0[..2].copy_from_slice(&(len as u16 - 2).to_be_bytes()); msg.0 } + + /// Gets the length of this object after it has been serialized. This can be overridden to + /// optimize cases where we prepend an object with its length. + // Note that LLVM optimizes this away in most cases! Check that it isn't before you override! + #[inline] + fn serialized_length(&self) -> usize { + let mut len_calc = LengthCalculatingWriter(0); + self.write(&mut len_calc).expect("No in-memory data may fail to serialize"); + len_calc.0 + } } impl<'a, T: Writeable> Writeable for &'a T { - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { (*self).write(writer) } + fn write(&self, writer: &mut W) -> Result<(), io::Error> { (*self).write(writer) } } /// A trait that various rust-lightning types implement allowing them to be read in from a Read @@ -221,10 +229,58 @@ pub trait MaybeReadable fn read(reader: &mut R) -> Result, DecodeError>; } +impl MaybeReadable for T { + #[inline] + fn read(reader: &mut R) -> Result, DecodeError> { + Ok(Some(Readable::read(reader)?)) + } +} + +pub(crate) struct OptionDeserWrapper(pub Option); +impl Readable for OptionDeserWrapper { + #[inline] + fn read(reader: &mut R) -> Result { + Ok(Self(Some(Readable::read(reader)?))) + } +} + +/// Wrapper to write each element of a Vec with no length prefix +pub(crate) struct VecWriteWrapper<'a, T: Writeable>(pub &'a Vec); +impl<'a, T: Writeable> Writeable for VecWriteWrapper<'a, T> { + #[inline] + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + for ref v in self.0.iter() { + v.write(writer)?; + } + Ok(()) + } +} + +/// Wrapper to read elements from a given stream until it reaches the end of the stream. +pub(crate) struct VecReadWrapper(pub Vec); +impl Readable for VecReadWrapper { + #[inline] + fn read(mut reader: &mut R) -> Result { + let mut values = Vec::new(); + loop { + let mut track_read = ReadTrackingReader::new(&mut reader); + match MaybeReadable::read(&mut track_read) { + Ok(Some(v)) => { values.push(v); }, + Ok(None) => { }, + // If we failed to read any bytes at all, we reached the end of our TLV + // stream and have simply exhausted all entries. + Err(ref e) if e == &DecodeError::ShortRead && !track_read.have_read => break, + Err(e) => return Err(e), + } + } + Ok(Self(values)) + } +} + pub(crate) struct U48(pub u64); impl Writeable for U48 { #[inline] - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { writer.write_all(&be48_to_array(self.0)) } } @@ -247,7 +303,7 @@ impl Readable for U48 { pub(crate) struct BigSize(pub u64); impl Writeable for BigSize { #[inline] - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { match self.0 { 0...0xFC => { (self.0 as u8).write(writer) @@ -308,18 +364,18 @@ impl Readable for BigSize { pub(crate) struct HighZeroBytesDroppedVarInt(pub T); macro_rules! impl_writeable_primitive { - ($val_type:ty, $meth_write:ident, $len: expr, $meth_read:ident) => { + ($val_type:ty, $len: expr) => { impl Writeable for $val_type { #[inline] - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { - writer.write_all(&$meth_write(*self)) + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + writer.write_all(&self.to_be_bytes()) } } impl Writeable for HighZeroBytesDroppedVarInt<$val_type> { #[inline] - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { // Skip any full leading 0 bytes when writing (in BE): - writer.write_all(&$meth_write(self.0)[(self.0.leading_zeros()/8) as usize..$len]) + writer.write_all(&self.0.to_be_bytes()[(self.0.leading_zeros()/8) as usize..$len]) } } impl Readable for $val_type { @@ -327,7 +383,7 @@ macro_rules! impl_writeable_primitive { fn read(reader: &mut R) -> Result<$val_type, DecodeError> { let mut buf = [0; $len]; reader.read_exact(&mut buf)?; - Ok($meth_read(&buf)) + Ok(<$val_type>::from_be_bytes(buf)) } } impl Readable for HighZeroBytesDroppedVarInt<$val_type> { @@ -346,7 +402,9 @@ macro_rules! impl_writeable_primitive { } if total_read_len == 0 || buf[$len] != 0 { let first_byte = $len - ($len - total_read_len); - Ok(HighZeroBytesDroppedVarInt($meth_read(&buf[first_byte..first_byte + $len]))) + let mut bytes = [0; $len]; + bytes.copy_from_slice(&buf[first_byte..first_byte + $len]); + Ok(HighZeroBytesDroppedVarInt(<$val_type>::from_be_bytes(bytes))) } else { // If the encoding had extra zero bytes, return a failure even though we know // what they meant (as the TLV test vectors require this) @@ -357,13 +415,13 @@ macro_rules! impl_writeable_primitive { } } -impl_writeable_primitive!(u64, be64_to_array, 8, slice_to_be64); -impl_writeable_primitive!(u32, be32_to_array, 4, slice_to_be32); -impl_writeable_primitive!(u16, be16_to_array, 2, slice_to_be16); +impl_writeable_primitive!(u64, 8); +impl_writeable_primitive!(u32, 4); +impl_writeable_primitive!(u16, 2); impl Writeable for u8 { #[inline] - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { writer.write_all(&[*self]) } } @@ -378,7 +436,7 @@ impl Readable for u8 { impl Writeable for bool { #[inline] - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { writer.write_all(&[if *self {1} else {0}]) } } @@ -400,7 +458,7 @@ macro_rules! impl_array { impl Writeable for [u8; $size] { #[inline] - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { w.write_all(self) } } @@ -417,14 +475,13 @@ macro_rules! impl_array { ); } -//TODO: performance issue with [u8; size] with impl_array!() impl_array!(3); // for rgb impl_array!(4); // for IPv4 -impl_array!(10); // for OnionV2 +impl_array!(12); // for OnionV2 impl_array!(16); // for IPv6 impl_array!(32); // for channel id & hmac -impl_array!(33); // for PublicKey -impl_array!(64); // for Signature +impl_array!(PUBLIC_KEY_SIZE); // for PublicKey +impl_array!(COMPACT_SIGNATURE_SIZE); // for Signature impl_array!(1300); // for OnionPacket.hop_data // HashMap @@ -433,7 +490,7 @@ impl Writeable for HashMap V: Writeable { #[inline] - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { (self.len() as u16).write(w)?; for (key, value) in self.iter() { key.write(w)?; @@ -445,14 +502,50 @@ impl Writeable for HashMap impl Readable for HashMap where K: Readable + Eq + Hash, - V: Readable + V: MaybeReadable { #[inline] fn read(r: &mut R) -> Result { let len: u16 = Readable::read(r)?; let mut ret = HashMap::with_capacity(len as usize); for _ in 0..len { - ret.insert(K::read(r)?, V::read(r)?); + let k = K::read(r)?; + let v_opt = V::read(r)?; + if let Some(v) = v_opt { + if ret.insert(k, v).is_some() { + return Err(DecodeError::InvalidValue); + } + } + } + Ok(ret) + } +} + +// HashSet +impl Writeable for HashSet +where T: Writeable + Eq + Hash +{ + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + (self.len() as u16).write(w)?; + for item in self.iter() { + item.write(w)?; + } + Ok(()) + } +} + +impl Readable for HashSet +where T: Readable + Eq + Hash +{ + #[inline] + fn read(r: &mut R) -> Result { + let len: u16 = Readable::read(r)?; + let mut ret = HashSet::with_capacity(len as usize); + for _ in 0..len { + if !ret.insert(T::read(r)?) { + return Err(DecodeError::InvalidValue) + } } Ok(ret) } @@ -461,7 +554,7 @@ impl Readable for HashMap // Vectors impl Writeable for Vec { #[inline] - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { (self.len() as u16).write(w)?; w.write_all(&self) } @@ -479,7 +572,7 @@ impl Readable for Vec { } impl Writeable for Vec { #[inline] - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { (self.len() as u16).write(w)?; for e in self.iter() { e.write(w)?; @@ -493,19 +586,19 @@ impl Readable for Vec { fn read(r: &mut R) -> Result { let len: u16 = Readable::read(r)?; let byte_size = (len as usize) - .checked_mul(33) + .checked_mul(COMPACT_SIGNATURE_SIZE) .ok_or(DecodeError::BadLengthDescriptor)?; if byte_size > MAX_BUF_SIZE { return Err(DecodeError::BadLengthDescriptor); } let mut ret = Vec::with_capacity(len as usize); - for _ in 0..len { ret.push(Signature::read(r)?); } + for _ in 0..len { ret.push(Readable::read(r)?); } Ok(ret) } } impl Writeable for Script { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { (self.len() as u16).write(w)?; w.write_all(self.as_bytes()) } @@ -521,14 +614,18 @@ impl Readable for Script { } impl Writeable for PublicKey { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { self.serialize().write(w) } + #[inline] + fn serialized_length(&self) -> usize { + PUBLIC_KEY_SIZE + } } impl Readable for PublicKey { fn read(r: &mut R) -> Result { - let buf: [u8; 33] = Readable::read(r)?; + let buf: [u8; PUBLIC_KEY_SIZE] = Readable::read(r)?; match PublicKey::from_slice(&buf) { Ok(key) => Ok(key), Err(_) => return Err(DecodeError::InvalidValue), @@ -537,16 +634,20 @@ impl Readable for PublicKey { } impl Writeable for SecretKey { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { - let mut ser = [0; 32]; + fn write(&self, w: &mut W) -> Result<(), io::Error> { + let mut ser = [0; SECRET_KEY_SIZE]; ser.copy_from_slice(&self[..]); ser.write(w) } + #[inline] + fn serialized_length(&self) -> usize { + SECRET_KEY_SIZE + } } impl Readable for SecretKey { fn read(r: &mut R) -> Result { - let buf: [u8; 32] = Readable::read(r)?; + let buf: [u8; SECRET_KEY_SIZE] = Readable::read(r)?; match SecretKey::from_slice(&buf) { Ok(key) => Ok(key), Err(_) => return Err(DecodeError::InvalidValue), @@ -555,7 +656,7 @@ impl Readable for SecretKey { } impl Writeable for Sha256dHash { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { w.write_all(&self[..]) } } @@ -570,14 +671,18 @@ impl Readable for Sha256dHash { } impl Writeable for Signature { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { self.serialize_compact().write(w) } + #[inline] + fn serialized_length(&self) -> usize { + COMPACT_SIGNATURE_SIZE + } } impl Readable for Signature { fn read(r: &mut R) -> Result { - let buf: [u8; 64] = Readable::read(r)?; + let buf: [u8; COMPACT_SIGNATURE_SIZE] = Readable::read(r)?; match Signature::from_compact(&buf) { Ok(sig) => Ok(sig), Err(_) => return Err(DecodeError::InvalidValue), @@ -586,7 +691,7 @@ impl Readable for Signature { } impl Writeable for PaymentPreimage { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { self.0.write(w) } } @@ -599,7 +704,7 @@ impl Readable for PaymentPreimage { } impl Writeable for PaymentHash { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { self.0.write(w) } } @@ -612,7 +717,7 @@ impl Readable for PaymentHash { } impl Writeable for PaymentSecret { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { self.0.write(w) } } @@ -624,14 +729,24 @@ impl Readable for PaymentSecret { } } +impl Writeable for Box { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + T::write(&**self, w) + } +} + +impl Readable for Box { + fn read(r: &mut R) -> Result { + Ok(Box::new(Readable::read(r)?)) + } +} + impl Writeable for Option { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { match *self { None => 0u8.write(w)?, Some(ref data) => { - let mut len_calc = LengthCalculatingWriter(0); - data.write(&mut len_calc).expect("No in-memory data may fail to serialize"); - BigSize(len_calc.0 as u64 + 1).write(w)?; + BigSize(data.serialized_length() as u64 + 1).write(w)?; data.write(w)?; } } @@ -642,7 +757,8 @@ impl Writeable for Option { impl Readable for Option { fn read(r: &mut R) -> Result { - match BigSize::read(r)?.0 { + let len: BigSize = Readable::read(r)?; + match len.0 { 0 => Ok(None), len => { let mut reader = FixedLengthReader::new(r, len - 1); @@ -653,7 +769,7 @@ impl Readable for Option } impl Writeable for Txid { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { w.write_all(&self[..]) } } @@ -668,7 +784,7 @@ impl Readable for Txid { } impl Writeable for BlockHash { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { w.write_all(&self[..]) } } @@ -683,7 +799,7 @@ impl Readable for BlockHash { } impl Writeable for OutPoint { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { self.txid.write(w)?; self.vout.write(w)?; Ok(()) @@ -704,11 +820,10 @@ impl Readable for OutPoint { macro_rules! impl_consensus_ser { ($bitcoin_type: ty) => { impl Writeable for $bitcoin_type { - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { match self.consensus_encode(WriterWriteAdaptor(writer)) { Ok(_) => Ok(()), - Err(consensus::encode::Error::Io(e)) => Err(e), - Err(_) => panic!("We shouldn't get a consensus::encode::Error unless our Write generated an std::io::Error"), + Err(e) => Err(e), } } } @@ -717,7 +832,7 @@ macro_rules! impl_consensus_ser { fn read(r: &mut R) -> Result { match consensus::encode::Decodable::consensus_decode(r) { Ok(t) => Ok(t), - Err(consensus::encode::Error::Io(ref e)) if e.kind() == ::std::io::ErrorKind::UnexpectedEof => Err(DecodeError::ShortRead), + Err(consensus::encode::Error::Io(ref e)) if e.kind() == io::ErrorKind::UnexpectedEof => Err(DecodeError::ShortRead), Err(consensus::encode::Error::Io(e)) => Err(DecodeError::Io(e.kind())), Err(_) => Err(DecodeError::InvalidValue), } @@ -735,7 +850,7 @@ impl Readable for Mutex { } } impl Writeable for Mutex { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { self.lock().unwrap().write(w) } } @@ -748,8 +863,67 @@ impl Readable for (A, B) { } } impl Writeable for (A, B) { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { self.0.write(w)?; self.1.write(w) } } + +impl Readable for (A, B, C) { + fn read(r: &mut R) -> Result { + let a: A = Readable::read(r)?; + let b: B = Readable::read(r)?; + let c: C = Readable::read(r)?; + Ok((a, b, c)) + } +} +impl Writeable for (A, B, C) { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.0.write(w)?; + self.1.write(w)?; + self.2.write(w) + } +} + +impl Writeable for () { + fn write(&self, _: &mut W) -> Result<(), io::Error> { + Ok(()) + } +} +impl Readable for () { + fn read(_r: &mut R) -> Result { + Ok(()) + } +} + +impl Writeable for String { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + (self.len() as u16).write(w)?; + w.write_all(self.as_bytes()) + } +} +impl Readable for String { + #[inline] + fn read(r: &mut R) -> Result { + let v: Vec = Readable::read(r)?; + let ret = String::from_utf8(v).map_err(|_| DecodeError::InvalidValue)?; + Ok(ret) + } +} + +impl Writeable for Duration { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.as_secs().write(w)?; + self.subsec_nanos().write(w) + } +} +impl Readable for Duration { + #[inline] + fn read(r: &mut R) -> Result { + let secs = Readable::read(r)?; + let nanos = Readable::read(r)?; + Ok(Duration::new(secs, nanos)) + } +}