use alloc::{collections::BTreeSet, vec::Vec};
use core::ops::RangeInclusive;
use derive_more::Deref;
use iterator_sorted::is_unique_sorted;
use packable::{bounded::BoundedU8, prefix::BoxedSlicePrefix, Packable};
use crate::types::block::{BlockId, Error};
pub(crate) type ParentCount = BoundedU8<{ *Parents::COUNT_RANGE.start() }, { *Parents::COUNT_RANGE.end() }>;
#[derive(Clone, Debug, Eq, PartialEq, Deref, Packable)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[deref(forward)]
#[packable(unpack_error = Error, with = |e| Error::InvalidParentCount(e.into_prefix_err().into()))]
pub struct Parents(#[packable(verify_with = verify_parents)] BoxedSlicePrefix<BlockId, ParentCount>);
#[allow(clippy::len_without_is_empty)]
impl Parents {
pub const COUNT_RANGE: RangeInclusive<u8> = 1..=8;
pub fn from_vec(mut inner: Vec<BlockId>) -> Result<Self, Error> {
inner.sort_unstable();
inner.dedup();
Ok(Self(
inner.into_boxed_slice().try_into().map_err(Error::InvalidParentCount)?,
))
}
pub fn from_set(inner: BTreeSet<BlockId>) -> Result<Self, Error> {
Ok(Self(
inner
.into_iter()
.collect::<Box<[_]>>()
.try_into()
.map_err(Error::InvalidParentCount)?,
))
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = &BlockId> + '_ {
self.0.iter()
}
}
fn verify_parents<const VERIFY: bool>(parents: &[BlockId], _: &()) -> Result<(), Error> {
if VERIFY && !is_unique_sorted(parents.iter().map(AsRef::as_ref)) {
Err(Error::ParentsNotUniqueSorted)
} else {
Ok(())
}
}