use std::{io, net::Ipv6Addr, sync::Arc};
use super::{AtLeastOne, CompactSizeMessage, SerializationError, MAX_PROTOCOL_MESSAGE_LEN};
pub trait ZcashDeserialize: Sized {
fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError>;
}
impl<T: ZcashDeserialize + TrustedPreallocate> ZcashDeserialize for Vec<T> {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let len: CompactSizeMessage = (&mut reader).zcash_deserialize_into()?;
zcash_deserialize_external_count(len.into(), reader)
}
}
impl<T: ZcashDeserialize + TrustedPreallocate> ZcashDeserialize for AtLeastOne<T> {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let v: Vec<T> = (&mut reader).zcash_deserialize_into()?;
let at_least_one: AtLeastOne<T> = v.try_into()?;
Ok(at_least_one)
}
}
impl ZcashDeserialize for Vec<u8> {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let len: CompactSizeMessage = (&mut reader).zcash_deserialize_into()?;
zcash_deserialize_bytes_external_count(len.into(), reader)
}
}
pub fn zcash_deserialize_external_count<R: io::Read, T: ZcashDeserialize + TrustedPreallocate>(
external_count: usize,
mut reader: R,
) -> Result<Vec<T>, SerializationError> {
match u64::try_from(external_count) {
Ok(external_count) if external_count > T::max_allocation() => {
return Err(SerializationError::Parse(
"Vector longer than max_allocation",
))
}
Ok(_) => {}
Err(_) => return Err(SerializationError::Parse("Vector longer than u64::MAX")),
}
let mut vec = Vec::with_capacity(external_count);
for _ in 0..external_count {
vec.push(T::zcash_deserialize(&mut reader)?);
}
Ok(vec)
}
pub fn zcash_deserialize_bytes_external_count<R: io::Read>(
external_count: usize,
mut reader: R,
) -> Result<Vec<u8>, SerializationError> {
if external_count > MAX_U8_ALLOCATION {
return Err(SerializationError::Parse(
"Byte vector longer than MAX_U8_ALLOCATION",
));
}
let mut vec = vec![0u8; external_count];
reader.read_exact(&mut vec)?;
Ok(vec)
}
pub fn zcash_deserialize_string_external_count<R: io::Read>(
external_byte_count: usize,
reader: R,
) -> Result<String, SerializationError> {
let bytes = zcash_deserialize_bytes_external_count(external_byte_count, reader)?;
String::from_utf8(bytes).map_err(|_| SerializationError::Parse("invalid utf-8"))
}
impl ZcashDeserialize for String {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let byte_count: CompactSizeMessage = (&mut reader).zcash_deserialize_into()?;
zcash_deserialize_string_external_count(byte_count.into(), reader)
}
}
impl ZcashDeserialize for Ipv6Addr {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let mut ipv6_addr = [0u8; 16];
reader.read_exact(&mut ipv6_addr)?;
Ok(Ipv6Addr::from(ipv6_addr))
}
}
pub trait ZcashDeserializeInto {
fn zcash_deserialize_into<T>(self) -> Result<T, SerializationError>
where
T: ZcashDeserialize;
}
impl<R: io::Read> ZcashDeserializeInto for R {
fn zcash_deserialize_into<T>(self) -> Result<T, SerializationError>
where
T: ZcashDeserialize,
{
T::zcash_deserialize(self)
}
}
pub trait TrustedPreallocate {
fn max_allocation() -> u64;
}
impl<T> TrustedPreallocate for Arc<T>
where
T: TrustedPreallocate,
{
fn max_allocation() -> u64 {
T::max_allocation()
}
}
pub(crate) const MAX_U8_ALLOCATION: usize = MAX_PROTOCOL_MESSAGE_LEN - 5;