Skip to content

Commit

Permalink
chore: allow empty lists
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes committed Sep 27, 2024
1 parent 90a4fd1 commit c393e58
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 23 deletions.
58 changes: 44 additions & 14 deletions crates/primitives-traits/src/integer_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::fmt;
use derive_more::Deref;
use roaring::RoaringTreemap;
use serde::{
de::{SeqAccess, Unexpected, Visitor},
de::{SeqAccess, Visitor},
ser::SerializeSeq,
Deserialize, Deserializer, Serialize, Serializer,
};
Expand All @@ -22,26 +22,50 @@ impl fmt::Debug for IntegerList {
}

impl IntegerList {
/// Creates a new empty `IntegerList`.
pub fn empty() -> Self {
Self(RoaringTreemap::new())
}

/// Creates an `IntegerList` from a list of integers.
///
/// Returns an error if the list is empty or not pre-sorted.
pub fn new(list: impl IntoIterator<Item = u64>) -> Result<Self, RoaringBitmapError> {
/// Returns an error if the list is not pre-sorted.
pub fn new(list: impl IntoIterator<Item = u64>) -> Result<Self, IntegerListError> {
RoaringTreemap::from_sorted_iter(list)
.map(Self)
.map_err(|_| RoaringBitmapError::InvalidInput)
.map_err(|_| IntegerListError::UnsortedInput)
}

// Creates an IntegerList from a pre-sorted list of integers.
///
/// # Panics
///
/// Panics if the list is empty or not pre-sorted.
/// Panics if the list is not pre-sorted.
#[inline]
#[track_caller]
pub fn new_pre_sorted(list: impl IntoIterator<Item = u64>) -> Self {
Self::new(list).expect("IntegerList must be pre-sorted and non-empty")
}

/// Appends a list of integers to the current list.
pub fn append(&mut self, list: impl IntoIterator<Item = u64>) -> Result<u64, IntegerListError> {
self.0.append(list).map_err(|_| IntegerListError::UnsortedInput)
}

/// Pushes a new integer to the list.
pub fn push(&mut self, value: u64) -> Result<(), IntegerListError> {
if self.0.push(value) {
Ok(())
} else {
Err(IntegerListError::UnsortedInput)
}
}

/// Clears the list.
pub fn clear(&mut self) {
self.0.clear();
}

/// Serializes a [`IntegerList`] into a sequence of bytes.
pub fn to_bytes(&self) -> Vec<u8> {
let mut vec = Vec::with_capacity(self.0.serialized_size());
Expand All @@ -55,10 +79,10 @@ impl IntegerList {
}

/// Deserializes a sequence of bytes into a proper [`IntegerList`].
pub fn from_bytes(data: &[u8]) -> Result<Self, RoaringBitmapError> {
pub fn from_bytes(data: &[u8]) -> Result<Self, IntegerListError> {
Ok(Self(
RoaringTreemap::deserialize_from(data)
.map_err(|_| RoaringBitmapError::FailedToDeserialize)?,
.map_err(|_| IntegerListError::FailedToDeserialize)?,
))
}
}
Expand Down Expand Up @@ -88,11 +112,11 @@ impl<'de> Visitor<'de> for IntegerListVisitor {
where
E: SeqAccess<'de>,
{
let mut list = Vec::with_capacity(seq.size_hint().unwrap_or(0).min(1024));
let mut list = IntegerList::empty();
while let Some(item) = seq.next_element()? {
list.push(item);
list.push(item).map_err(serde::de::Error::custom)?;
}
IntegerList::new(list).map_err(|_| serde::de::Error::invalid_value(Unexpected::Seq, &self))
Ok(list)
}
}

Expand All @@ -119,10 +143,10 @@ impl<'a> Arbitrary<'a> for IntegerList {

/// Primitives error type.
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub enum RoaringBitmapError {
/// The provided input is invalid.
#[display("the provided input is invalid")]
InvalidInput,
pub enum IntegerListError {
/// The provided input is unsorted.
#[display("the provided input is unsorted")]
UnsortedInput,
/// Failed to deserialize data into type.
#[display("failed to deserialize data into type")]
FailedToDeserialize,
Expand All @@ -132,6 +156,12 @@ pub enum RoaringBitmapError {
mod tests {
use super::*;

#[test]
fn empty_list() {
assert_eq!(IntegerList::empty().len(), 0);
assert_eq!(IntegerList::new_pre_sorted(std::iter::empty()).len(), 0);
}

#[test]
fn test_integer_list() {
let original_list = [1, 2, 3];
Expand Down
2 changes: 1 addition & 1 deletion crates/primitives-traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub mod account;
pub use account::{Account, Bytecode};

mod integer_list;
pub use integer_list::{IntegerList, RoaringBitmapError};
pub use integer_list::{IntegerList, IntegerListError};

pub mod request;
pub use request::{Request, Requests};
Expand Down
10 changes: 2 additions & 8 deletions crates/storage/db/src/tables/codecs/fuzz/inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,7 @@ pub struct IntegerListInput(pub Vec<u64>);
impl From<IntegerListInput> for IntegerList {
fn from(list: IntegerListInput) -> Self {
let mut v = list.0;
// Empty lists are not supported by `IntegerList`, so we want to skip these cases.
let list = if v.is_empty() {
&[1u64][..]
} else {
v.sort_unstable();
&v
};
IntegerList::new_pre_sorted(list.iter().copied())
v.sort_unstable();
Self::new_pre_sorted(v)
}
}

0 comments on commit c393e58

Please sign in to comment.