use std::fmt;
use std::io::{Read, Write};
use error::Error;
use hex::Hexed;
use ser;
const TAG_SIZE: usize = 8;
const MAX_URI_LEN: usize = 1000;
const BITCOIN_TAG: &'static [u8] = b"\x05\x88\x96\x0d\x73\xd7\x19\x01";
const PENDING_TAG: &'static [u8] = b"\x83\xdf\xe3\x0d\x2e\xf9\x0c\x8e";
#[allow(missing_docs)]
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Attestation {
Bitcoin {
height: usize
},
Pending {
uri: String
},
Unknown {
tag: Vec<u8>,
data: Vec<u8>
}
}
impl Attestation {
pub fn deserialize<R: Read>(deser: &mut ser::Deserializer<R>) -> Result<Attestation, Error> {
let tag = deser.read_fixed_bytes(TAG_SIZE)?;
let len = deser.read_uint()?;
if tag == BITCOIN_TAG {
let height = deser.read_uint()?;
Ok(Attestation::Bitcoin {
height: height
})
} else if tag == PENDING_TAG {
let uri_bytes = deser.read_bytes(0, MAX_URI_LEN)?;
let uri_string = String::from_utf8(uri_bytes)?;
for ch in uri_string.chars() {
match ch {
'a'...'z' => {}
'A'...'Z' => {}
'0'...'9' => {}
'.' | '-' | '_' | '/' | ':' => {},
x => return Err(Error::InvalidUriChar(x))
}
}
Ok(Attestation::Pending {
uri: uri_string
})
} else {
Ok(Attestation::Unknown {
tag: tag,
data: deser.read_fixed_bytes(len)?
})
}
}
pub fn serialize<W: Write>(&self, ser: &mut ser::Serializer<W>) -> Result<(), Error> {
let mut byte_ser = ser::Serializer::new(vec![]);
match *self {
Attestation::Bitcoin { height } => {
ser.write_fixed_bytes(BITCOIN_TAG)?;
byte_ser.write_uint(height)?;
ser.write_bytes(&byte_ser.into_inner())
}
Attestation::Pending { ref uri } => {
ser.write_fixed_bytes(PENDING_TAG)?;
byte_ser.write_bytes(uri.as_bytes())?;
ser.write_bytes(&byte_ser.into_inner())
}
Attestation::Unknown { ref tag, ref data } => {
ser.write_fixed_bytes(tag)?;
ser.write_bytes(data)
}
}
}
}
impl fmt::Display for Attestation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Attestation::Bitcoin { height } => write!(f, "Bitcoin block {}", height),
Attestation::Pending { ref uri } => write!(f, "Pending: update URI {}", uri),
Attestation::Unknown { ref tag, ref data } => write!(f, "unknown attestation type {}: {}", Hexed(tag), Hexed(data)),
}
}
}