1use alloc::vec::Vec;
7use core::ops::RangeInclusive;
8
9use derive_more::Deref;
10use iterator_sorted::is_unique_sorted;
11use packable::{bounded::BoundedU8, prefix::BoxedSlicePrefix, Packable, PackableExt};
12
13use crate::{BlockId, Error};
14
15pub(crate) type ParentCount = BoundedU8<{ *Parents::COUNT_RANGE.start() }, { *Parents::COUNT_RANGE.end() }>;
16
17#[derive(Clone, Debug, Eq, PartialEq, Deref, Packable)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[deref(forward)]
26#[packable(unpack_error = Error, with = |e| Error::InvalidParentCount(e.into_prefix_err().into()))]
27pub struct Parents(#[packable(verify_with = verify_parents)] BoxedSlicePrefix<BlockId, ParentCount>);
28
29#[allow(clippy::len_without_is_empty)]
30impl Parents {
31 pub const COUNT_RANGE: RangeInclusive<u8> = 1..=8;
33
34 pub fn new(mut inner: Vec<BlockId>) -> Result<Self, Error> {
36 inner.sort_unstable_by_key(|a| a.pack_to_vec());
37 inner.dedup();
38
39 Ok(Self(
40 inner.into_boxed_slice().try_into().map_err(Error::InvalidParentCount)?,
41 ))
42 }
43
44 pub fn len(&self) -> usize {
46 self.0.len()
47 }
48
49 pub fn iter(&self) -> impl ExactSizeIterator<Item = &BlockId> + '_ {
51 self.0.iter()
52 }
53}
54
55fn verify_parents<const VERIFY: bool>(parents: &[BlockId], _: &()) -> Result<(), Error> {
56 if VERIFY && !is_unique_sorted(parents.iter().map(AsRef::as_ref)) {
57 Err(Error::ParentsNotUniqueSorted)
58 } else {
59 Ok(())
60 }
61}