alloy_network_primitives/
block.rsuse alloy_primitives::B256;
use serde::{Deserialize, Serialize};
use alloc::{vec, vec::Vec};
use core::slice;
use crate::TransactionResponse;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum BlockTransactions<T> {
Full(Vec<T>),
Hashes(Vec<B256>),
Uncle,
}
impl<T> Default for BlockTransactions<T> {
fn default() -> Self {
Self::Hashes(Vec::default())
}
}
impl<T> BlockTransactions<T> {
#[inline]
pub const fn is_hashes(&self) -> bool {
matches!(self, Self::Hashes(_))
}
pub fn as_hashes(&self) -> Option<&[B256]> {
match self {
Self::Hashes(hashes) => Some(hashes),
_ => None,
}
}
#[inline]
pub const fn is_full(&self) -> bool {
matches!(self, Self::Full(_))
}
pub fn as_transactions(&self) -> Option<&[T]> {
match self {
Self::Full(txs) => Some(txs),
_ => None,
}
}
#[inline]
pub const fn is_uncle(&self) -> bool {
matches!(self, Self::Uncle)
}
#[doc(alias = "transactions")]
pub fn txns(&self) -> impl Iterator<Item = &T> {
self.as_transactions().map(|txs| txs.iter()).unwrap_or_else(|| [].iter())
}
pub fn into_transactions(self) -> vec::IntoIter<T> {
match self {
Self::Full(txs) => txs.into_iter(),
_ => vec::IntoIter::default(),
}
}
#[inline]
pub const fn uncle() -> Self {
Self::Uncle
}
#[inline]
pub fn len(&self) -> usize {
match self {
Self::Hashes(h) => h.len(),
Self::Full(f) => f.len(),
Self::Uncle => 0,
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<T: TransactionResponse> BlockTransactions<T> {
#[inline]
pub fn convert_to_hashes(&mut self) {
if !self.is_hashes() {
*self = Self::Hashes(self.hashes().collect());
}
}
#[inline]
pub fn into_hashes(mut self) -> Self {
self.convert_to_hashes();
self
}
#[deprecated = "use `hashes` instead"]
#[inline]
pub fn iter(&self) -> BlockTransactionHashes<'_, T> {
self.hashes()
}
#[inline]
pub fn hashes(&self) -> BlockTransactionHashes<'_, T> {
BlockTransactionHashes::new(self)
}
}
impl<T> From<Vec<B256>> for BlockTransactions<T> {
fn from(hashes: Vec<B256>) -> Self {
Self::Hashes(hashes)
}
}
impl<T: TransactionResponse> From<Vec<T>> for BlockTransactions<T> {
fn from(transactions: Vec<T>) -> Self {
Self::Full(transactions)
}
}
#[derive(Clone, Debug)]
pub struct BlockTransactionHashes<'a, T>(BlockTransactionHashesInner<'a, T>);
#[derive(Clone, Debug)]
enum BlockTransactionHashesInner<'a, T> {
Hashes(slice::Iter<'a, B256>),
Full(slice::Iter<'a, T>),
Uncle,
}
impl<'a, T> BlockTransactionHashes<'a, T> {
#[inline]
fn new(txs: &'a BlockTransactions<T>) -> Self {
Self(match txs {
BlockTransactions::Hashes(txs) => BlockTransactionHashesInner::Hashes(txs.iter()),
BlockTransactions::Full(txs) => BlockTransactionHashesInner::Full(txs.iter()),
BlockTransactions::Uncle => BlockTransactionHashesInner::Uncle,
})
}
}
impl<T: TransactionResponse> Iterator for BlockTransactionHashes<'_, T> {
type Item = B256;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
BlockTransactionHashesInner::Hashes(txs) => txs.next().copied(),
BlockTransactionHashesInner::Full(txs) => txs.next().map(|tx| tx.tx_hash()),
BlockTransactionHashesInner::Uncle => None,
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.0 {
BlockTransactionHashesInner::Full(txs) => txs.size_hint(),
BlockTransactionHashesInner::Hashes(txs) => txs.size_hint(),
BlockTransactionHashesInner::Uncle => (0, Some(0)),
}
}
}
impl<T: TransactionResponse> ExactSizeIterator for BlockTransactionHashes<'_, T> {
#[inline]
fn len(&self) -> usize {
match &self.0 {
BlockTransactionHashesInner::Full(txs) => txs.len(),
BlockTransactionHashesInner::Hashes(txs) => txs.len(),
BlockTransactionHashesInner::Uncle => 0,
}
}
}
impl<T: TransactionResponse> DoubleEndedIterator for BlockTransactionHashes<'_, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
match &mut self.0 {
BlockTransactionHashesInner::Full(txs) => txs.next_back().map(|tx| tx.tx_hash()),
BlockTransactionHashesInner::Hashes(txs) => txs.next_back().copied(),
BlockTransactionHashesInner::Uncle => None,
}
}
}
#[cfg(feature = "std")]
impl<T: TransactionResponse> std::iter::FusedIterator for BlockTransactionHashes<'_, T> {}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum BlockTransactionsKind {
#[default]
Hashes,
Full,
}
impl From<bool> for BlockTransactionsKind {
fn from(is_full: bool) -> Self {
if is_full {
Self::Full
} else {
Self::Hashes
}
}
}
impl From<BlockTransactionsKind> for bool {
fn from(kind: BlockTransactionsKind) -> Self {
match kind {
BlockTransactionsKind::Full => true,
BlockTransactionsKind::Hashes => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_full_conversion() {
let full = true;
assert_eq!(BlockTransactionsKind::Full, full.into());
let full = false;
assert_eq!(BlockTransactionsKind::Hashes, full.into());
}
#[test]
fn test_block_transactions_default() {
let default: BlockTransactions<()> = BlockTransactions::default();
assert!(default.is_hashes());
assert_eq!(default.len(), 0);
}
#[test]
fn test_block_transactions_is_methods() {
let hashes: BlockTransactions<()> = BlockTransactions::Hashes(vec![B256::ZERO]);
let full: BlockTransactions<u32> = BlockTransactions::Full(vec![42]);
let uncle: BlockTransactions<()> = BlockTransactions::Uncle;
assert!(hashes.is_hashes());
assert!(!hashes.is_full());
assert!(!hashes.is_uncle());
assert!(full.is_full());
assert!(!full.is_hashes());
assert!(!full.is_uncle());
assert!(uncle.is_uncle());
assert!(!uncle.is_full());
assert!(!uncle.is_hashes());
}
#[test]
fn test_as_hashes() {
let hashes = vec![B256::ZERO, B256::repeat_byte(1)];
let tx_hashes: BlockTransactions<()> = BlockTransactions::Hashes(hashes.clone());
assert_eq!(tx_hashes.as_hashes(), Some(hashes.as_slice()));
}
#[test]
fn test_as_transactions() {
let transactions = vec![42, 43];
let txs = BlockTransactions::Full(transactions.clone());
assert_eq!(txs.as_transactions(), Some(transactions.as_slice()));
}
#[test]
fn test_block_transactions_len_and_is_empty() {
let hashes: BlockTransactions<()> = BlockTransactions::Hashes(vec![B256::ZERO]);
let full = BlockTransactions::Full(vec![42]);
let uncle: BlockTransactions<()> = BlockTransactions::Uncle;
assert_eq!(hashes.len(), 1);
assert_eq!(full.len(), 1);
assert_eq!(uncle.len(), 0);
assert!(!hashes.is_empty());
assert!(!full.is_empty());
assert!(uncle.is_empty());
}
#[test]
fn test_block_transactions_txns_iterator() {
let transactions = vec![42, 43];
let txs = BlockTransactions::Full(transactions);
let mut iter = txs.txns();
assert_eq!(iter.next(), Some(&42));
assert_eq!(iter.next(), Some(&43));
assert_eq!(iter.next(), None);
}
#[test]
fn test_block_transactions_into_transactions() {
let transactions = vec![42, 43];
let txs = BlockTransactions::Full(transactions.clone());
let collected: Vec<_> = txs.into_transactions().collect();
assert_eq!(collected, transactions);
}
#[test]
fn test_block_transactions_kind_conversion() {
let full: BlockTransactionsKind = true.into();
assert_eq!(full, BlockTransactionsKind::Full);
let hashes: BlockTransactionsKind = false.into();
assert_eq!(hashes, BlockTransactionsKind::Hashes);
let bool_full: bool = BlockTransactionsKind::Full.into();
assert!(bool_full);
let bool_hashes: bool = BlockTransactionsKind::Hashes.into();
assert!(!bool_hashes);
}
}