use crate::util::{Error, Hash256, Result, Serializable};
use std::io;
use std::io::{Read, Write};
#[cfg(feature = "async")]
use tokio::io::{AsyncRead, AsyncWrite};
pub const COINBASE_OUTPOINT_HASH: Hash256 = Hash256([0; 32]);
pub const COINBASE_OUTPOINT_INDEX: u32 = 0xffffffff;
#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
pub struct OutPoint {
pub hash: Hash256,
pub index: u32,
}
impl OutPoint {
pub const SIZE: usize = 36;
#[must_use]
#[inline]
pub fn size(&self) -> usize {
Self::SIZE
}
}
impl Serializable<OutPoint> for OutPoint {
fn read(reader: &mut dyn Read) -> Result<OutPoint> {
let mut hash_bytes = [0u8; 32];
reader
.read_exact(&mut hash_bytes)
.map_err(|e| Error::IOError(e))?;
let hash = Hash256(hash_bytes);
let mut index = [0u8; 4];
reader
.read_exact(&mut index)
.map_err(|e| Error::IOError(e))?;
let index = u32::from_le_bytes(index);
Ok(OutPoint { hash, index })
}
fn write(&self, writer: &mut dyn Write) -> io::Result<()> {
writer.write_all(&self.hash.0)?;
writer.write_all(&self.index.to_le_bytes())
}
}
#[cfg(feature = "async")]
impl AsyncSerializable<OutPoint> for OutPoint {
async fn read_async(reader: &mut dyn AsyncRead) -> Result<OutPoint> {
let mut hash_bytes = [0u8; 32];
reader
.read_exact(&mut hash_bytes)
.await
.map_err(|e| Error::IOError(e))?;
let hash = Hash256(hash_bytes);
let mut index = [0u8; 4];
reader
.read_exact(&mut index)
.await
.map_err(|e| Error::IOError(e))?;
let index = u32::from_le_bytes(index);
Ok(OutPoint { hash, index })
}
async fn write_async(&self, writer: &mut dyn AsyncWrite) -> io::Result<()> {
writer.write_all(&self.hash.0).await?;
writer.write_all(&self.index.to_le_bytes()).await
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use std::io::Cursor;
#[test]
fn write_read() {
let mut v = Vec::new();
let hash_bytes = [0x12u8; 32]; let t = OutPoint {
hash: Hash256(hash_bytes),
index: 0,
};
t.write(&mut v).unwrap();
assert_eq!(v.len(), t.size());
assert_eq!(OutPoint::read(&mut Cursor::new(&v)).unwrap(), t);
}
#[test]
fn coinbase() {
let mut v = Vec::new();
let t = OutPoint {
hash: COINBASE_OUTPOINT_HASH,
index: COINBASE_OUTPOINT_INDEX,
};
t.write(&mut v).unwrap();
assert_eq!(v.len(), t.size());
assert_eq!(OutPoint::read(&mut Cursor::new(&v)).unwrap(), t);
}
}