mirror of
https://github.com/Cuprate/cuprate.git
synced 2025-01-11 13:25:09 +00:00
add an iterator for ByteArrayVec
This commit is contained in:
parent
7e9891de5b
commit
cf46d58d17
4 changed files with 193 additions and 112 deletions
119
net/fixed-bytes/src/byte_array_vec.rs
Normal file
119
net/fixed-bytes/src/byte_array_vec.rs
Normal file
|
@ -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<const N: usize>(Bytes);
|
||||||
|
|
||||||
|
impl<const N: usize> ByteArrayVec<N> {
|
||||||
|
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<const N: usize> IntoIterator for ByteArrayVec<N> {
|
||||||
|
type Item = [u8; N];
|
||||||
|
type IntoIter = into_iter::ByteArrayVecIterator<N>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
into_iter::ByteArrayVecIterator(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> From<ByteArrayVec<N>> for Vec<[u8; N]> {
|
||||||
|
fn from(value: ByteArrayVec<N>) -> Self {
|
||||||
|
value.into_iter().collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> From<Vec<[u8; N]>> for ByteArrayVec<N> {
|
||||||
|
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<const N: usize> TryFrom<Bytes> for ByteArrayVec<N> {
|
||||||
|
type Error = FixedByteError;
|
||||||
|
|
||||||
|
fn try_from(value: Bytes) -> Result<Self, Self::Error> {
|
||||||
|
if value.len() % N != 0 {
|
||||||
|
return Err(FixedByteError::InvalidLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ByteArrayVec(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> From<[u8; N]> for ByteArrayVec<N> {
|
||||||
|
fn from(value: [u8; N]) -> Self {
|
||||||
|
ByteArrayVec(Bytes::copy_from_slice(value.as_slice()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize, const LEN: usize> From<[[u8; N]; LEN]> for ByteArrayVec<N> {
|
||||||
|
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<const N: usize> TryFrom<Vec<u8>> for ByteArrayVec<N> {
|
||||||
|
type Error = FixedByteError;
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
if value.len() % N != 0 {
|
||||||
|
return Err(FixedByteError::InvalidLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ByteArrayVec(Bytes::from(value)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Index<usize> for ByteArrayVec<N> {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
66
net/fixed-bytes/src/byte_array_vec/into_iter.rs
Normal file
66
net/fixed-bytes/src/byte_array_vec/into_iter.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use bytes::{Buf, Bytes};
|
||||||
|
|
||||||
|
pub struct ByteArrayVecIterator<const N: usize>(pub(crate) Bytes);
|
||||||
|
|
||||||
|
impl<const N: usize> Iterator for ByteArrayVecIterator<N> {
|
||||||
|
type Item = [u8; N];
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
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<usize>) {
|
||||||
|
(self.0.len() / N, Some(self.0.len() / N))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last(self) -> Option<Self::Item>
|
||||||
|
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<Self::Item> {
|
||||||
|
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<const N: usize> DoubleEndedIterator for ByteArrayVecIterator<N> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
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<Self::Item> {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,12 @@
|
||||||
use core::{
|
use core::{
|
||||||
fmt::{Debug, Formatter},
|
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))]
|
#[cfg_attr(feature = "std", derive(thiserror::Error))]
|
||||||
pub enum FixedByteError {
|
pub enum FixedByteError {
|
||||||
|
@ -87,114 +90,6 @@ impl<const N: usize> TryFrom<Vec<u8>> for ByteArray<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct ByteArrayVec<const N: usize>(Bytes);
|
|
||||||
|
|
||||||
impl<const N: usize> ByteArrayVec<N> {
|
|
||||||
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<const N: usize> From<&ByteArrayVec<N>> for Vec<[u8; N]> {
|
|
||||||
fn from(value: &ByteArrayVec<N>) -> Self {
|
|
||||||
let mut out = Vec::with_capacity(value.len());
|
|
||||||
for i in 0..value.len() {
|
|
||||||
out.push(value[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize> From<Vec<[u8; N]>> for ByteArrayVec<N> {
|
|
||||||
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<const N: usize> TryFrom<Bytes> for ByteArrayVec<N> {
|
|
||||||
type Error = FixedByteError;
|
|
||||||
|
|
||||||
fn try_from(value: Bytes) -> Result<Self, Self::Error> {
|
|
||||||
if value.len() % N != 0 {
|
|
||||||
return Err(FixedByteError::InvalidLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ByteArrayVec(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize> From<[u8; N]> for ByteArrayVec<N> {
|
|
||||||
fn from(value: [u8; N]) -> Self {
|
|
||||||
ByteArrayVec(Bytes::copy_from_slice(value.as_slice()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize, const LEN: usize> From<[[u8; N]; LEN]> for ByteArrayVec<N> {
|
|
||||||
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<const N: usize> TryFrom<Vec<u8>> for ByteArrayVec<N> {
|
|
||||||
type Error = FixedByteError;
|
|
||||||
|
|
||||||
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
|
||||||
if value.len() % N != 0 {
|
|
||||||
return Err(FixedByteError::InvalidLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ByteArrayVec(Bytes::from(value)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize> Index<usize> for ByteArrayVec<N> {
|
|
||||||
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -68,7 +68,7 @@ pub async fn request_chain_entry_from_peer<N: NetworkZone>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = ChainEntry {
|
let entry = ChainEntry {
|
||||||
ids: (&chain_res.m_block_ids).into(),
|
ids: chain_res.m_block_ids.into(),
|
||||||
peer: client.info.id,
|
peer: client.info.id,
|
||||||
handle: client.info.handle.clone(),
|
handle: client.info.handle.clone(),
|
||||||
};
|
};
|
||||||
|
@ -191,7 +191,8 @@ where
|
||||||
return Err(BlockDownloadError::FailedToFindAChainToFollow);
|
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 this to deallocate the [`Bytes`].
|
||||||
drop(chain_res);
|
drop(chain_res);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue