core/ser: change serialization trait to use Result<(), Error> in place of Option<Error>

This commit is contained in:
Merope Riddle 2016-10-31 22:17:53 +00:00
parent 3ffc2f5d8c
commit bc38016385
5 changed files with 104 additions and 81 deletions

View file

@ -60,7 +60,7 @@ impl Default for BlockHeader {
// Only Writeable implementation is required for hashing, which is part of
// core. Readable is in the ser package.
impl Writeable for BlockHeader {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
ser_multiwrite!(writer,
[write_u64, self.height],
[write_fixed_bytes, &self.previous],
@ -70,10 +70,10 @@ impl Writeable for BlockHeader {
[write_u64, self.total_fees]);
// make sure to not introduce any variable length data before the nonce to
// avoid complicating PoW
try_o!(writer.write_u64(self.nonce));
try!(writer.write_u64(self.nonce));
// cuckoo cycle of 42 nodes
for n in 0..42 {
try_o!(writer.write_u32(self.pow.0[n]));
try!(writer.write_u32(self.pow.0[n]));
}
writer.write_u64(self.td)
}
@ -101,23 +101,23 @@ pub struct Block {
/// Implementation of Writeable for a block, defines how to write the full
/// block as binary.
impl Writeable for Block {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
try_o!(self.header.write(writer));
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try!(self.header.write(writer));
ser_multiwrite!(writer,
[write_u64, self.inputs.len() as u64],
[write_u64, self.outputs.len() as u64],
[write_u64, self.proofs.len() as u64]);
for inp in &self.inputs {
try_o!(inp.write(writer));
try!(inp.write(writer));
}
for out in &self.outputs {
try_o!(out.write(writer));
try!(out.write(writer));
}
for proof in &self.proofs {
try_o!(proof.write(writer));
try!(proof.write(writer));
}
None
Ok(())
}
}

View file

@ -39,8 +39,8 @@ pub struct TxProof {
}
impl Writeable for TxProof {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
try_o!(writer.write_fixed_bytes(&self.remainder));
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try!(writer.write_fixed_bytes(&self.remainder));
writer.write_vec(&mut self.sig.clone())
}
}
@ -68,19 +68,19 @@ pub struct Transaction {
/// Implementation of Writeable for a fully blinded transaction, defines how to
/// write the transaction as binary.
impl Writeable for Transaction {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
ser_multiwrite!(writer,
[write_u64, self.fee],
[write_vec, &mut self.zerosig.clone()],
[write_u64, self.inputs.len() as u64],
[write_u64, self.outputs.len() as u64]);
for inp in &self.inputs {
try_o!(inp.write(writer));
try!(inp.write(writer));
}
for out in &self.outputs {
try_o!(out.write(writer));
try!(out.write(writer));
}
None
Ok(())
}
}
@ -235,7 +235,7 @@ pub enum Input {
/// Implementation of Writeable for a transaction Input, defines how to write
/// an Input as binary.
impl Writeable for Input {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
writer.write_fixed_bytes(&self.output_hash())
}
}
@ -302,8 +302,8 @@ pub enum Output {
/// Implementation of Writeable for a transaction Output, defines how to write
/// an Output as binary.
impl Writeable for Output {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
try_o!(writer.write_fixed_bytes(&self.commitment().unwrap()));
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try!(writer.write_fixed_bytes(&self.commitment().unwrap()));
writer.write_vec(&mut self.proof().unwrap().bytes().to_vec())
}
}
@ -407,9 +407,7 @@ mod test {
let tx = tx2i1o(secp, &mut rng);
let btx = tx.blind(&secp).unwrap();
let mut vec = Vec::new();
if let Some(e) = serialize(&mut vec, &btx) {
panic!(e);
}
serialize(&mut vec, &btx).expect("serialized failed");
assert!(vec.len() > 5320);
assert!(vec.len() < 5340);
}
@ -422,9 +420,7 @@ mod test {
let tx = tx2i1o(secp, &mut rng);
let mut btx = tx.blind(&secp).unwrap();
let mut vec = Vec::new();
if let Some(e) = serialize(&mut vec, &btx) {
panic!(e);
}
serialize(&mut vec, &btx).expect("serialization failed");
// let mut dtx = Transaction::read(&mut BinReader { source: &mut &vec[..]
// }).unwrap();
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
@ -444,11 +440,11 @@ mod test {
let mut btx = tx.blind(&secp).unwrap();
let mut vec = Vec::new();
assert!(serialize(&mut vec, &btx).is_none());
assert!(serialize(&mut vec, &btx).is_ok());
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
let mut vec2 = Vec::new();
assert!(serialize(&mut vec2, &btx).is_none());
assert!(serialize(&mut vec2, &btx).is_ok());
let mut dtx2: Transaction = deserialize(&mut &vec2[..]).unwrap();
assert_eq!(btx.hash(), dtx.hash());

View file

@ -61,19 +61,6 @@ macro_rules! tee {
}
}
/// Simple equivalent of try! but for an Option<Error>. Motivated mostly by the
/// io package and our serialization as an alternative to silly Result<(),
/// Error>.
#[macro_export]
macro_rules! try_o {
($trying:expr) => {
let tried = $trying;
if let Some(_) = tried {
return tried;
}
}
}
#[macro_export]
macro_rules! try_to_o {
($trying:expr) => {{
@ -109,6 +96,6 @@ macro_rules! ser_multiread {
#[macro_export]
macro_rules! ser_multiwrite {
($wrtr:ident, $([ $write_call:ident, $val:expr ]),* ) => {
$( try_o!($wrtr.$write_call($val)) );*
$( try!($wrtr.$write_call($val)) );*
}
}

View file

@ -71,16 +71,16 @@ struct PowHeader {
/// the data that gets hashed for PoW calculation. The nonce is written first
/// to make incrementing from the serialized form trivial.
impl Writeable for PowHeader {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
try_o!(writer.write_u64(self.nonce));
try_o!(writer.write_u64(self.height));
try_o!(writer.write_fixed_bytes(&self.previous));
try_o!(writer.write_i64(self.timestamp.to_timespec().sec));
try_o!(writer.write_fixed_bytes(&self.utxo_merkle));
try_o!(writer.write_fixed_bytes(&self.tx_merkle));
try_o!(writer.write_u64(self.total_fees));
try_o!(writer.write_u64(self.n_in));
try_o!(writer.write_u64(self.n_out));
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try!(writer.write_u64(self.nonce));
try!(writer.write_u64(self.height));
try!(writer.write_fixed_bytes(&self.previous));
try!(writer.write_i64(self.timestamp.to_timespec().sec));
try!(writer.write_fixed_bytes(&self.utxo_merkle));
try!(writer.write_fixed_bytes(&self.tx_merkle));
try!(writer.write_u64(self.total_fees));
try!(writer.write_u64(self.n_in));
try!(writer.write_u64(self.n_out));
writer.write_u64(self.n_proofs)
}
}

View file

@ -19,8 +19,8 @@
//! To use it simply implement `Writeable` or `Readable` and then use the
//! `serialize` or `deserialize` functions on them as appropriate.
use std::io;
use std::io::{Write, Read};
use std::{error, fmt};
use std::io::{self, Write, Read};
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
/// Possible errors deriving from serializing or deserializing.
@ -33,12 +33,47 @@ pub enum Error {
expected: Vec<u8>,
received: Vec<u8>,
},
/// Data wasn't in a consumable format
CorruptedData,
/// Data wasn't in a consumable format
CorruptedData,
/// When asked to read too much data
TooLargeReadErr(String),
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Error {
Error::IOErr(e)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::IOErr(ref e) => write!(f, "{}", e),
Error::UnexpectedData { expected: ref e, received: ref r } => write!(f, "expected {:?}, got {:?}", e, r),
Error::CorruptedData => f.write_str("corrupted data"),
Error::TooLargeReadErr(ref s) => f.write_str(&s)
}
}
}
impl error::Error for Error {
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::IOErr(ref e) => Some(e),
_ => None
}
}
fn description(&self) -> &str {
match *self {
Error::IOErr(ref e) => error::Error::description(e),
Error::UnexpectedData { expected: _, received: _ } => "unexpected data",
Error::CorruptedData => "corrupted data",
Error::TooLargeReadErr(ref s) => s
}
}
}
/// Useful trait to implement on types that can be translated to byte slices
/// directly. Allows the use of `write_fixed_bytes` on them.
pub trait AsFixedBytes {
@ -50,21 +85,21 @@ pub trait AsFixedBytes {
/// written to an underlying stream or container (depending on implementation).
pub trait Writer {
/// Writes a u8 as bytes
fn write_u8(&mut self, n: u8) -> Option<Error>;
fn write_u8(&mut self, n: u8) -> Result<(), Error>;
/// Writes a u16 as bytes
fn write_u16(&mut self, n: u16) -> Option<Error>;
fn write_u16(&mut self, n: u16) -> Result<(), Error>;
/// Writes a u32 as bytes
fn write_u32(&mut self, n: u32) -> Option<Error>;
fn write_u32(&mut self, n: u32) -> Result<(), Error>;
/// Writes a u64 as bytes
fn write_u64(&mut self, n: u64) -> Option<Error>;
fn write_u64(&mut self, n: u64) -> Result<(), Error>;
/// Writes a i64 as bytes
fn write_i64(&mut self, n: i64) -> Option<Error>;
fn write_i64(&mut self, n: i64) -> Result<(), Error>;
/// Writes a variable length `Vec`, the length of the `Vec` is encoded as a
/// prefix.
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Option<Error>;
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Result<(), Error>;
/// Writes a fixed number of bytes from something that can turn itself into
/// a `&[u8]`. The reader is expected to know the actual length on read.
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Option<Error>;
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Result<(), Error>;
}
/// Implementations defined how different numbers and binary structures are
@ -98,7 +133,7 @@ pub trait Reader {
/// underlying Write implementation.
pub trait Writeable {
/// Write the data held by this Writeable to the provided writer
fn write(&self, writer: &mut Writer) -> Option<Error>;
fn write(&self, writer: &mut Writer) -> Result<(), Error>;
}
/// Trait that every type that can be deserialized from binary must implement.
@ -116,7 +151,7 @@ pub fn deserialize<T: Readable<T>>(mut source: &mut Read) -> Result<T, Error> {
}
/// Serializes a Writeable into any std::io::Write implementation.
pub fn serialize(mut sink: &mut Write, thing: &Writeable) -> Option<Error> {
pub fn serialize(mut sink: &mut Write, thing: &Writeable) -> Result<(), Error> {
let mut writer = BinWriter { sink: sink };
thing.write(&mut writer)
}
@ -125,9 +160,7 @@ pub fn serialize(mut sink: &mut Write, thing: &Writeable) -> Option<Error> {
/// Vec<u8>.
pub fn ser_vec(thing: &Writeable) -> Result<Vec<u8>, Error> {
let mut vec = Vec::new();
if let Some(err) = serialize(&mut vec, thing) {
return Err(err);
}
try!(serialize(&mut vec, thing));
Ok(vec)
}
@ -192,33 +225,40 @@ struct BinWriter<'a> {
}
impl<'a> Writer for BinWriter<'a> {
fn write_u8(&mut self, n: u8) -> Option<Error> {
self.sink.write_u8(n).err().map(Error::IOErr)
fn write_u8(&mut self, n: u8) -> Result<(), Error> {
try!(self.sink.write_u8(n));
Ok(())
}
fn write_u16(&mut self, n: u16) -> Option<Error> {
self.sink.write_u16::<BigEndian>(n).err().map(Error::IOErr)
fn write_u16(&mut self, n: u16) -> Result<(), Error> {
try!(self.sink.write_u16::<BigEndian>(n));
Ok(())
}
fn write_u32(&mut self, n: u32) -> Option<Error> {
self.sink.write_u32::<BigEndian>(n).err().map(Error::IOErr)
fn write_u32(&mut self, n: u32) -> Result<(), Error> {
try!(self.sink.write_u32::<BigEndian>(n));
Ok(())
}
fn write_u64(&mut self, n: u64) -> Option<Error> {
self.sink.write_u64::<BigEndian>(n).err().map(Error::IOErr)
fn write_u64(&mut self, n: u64) -> Result<(), Error> {
try!(self.sink.write_u64::<BigEndian>(n));
Ok(())
}
fn write_i64(&mut self, n: i64) -> Option<Error> {
self.sink.write_i64::<BigEndian>(n).err().map(Error::IOErr)
fn write_i64(&mut self, n: i64) -> Result<(), Error> {
try!(self.sink.write_i64::<BigEndian>(n));
Ok(())
}
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Option<Error> {
try_o!(self.write_u64(vec.len() as u64));
self.sink.write_all(vec).err().map(Error::IOErr)
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Result<(), Error> {
try!(self.write_u64(vec.len() as u64));
try!(self.sink.write_all(vec));
Ok(())
}
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Option<Error> {
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Result<(), Error> {
let bs = b32.as_fixed_bytes();
self.sink.write_all(bs).err().map(Error::IOErr)
try!(self.sink.write_all(bs));
Ok(())
}
}