use std::{io, net::Ipv6Addr};
use super::{AtLeastOne, CompactSizeMessage};
pub const MAX_PROTOCOL_MESSAGE_LEN: usize = 2 * 1024 * 1024;
pub trait ZcashSerialize: Sized {
fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), io::Error>;
fn zcash_serialize_to_vec(&self) -> Result<Vec<u8>, io::Error> {
let mut data = Vec::new();
self.zcash_serialize(&mut data)?;
Ok(data)
}
fn zcash_serialized_size(&self) -> usize {
let mut writer = FakeWriter(0);
self.zcash_serialize(&mut writer)
.expect("writer should never fail");
writer.0
}
}
pub struct FakeWriter(pub usize);
impl std::io::Write for FakeWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.0 += buf.len();
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl<T: ZcashSerialize> ZcashSerialize for Vec<T> {
#[allow(clippy::unwrap_in_result)]
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
let len: CompactSizeMessage = self
.len()
.try_into()
.expect("len fits in MAX_PROTOCOL_MESSAGE_LEN");
len.zcash_serialize(&mut writer)?;
zcash_serialize_external_count(self, writer)
}
}
impl<T: ZcashSerialize> ZcashSerialize for AtLeastOne<T> {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
self.as_vec().zcash_serialize(&mut writer)
}
}
#[allow(clippy::ptr_arg)]
pub fn zcash_serialize_bytes<W: io::Write>(vec: &Vec<u8>, mut writer: W) -> Result<(), io::Error> {
CompactSizeMessage::try_from(vec.len())?.zcash_serialize(&mut writer)?;
zcash_serialize_bytes_external_count(vec, writer)
}
pub fn zcash_serialize_empty_list<W: io::Write>(writer: W) -> Result<(), io::Error> {
CompactSizeMessage::default().zcash_serialize(writer)
}
#[allow(clippy::ptr_arg)]
pub fn zcash_serialize_external_count<W: io::Write, T: ZcashSerialize>(
vec: &Vec<T>,
mut writer: W,
) -> Result<(), io::Error> {
for x in vec {
x.zcash_serialize(&mut writer)?;
}
Ok(())
}
#[allow(clippy::ptr_arg)]
pub fn zcash_serialize_bytes_external_count<W: io::Write>(
vec: &Vec<u8>,
mut writer: W,
) -> Result<(), io::Error> {
writer.write_all(vec)
}
impl ZcashSerialize for &str {
fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), io::Error> {
let str_bytes = self.as_bytes().to_vec();
zcash_serialize_bytes(&str_bytes, writer)
}
}
impl ZcashSerialize for String {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
self.as_str().zcash_serialize(&mut writer)
}
}
impl ZcashSerialize for Ipv6Addr {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), std::io::Error> {
writer.write_all(&self.octets())
}
}