diff --git a/net/fixed-bytes/src/byte_array_vec.rs b/net/fixed-bytes/src/byte_array_vec.rs new file mode 100644 index 00000000..84f38057 --- /dev/null +++ b/net/fixed-bytes/src/byte_array_vec.rs @@ -0,0 +1,119 @@ +mod into_iter; + +use core::ops::Index; + +use bytes::{BufMut, Bytes, BytesMut}; + +use crate::FixedByteError; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ByteArrayVec(Bytes); + +impl ByteArrayVec { + pub fn len(&self) -> usize { + self.0.len() / N + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn take_bytes(self) -> Bytes { + self.0 + } + + /// Splits the byte array vec into two at the given index. + /// + /// Afterwards self contains elements [0, at), and the returned [`ByteArrayVec`] contains elements [at, len). + /// + /// This is an O(1) operation that just increases the reference count and sets a few indices. + /// + /// # Panics + /// Panics if at > len. + pub fn split_off(&mut self, at: usize) -> Self { + Self(self.0.split_off(at * N)) + } +} + +impl IntoIterator for ByteArrayVec { + type Item = [u8; N]; + type IntoIter = into_iter::ByteArrayVecIterator; + + fn into_iter(self) -> Self::IntoIter { + into_iter::ByteArrayVecIterator(self.0) + } +} + +impl From> for Vec<[u8; N]> { + fn from(value: ByteArrayVec) -> Self { + value.into_iter().collect() + } +} + +impl From> for ByteArrayVec { + fn from(value: Vec<[u8; N]>) -> Self { + let mut bytes = BytesMut::with_capacity(N * value.len()); + for i in value.into_iter() { + bytes.extend_from_slice(&i) + } + + ByteArrayVec(bytes.freeze()) + } +} + +impl TryFrom for ByteArrayVec { + type Error = FixedByteError; + + fn try_from(value: Bytes) -> Result { + if value.len() % N != 0 { + return Err(FixedByteError::InvalidLength); + } + + Ok(ByteArrayVec(value)) + } +} + +impl From<[u8; N]> for ByteArrayVec { + fn from(value: [u8; N]) -> Self { + ByteArrayVec(Bytes::copy_from_slice(value.as_slice())) + } +} + +impl From<[[u8; N]; LEN]> for ByteArrayVec { + fn from(value: [[u8; N]; LEN]) -> Self { + let mut bytes = BytesMut::with_capacity(N * LEN); + + for val in value.into_iter() { + bytes.put_slice(val.as_slice()); + } + + ByteArrayVec(bytes.freeze()) + } +} + +impl TryFrom> for ByteArrayVec { + type Error = FixedByteError; + + fn try_from(value: Vec) -> Result { + if value.len() % N != 0 { + return Err(FixedByteError::InvalidLength); + } + + Ok(ByteArrayVec(Bytes::from(value))) + } +} + +impl Index for ByteArrayVec { + type Output = [u8; N]; + + fn index(&self, index: usize) -> &Self::Output { + if (index + 1) * N > self.0.len() { + panic!("Index out of range, idx: {}, length: {}", index, self.len()); + } + + self.0[index * N..(index + 1) * N] + .as_ref() + .try_into() + .unwrap() + } +} diff --git a/net/fixed-bytes/src/byte_array_vec/into_iter.rs b/net/fixed-bytes/src/byte_array_vec/into_iter.rs new file mode 100644 index 00000000..5fb24b1f --- /dev/null +++ b/net/fixed-bytes/src/byte_array_vec/into_iter.rs @@ -0,0 +1,66 @@ +use bytes::{Buf, Bytes}; + +pub struct ByteArrayVecIterator(pub(crate) Bytes); + +impl Iterator for ByteArrayVecIterator { + type Item = [u8; N]; + + fn next(&mut self) -> Option { + if self.0.is_empty() { + return None; + } + + let next = self.0[..N].try_into().unwrap(); + self.0.advance(N); + Some(next) + } + + fn size_hint(&self) -> (usize, Option) { + (self.0.len() / N, Some(self.0.len() / N)) + } + + fn last(self) -> Option + where + Self: Sized, + { + if self.0.is_empty() { + return None; + } + + Some(self.0[self.0.len() - N..].try_into().unwrap()) + } + + fn nth(&mut self, n: usize) -> Option { + let iters_left = self.0.len() / N; + + if iters_left.checked_sub(n).is_none() { + return None; + } + + self.0.advance(n * N - N); + + self.next() + } +} + +impl DoubleEndedIterator for ByteArrayVecIterator { + fn next_back(&mut self) -> Option { + if self.0.is_empty() { + return None; + } + + Some(self.0[self.0.len() - N..].try_into().unwrap()) + } + + fn nth_back(&mut self, n: usize) -> Option { + let iters_left = self.0.len() / N; + + if iters_left.checked_sub(n).is_none() { + return None; + } + + self.0.truncate(self.0.len() - n * N - N); + + self.next_back() + } +} diff --git a/net/fixed-bytes/src/lib.rs b/net/fixed-bytes/src/lib.rs index 8776d309..80368a17 100644 --- a/net/fixed-bytes/src/lib.rs +++ b/net/fixed-bytes/src/lib.rs @@ -1,9 +1,12 @@ use core::{ fmt::{Debug, Formatter}, - ops::{Deref, Index}, + ops::Deref, }; -use bytes::{BufMut, Bytes, BytesMut}; +use bytes::Bytes; + +mod byte_array_vec; +pub use byte_array_vec::ByteArrayVec; #[cfg_attr(feature = "std", derive(thiserror::Error))] pub enum FixedByteError { @@ -87,114 +90,6 @@ impl TryFrom> for ByteArray { } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ByteArrayVec(Bytes); - -impl ByteArrayVec { - pub fn len(&self) -> usize { - self.0.len() / N - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - pub fn take_bytes(self) -> Bytes { - self.0 - } - - /// Splits the byte array vec into two at the given index. - /// - /// Afterwards self contains elements [0, at), and the returned [`ByteArrayVec`] contains elements [at, len). - /// - /// This is an O(1) operation that just increases the reference count and sets a few indices. - /// - /// # Panics - /// Panics if at > len. - pub fn split_off(&mut self, at: usize) -> Self { - Self(self.0.split_off(at * N)) - } -} - -impl From<&ByteArrayVec> for Vec<[u8; N]> { - fn from(value: &ByteArrayVec) -> Self { - let mut out = Vec::with_capacity(value.len()); - for i in 0..value.len() { - out.push(value[i]) - } - - out - } -} - -impl From> for ByteArrayVec { - fn from(value: Vec<[u8; N]>) -> Self { - let mut bytes = BytesMut::with_capacity(N * value.len()); - for i in value.into_iter() { - bytes.extend_from_slice(&i) - } - - ByteArrayVec(bytes.freeze()) - } -} - -impl TryFrom for ByteArrayVec { - type Error = FixedByteError; - - fn try_from(value: Bytes) -> Result { - if value.len() % N != 0 { - return Err(FixedByteError::InvalidLength); - } - - Ok(ByteArrayVec(value)) - } -} - -impl From<[u8; N]> for ByteArrayVec { - fn from(value: [u8; N]) -> Self { - ByteArrayVec(Bytes::copy_from_slice(value.as_slice())) - } -} - -impl From<[[u8; N]; LEN]> for ByteArrayVec { - fn from(value: [[u8; N]; LEN]) -> Self { - let mut bytes = BytesMut::with_capacity(N * LEN); - - for val in value.into_iter() { - bytes.put_slice(val.as_slice()); - } - - ByteArrayVec(bytes.freeze()) - } -} - -impl TryFrom> for ByteArrayVec { - type Error = FixedByteError; - - fn try_from(value: Vec) -> Result { - if value.len() % N != 0 { - return Err(FixedByteError::InvalidLength); - } - - Ok(ByteArrayVec(Bytes::from(value))) - } -} - -impl Index for ByteArrayVec { - type Output = [u8; N]; - - fn index(&self, index: usize) -> &Self::Output { - if (index + 1) * N > self.0.len() { - panic!("Index out of range, idx: {}, length: {}", index, self.len()); - } - - self.0[index * N..(index + 1) * N] - .as_ref() - .try_into() - .unwrap() - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/p2p/p2p/src/block_downloader/request_chain.rs b/p2p/p2p/src/block_downloader/request_chain.rs index f8b53194..4450b67c 100644 --- a/p2p/p2p/src/block_downloader/request_chain.rs +++ b/p2p/p2p/src/block_downloader/request_chain.rs @@ -68,7 +68,7 @@ pub async fn request_chain_entry_from_peer( } let entry = ChainEntry { - ids: (&chain_res.m_block_ids).into(), + ids: chain_res.m_block_ids.into(), peer: client.info.id, handle: client.info.handle.clone(), }; @@ -191,7 +191,8 @@ where return Err(BlockDownloadError::FailedToFindAChainToFollow); }; - let hashes: Vec<[u8; 32]> = (&chain_res.m_block_ids).into(); + // .clone here is not a full clone as the underlying data is [`Bytes`]. + let hashes: Vec<[u8; 32]> = chain_res.m_block_ids.clone().into(); // drop this to deallocate the [`Bytes`]. drop(chain_res);