bee_block/
parent.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4//! The parents module defines the core data type for storing the blocks directly approved by a block.
5
6use 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/// A [`Block`](crate::Block)'s [`Parents`] are the [`BlockId`]s of the blocks it directly approves.
18///
19/// Parents must be:
20/// * in the `Parents::COUNT_RANGE` range;
21/// * lexicographically sorted;
22/// * unique;
23#[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    /// The range representing the valid number of parents.
32    pub const COUNT_RANGE: RangeInclusive<u8> = 1..=8;
33
34    /// Creates new [`Parents`].
35    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    /// Returns the number of parents.
45    pub fn len(&self) -> usize {
46        self.0.len()
47    }
48
49    /// Returns an iterator over the parents.
50    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}