use std::slice;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::iter::Peekable;
use std::ops::{Deref, Range};
use std::sync::Arc;
use rpki::rtr::client::PayloadError;
use rpki::rtr::payload::{Action, Payload, PayloadRef};
use rpki::rtr::server::{PayloadDiff, PayloadSet};
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Pack {
items: Arc<[Payload]>,
}
impl Pack {
pub fn as_slice(&self) -> &[Payload] {
self.items.as_ref()
}
pub fn block(&self, range: Range<usize>) -> Block {
assert!(range.end <= self.items.len());
Block {
pack: self.clone(),
range
}
}
pub fn owned_iter(&self) -> OwnedBlockIter {
OwnedBlockIter::new(self.clone().into())
}
pub fn contains(&self, payload: &Payload) -> bool {
self.items.binary_search(payload).is_ok()
}
}
impl Default for Pack {
fn default() -> Self {
Pack { items: Arc::new([]) }
}
}
impl Deref for Pack {
type Target = [Payload];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl AsRef<[Payload]> for Pack {
fn as_ref(&self) -> &[Payload] {
self.as_slice()
}
}
impl Borrow<[Payload]> for Pack {
fn borrow(&self) -> &[Payload] {
self.as_slice()
}
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct PackBuilder {
items: HashSet<Payload>,
}
impl PackBuilder {
pub fn empty() -> Self {
Self::default()
}
pub fn insert(&mut self, payload: Payload) -> Result<(), PayloadError> {
if let Payload::Aspa(aspa) = &payload {
self.items.retain(|item| {
match item {
Payload::Aspa(item) => item.customer != aspa.customer
|| item.providers == aspa.providers,
_ => true
}
});
};
if self.items.insert(payload) {
Ok(())
}
else {
Err(PayloadError::DuplicateAnnounce)
}
}
pub fn insert_unchecked(&mut self, payload: Payload) {
self.items.insert(payload);
}
pub fn retain<F: FnMut(&Payload) -> bool>(&mut self, f: F) {
self.items.retain(f);
}
pub fn remove(&mut self, payload: &Payload) -> Result<(), PayloadError> {
if self.items.remove(payload) {
Ok(())
}
else {
Err(PayloadError::UnknownWithdraw)
}
}
pub fn contains(&self, payload: &Payload) -> bool {
self.items.contains(payload)
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn finalize(self) -> Pack {
let mut items: Vec<_> = self.items.into_iter().collect();
items.sort_unstable();
Pack { items: items.into_boxed_slice().into() }
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Block {
pack: Pack,
range: Range<usize>,
}
impl Block {
pub fn start(&self) -> usize {
self.range.start
}
pub fn end(&self) -> usize {
self.range.end
}
fn as_slice(&self) ->&[Payload] {
&self.pack[self.range.clone()]
}
pub(crate) fn get_from_pack(&self, pack_index: usize) -> Option<&Payload> {
if self.range.contains(&pack_index) {
self.pack.get(pack_index)
}
else {
None
}
}
pub(crate) fn head_until(&self, pack_index: usize) -> Self {
assert!(pack_index <= self.range.end);
Block {
pack: self.pack.clone(),
range: self.range.start..pack_index
}
}
fn split_off_at(&mut self, pack_index: usize) -> Block {
assert!(pack_index >= self.range.start);
assert!(pack_index <= self.range.end);
let mut res = self.clone();
res.range.end = pack_index;
self.range.start = res.range.end;
res
}
pub fn owned_iter(&self) -> OwnedBlockIter {
OwnedBlockIter::new(self.clone())
}
pub fn overlaps(&self, other: &Block) -> bool {
let mut other_iter = other.iter().peekable();
for self_item in self.iter() {
loop {
let other_item = match other_iter.peek() {
Some(item) => item,
None => return false
};
match other_item.cmp(&self_item) {
Ordering::Less => {
let _ = other_iter.next();
}
Ordering::Equal => return true,
Ordering::Greater => break,
}
}
}
false
}
}
impl From<Pack> for Block {
fn from(pack: Pack) -> Self {
Block {
range: 0..pack.len(),
pack,
}
}
}
impl Deref for Block {
type Target = [Payload];
fn deref(&self) -> &[Payload] {
self.as_slice()
}
}
impl AsRef<[Payload]> for Block {
fn as_ref(&self) ->&[Payload] {
self.as_slice()
}
}
impl Borrow<[Payload]> for Block {
fn borrow(&self) ->&[Payload] {
self.as_slice()
}
}
impl<'a> IntoIterator for &'a Block {
type Item = &'a Payload;
type IntoIter = slice::Iter<'a, Payload>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
#[derive(Clone, Debug)]
pub struct OwnedBlockIter {
block: Block,
pos: usize,
}
impl OwnedBlockIter {
fn new(block: Block) -> Self {
OwnedBlockIter {
pos: block.range.start,
block
}
}
pub fn peek(&self) -> Option<&Payload> {
if self.pos < self.block.range.end {
self.block.pack.get(self.pos)
}
else {
None
}
}
#[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Option<&Payload> {
if self.pos < self.block.range.end {
let res = self.block.pack.get(self.pos)?;
self.pos +=1;
Some(res)
}
else {
None
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Set {
blocks: Arc<[Block]>,
len: usize,
}
impl Set {
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.blocks.is_empty()
}
pub fn iter(&self) -> SetIter<'_> {
SetIter::new(self)
}
pub fn owned_iter(&self) -> OwnedSetIter {
OwnedSetIter::new(self.clone())
}
pub fn into_owned_iter(self) -> OwnedSetIter {
OwnedSetIter::new(self)
}
pub fn filter(&self, mut retain: impl FnMut(&Payload) -> bool) -> Set {
let mut res = Vec::new();
let mut res_len = 0;
for block in self.blocks.iter() {
let mut start = block.start();
while start < block.end() {
let mut end = start;
while end < block.end() {
if !retain(&block.pack[end]) {
break;
}
else {
end += 1;
}
}
if end > start {
let new_block = block.pack.block(start..end);
res_len += new_block.len();
res.push(new_block);
}
end += 1;
while end < block.end() {
if retain(&block.pack[end]) {
break;
}
else {
end += 1;
}
}
start = end;
}
}
Set {
blocks: res.into(),
len: res_len
}
}
pub fn merge(&self, other: &Set) -> Set {
let mut left_tail = self.blocks.iter().cloned();
let mut right_tail = other.blocks.iter().cloned();
let mut left_head = left_tail.next();
let mut right_head = right_tail.next();
let mut target = Vec::new();
let mut target_len = 0;
loop {
let left = loop {
match left_head.as_mut() {
Some(block) if block.is_empty() => { }
Some(block) => break Some(block),
None => break None,
}
left_head = left_tail.next();
};
let right = loop {
match right_head.as_mut() {
Some(block) if block.is_empty() => { }
Some(block) => break Some(block),
None => break None,
}
right_head = right_tail.next();
};
let (left, right) = match (left, right) {
(Some(left), Some(right))
if right.first().unwrap() < left.first().unwrap() =>
{
(right, left)
}
(Some(left), Some(right)) => (left, right),
_ => break,
};
let first_right = right.first().unwrap();
let mut left_idx = left.range.start;
while let Some(item) = left.get_from_pack(left_idx) {
if item >= first_right {
break;
}
left_idx += 1;
}
let mut right_idx = right.range.start;
while let (Some(left_item), Some(right_item)) = (
left.get_from_pack(left_idx), right.get_from_pack(right_idx)
) {
if left_item == right_item {
left_idx += 1;
right_idx += 1;
}
else {
break
}
}
let new = left.split_off_at(left_idx);
target_len += new.len();
target.push(new);
right.range.start = right_idx;
}
if let Some(block) = left_head {
if !block.is_empty() {
target_len += block.len();
target.push(block);
}
}
if let Some(block) = right_head {
if !block.is_empty() {
target_len += block.len();
target.push(block);
}
}
for block in left_tail.chain(right_tail) {
target_len += block.len();
target.push(block)
}
Set {
blocks: target.into(),
len: target_len
}
}
pub fn diff_from(&self, other: &Set) -> Diff {
let mut diff = DiffBuilder::empty();
let mut source = other.iter().peekable();
let mut target = self.iter().peekable();
while let (Some(&source_item), Some(&target_item)) = (
source.peek(), target.peek()
) {
match source_item.cmp(target_item) {
Ordering::Less => {
diff.withdrawn.insert_unchecked(source_item.clone());
source.next();
}
Ordering::Equal => {
source.next();
target.next();
}
Ordering::Greater => {
diff.announced.insert_unchecked(target_item.clone());
target.next();
}
}
}
for item in source {
diff.withdrawn.insert_unchecked(item.clone());
}
for item in target {
diff.announced.insert_unchecked(item.clone());
}
diff.finalize()
}
pub fn as_blocks(&self) -> &[Block] {
self.blocks.as_ref()
}
pub fn to_builder(&self) -> SetBuilder {
SetBuilder {
blocks: self.blocks.as_ref().into()
}
}
}
impl Default for Set {
fn default() -> Self {
Set {
blocks: Arc::new([]),
len: 0,
}
}
}
impl From<Pack> for Set {
fn from(pack: Pack) -> Self {
Block::from(pack).into()
}
}
impl From<Block> for Set {
fn from(block: Block) -> Self {
Set {
len: block.len(),
blocks: vec!(block).into(),
}
}
}
impl PartialEq for Set {
fn eq(&self, other: &Self) -> bool {
self.iter().eq(other.iter())
}
}
impl Eq for Set { }
impl<'a> IntoIterator for &'a Set {
type Item = &'a Payload;
type IntoIter = SetIter<'a>;
fn into_iter(self) -> Self::IntoIter {
SetIter::new(self)
}
}
#[derive(Clone, Debug)]
pub struct SetIter<'a> {
head: &'a [Payload],
tail: &'a [Block],
}
impl<'a> SetIter<'a> {
fn new(set: &'a Set) -> Self {
let mut res = SetIter {
head: &[],
tail: &set.blocks
};
res.next_block();
res
}
fn next_block(&mut self) -> bool {
match self.tail.split_first() {
Some((head, tail)) => {
self.head = head.as_slice();
self.tail = tail;
true
}
None => false,
}
}
}
impl<'a> Iterator for SetIter<'a> {
type Item = &'a Payload;
fn next(&mut self) -> Option<Self::Item> {
match self.head.split_first() {
Some((head, tail)) => {
self.head = tail;
Some(head)
}
None => {
if self.next_block() {
self.next()
}
else {
None
}
}
}
}
}
#[derive(Clone, Debug)]
pub struct OwnedSetIter {
set: Set,
block: usize,
item: usize,
}
impl OwnedSetIter {
fn new(set: Set) -> Self {
let item = set.blocks.first().map(|block| block.start()).unwrap_or(0);
OwnedSetIter {
set, block: 0, item
}
}
pub fn peek(&self) -> Option<&Payload> {
if let Some(item) =
self.set.blocks.get(self.block)?.get_from_pack(self.item)
{
Some(item)
}
else {
self.set.blocks.get(self.block + 1)?.first()
}
}
}
impl PayloadSet for OwnedSetIter {
fn next(&mut self) -> Option<PayloadRef<'_>> {
if let Some(item) =
self.set.blocks.get(self.block)?.get_from_pack(self.item)
{
self.item += 1;
Some(item.as_ref())
}
else {
self.block += 1;
self.item = self.set.blocks.get(self.block)?.start();
let res = self.set.blocks.get(
self.block
)?.get_from_pack(self.item)?;
self.item +=1;
Some(res.as_ref())
}
}
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct SetBuilder {
blocks: Vec<Block>,
}
impl SetBuilder {
pub fn empty() -> Self {
Default::default()
}
pub fn insert_pack(&mut self, pack: Pack) {
self.insert_block(pack.into());
}
pub fn insert_block(&mut self, block: Block) {
self.blocks.push(block);
}
pub fn insert_set(&mut self, set: Set) {
self.blocks.extend(set.blocks.iter().cloned())
}
pub fn try_insert_pack(&mut self, pack: Pack) -> Result<(), PayloadError> {
self.try_insert_block(pack.into())
}
pub fn try_insert_block(
&mut self, block: Block
) -> Result<(), PayloadError> {
if self.blocks.iter().any(|item| item.overlaps(&block)) {
return Err(PayloadError::Corrupt)
}
self.insert_block(block);
Ok(())
}
pub fn finalize(mut self) -> Set {
let mut res = Vec::new();
let mut res_len = 0;
let mut src = self.blocks.as_mut_slice();
loop {
while src.first().map(|blk| blk.is_empty()).unwrap_or(false) {
src = &mut src[1..];
}
src.sort_by(|left, right| left.first().cmp(&right.first()));
let first_end = {
let first = match src.first() {
Some(first) => first,
None => break,
};
let second = match
src[1..].iter().find_map(|blk| blk.first())
{
Some(second) => second,
None => {
res.push(first.clone());
res_len += first.len();
break;
}
};
let mut first_end = first.start();
while let Some(item) = first.get_from_pack(first_end) {
if item < second {
first_end += 1;
}
else {
break;
}
}
if first_end > first.start() {
let block = first.head_until(first_end);
res_len += block.len();
res.push(block);
}
if first.get_from_pack(first_end) == Some(second) {
first_end + 1
}
else {
first_end
}
};
if let Some(first) = src.first_mut() {
first.range.start = first_end;
}
}
Set {
blocks: res.into(),
len: res_len
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Diff {
announced: Pack,
withdrawn: Pack,
}
impl Diff {
pub fn len(&self) -> usize {
self.announced.len() + self.withdrawn.len()
}
pub fn is_empty(&self) -> bool {
self.announced.is_empty() && self.withdrawn.is_empty()
}
pub fn iter(&self) -> DiffIter<'_> {
DiffIter::new(self)
}
pub fn owned_iter(&self) -> OwnedDiffIter {
OwnedDiffIter::new(self.clone())
}
pub fn into_owned_iter(self) -> OwnedDiffIter {
OwnedDiffIter::new(self)
}
pub fn extend(&self, additional: &Diff) -> Result<Diff, PayloadError> {
let mut builder = DiffBuilder::default();
builder.push_diff(self)?;
builder.push_diff(additional)?;
Ok(builder.finalize())
}
#[allow(clippy::mutable_key_type)] pub fn apply(&self, set: &Set) -> Result<Set, PayloadError> {
let mut res = set.to_builder();
res.try_insert_pack(self.announced.clone()).map_err(|_|
PayloadError::DuplicateAnnounce
)?;
let res = res.finalize();
let mut withdrawn: HashSet<_> = self.withdrawn.iter().collect();
let res = res.filter(|item| {
match item {
Payload::Aspa(aspa) =>
!withdrawn.remove(&Payload::Aspa(aspa.withdraw())),
_ => !withdrawn.remove(item)
}
});
if !withdrawn.is_empty() {
Err(PayloadError::UnknownWithdraw)
}
else {
Ok(res)
}
}
#[allow(clippy::mutable_key_type)] pub fn apply_relaxed(&self, set: &Set) -> Set {
let mut res = set.to_builder();
res.insert_pack(self.announced.clone());
let res = res.finalize();
let mut withdrawn: HashSet<_> = self.withdrawn.iter().collect();
res.filter(|item| {
!withdrawn.remove(item)
})
}
}
impl<'a> IntoIterator for &'a Diff {
type Item = (&'a Payload, Action);
type IntoIter = DiffIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Clone, Debug)]
pub struct DiffIter<'a> {
announced: Peekable<slice::Iter<'a, Payload>>,
withdrawn: Peekable<slice::Iter<'a, Payload>>,
}
impl<'a> DiffIter<'a> {
fn new(diff: &'a Diff) -> Self {
DiffIter {
announced: diff.announced.iter().peekable(),
withdrawn: diff.withdrawn.iter().peekable(),
}
}
}
impl<'a> Iterator for DiffIter<'a> {
type Item = (&'a Payload, Action);
fn next(&mut self) -> Option<Self::Item> {
match (self.announced.peek(), self.withdrawn.peek()) {
(Some(_), None) => {
self.announced.next().map(|some| (some, Action::Announce))
}
(None, Some(_)) => {
self.withdrawn.next().map(|some| (some, Action::Withdraw))
}
(Some(announced), Some(withdrawn)) => {
if announced < withdrawn {
self.announced.next().map(|some| (some, Action::Announce))
}
else {
self.withdrawn.next().map(|some| (some, Action::Withdraw))
}
}
(None, None) => None,
}
}
}
#[derive(Clone, Debug)]
pub struct OwnedDiffIter {
announced: OwnedBlockIter,
withdrawn: OwnedBlockIter,
}
impl OwnedDiffIter {
fn new(diff: Diff) -> Self {
OwnedDiffIter {
announced: diff.announced.owned_iter(),
withdrawn: diff.withdrawn.owned_iter(),
}
}
pub fn peek(&self) -> Option<(&Payload, Action)> {
match (self.announced.peek(), self.withdrawn.peek()
) {
(Some(some), None) => Some((some, Action::Announce)),
(None, Some(some)) => Some((some, Action::Withdraw)),
(Some(announced), Some(withdrawn)) => {
if announced < withdrawn {
Some((announced, Action::Announce))
}
else {
Some((withdrawn, Action::Withdraw))
}
}
(None, None) => None,
}
}
}
impl PayloadDiff for OwnedDiffIter {
fn next(&mut self) -> Option<(PayloadRef<'_>, Action)> {
match (self.announced.peek(), self.withdrawn.peek()
) {
(Some(_), None) => {
self.announced.next().map(|some| {
(some.as_ref(), Action::Announce)
})
}
(None, Some(_)) => {
self.withdrawn.next().map(|some| {
(some.as_ref(), Action::Withdraw)
})
}
(Some(announced), Some(withdrawn)) => {
if announced < withdrawn {
self.announced.next().map(|some| {
(some.as_ref(), Action::Announce)
})
}
else {
self.withdrawn.next().map(|some| {
(some.as_ref(), Action::Withdraw)
})
}
}
(None, None) => None,
}
}
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct DiffBuilder {
announced: PackBuilder,
withdrawn: PackBuilder,
}
impl DiffBuilder {
pub fn empty() -> Self {
Self::default()
}
pub fn len(&self) -> usize {
self.announced.len() + self.withdrawn.len()
}
pub fn is_empty(&self) -> bool {
self.announced.is_empty() && self.withdrawn.is_empty()
}
pub fn push(
&mut self, payload: Payload, action: Action
) -> Result<(), PayloadError> {
match action {
Action::Announce => {
if let Payload::Aspa(aspa) = &payload {
let _ = self.withdrawn.remove(
&Payload::Aspa(aspa.withdraw())
);
self.announced.retain(|item| {
match item {
Payload::Aspa(item) => item.customer != aspa.customer
|| item.providers == aspa.providers,
_ => true
}
});
}
if self.withdrawn.contains(&payload) {
return Err(PayloadError::Corrupt)
}
self.announced.insert(payload)
}
Action::Withdraw => {
if self.announced.contains(&payload) {
return Err(PayloadError::Corrupt)
}
let payload = match payload {
Payload::Aspa(aspa) => Payload::Aspa(aspa.withdraw()),
_ => payload
};
self.withdrawn.insert(payload)
}
}
}
pub fn push_diff(
&mut self, diff: &Diff
) -> Result<(), PayloadError> {
for (payload, action) in diff {
match action {
Action::Announce => {
if self.withdrawn.remove(payload).is_err() {
self.announced.insert(payload.clone())?
}
}
Action::Withdraw => {
if self.announced.remove(payload).is_err() {
self.withdrawn.insert(payload.clone())?
}
}
}
}
Ok(())
}
pub fn finalize(self) -> Diff {
let mut withdrawn = self.withdrawn;
let ann_customers: HashSet<_> = self.announced.items.iter()
.filter_map(|p| p.as_aspa())
.map(|a| a.customer)
.collect();
withdrawn.retain(|item| {
match item {
Payload::Aspa(aspa) =>
!ann_customers.contains(&aspa.customer),
_ => true,
}
});
Diff {
announced: self.announced.finalize(),
withdrawn: withdrawn.finalize(),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Update {
set: Set,
}
impl Update {
pub fn new(
set: Set
) -> Self {
Update { set }
}
pub fn set(&self) -> &Set {
&self.set
}
pub fn into_set(self) -> Set {
self.set
}
pub fn apply_diff_relaxed(&mut self, diff: &Diff) {
self.set = diff.apply_relaxed(&self.set);
}
}
#[cfg(test)]
pub(crate) mod testrig {
use super::*;
use std::net::IpAddr;
use rpki::resources::addr::{MaxLenPrefix, Prefix};
pub fn p(value: u32) -> Payload {
Payload::origin(
MaxLenPrefix::new(
Prefix::new_v4(value.into(), 32).unwrap(),
Some(32)
).unwrap(),
0.into()
)
}
pub fn pack<const N: usize>(values: [u32; N]) -> Pack {
Pack {
items:
values.into_iter().map(p).collect::<Vec<_>>().into()
}
}
pub fn block<const N: usize>(
values: [u32; N], range: Range<usize>
) -> Block {
Block {
pack: pack(values),
range
}
}
pub fn set<const N: usize>(blocks: [Block; N]) -> Set {
let len = blocks.iter().map(|item| item.len()).sum();
Set {
blocks: Arc::from(blocks.as_slice()),
len
}
}
pub fn check_pack(pack: &Pack) {
if pack.items.is_empty() {
return
}
for window in pack.items.windows(2) {
assert!(window[0] < window[1])
}
}
pub fn check_set(set: &Set) {
for block in set.blocks.iter() {
assert!(!block.is_empty())
}
for window in set.iter().cloned().collect::<Vec<_>>().windows(2) {
assert!(window[0] < window[1])
}
}
pub fn update<const N: usize>(values: [u32; N]) -> Update {
Update::new(
set([
block(values, 0..values.len())
])
)
}
pub fn set_to_vec(set: &Set) -> Vec<u32> {
set.iter().map(|payload| match payload {
Payload::Origin(item) => {
match item.prefix.addr() {
IpAddr::V4(addr) => addr.into(),
_ => panic!("not a v4 prefix")
}
}
_ => panic!("not a v4 prefix")
}).collect()
}
}
#[cfg(test)]
mod test {
use super::*;
use super::testrig::*;
#[test]
fn set_merge() {
assert!(
set([block([], 0..0)]).merge(
&set([block([], 0..0)])
).iter().eq(set([block([], 0..0)]).iter())
);
assert!(
set([block([1, 3, 4], 0..3)]).merge(
&set([block([1, 3, 4], 0..3)])
).iter().eq(set([block([1, 3, 4], 0..3)]).iter())
);
assert!(
set([block([1, 3, 4], 0..3)]).merge(
&set([block([], 0..0)])
).iter().eq(set([block([1, 3, 4], 0..3)]).iter())
);
assert!(
set([block([], 0..0)]).merge(
&set([block([1, 3, 4], 0..3)])
).iter().eq(set([block([1, 3, 4], 0..3)]).iter())
);
assert!(
set([block([1, 3, 4, 5], 0..4)]).merge(
&set([block([1, 3, 4], 0..3)])
).iter().eq(set([block([1, 3, 4, 5], 0..4)]).iter())
);
assert!(
set([block([1, 3, 5], 0..3)]).merge(
&set([block([1, 3, 4], 0..3)])
).iter().eq(set([block([1, 3, 4, 5], 0..4)]).iter())
);
assert!(
set([block([1, 3, 5], 0..3), block([10, 11], 0..2)]).merge(
&set([block([3, 4], 0..2)])
).iter().eq(set([block([1, 3, 4, 5, 10, 11], 0..6)]).iter())
);
}
#[test]
fn set_iter() {
assert_eq!(
Set {
blocks: vec![
block([1, 2, 4], 0..3),
block([4, 5], 1..2)
].into(),
len: 4
}.iter().cloned().collect::<Vec<_>>(),
[p(1), p(2), p(4), p(5)]
);
}
#[test]
fn set_builder() {
let mut builder = SetBuilder::empty();
builder.insert_pack(pack([1, 2, 11, 12]));
builder.insert_pack(pack([5, 6, 7, 15, 18]));
builder.insert_pack(pack([6, 7]));
builder.insert_pack(pack([7]));
builder.insert_pack(pack([17]));
let set = builder.finalize();
check_set(&set);
assert_eq!(
set_to_vec(&set),
[1, 2, 5, 6, 7, 11, 12, 15, 17, 18]
);
}
#[test]
fn diff_iter() {
use rpki::rtr::payload::Action::{Announce as A, Withdraw as W};
assert_eq!(
Diff {
announced: pack([6, 7, 15, 18]),
withdrawn: pack([2, 8, 9]),
}.iter().collect::<Vec<_>>(),
[
(&p(2), W), (&p(6), A), (&p(7), A), (&p(8), W), (&p(9), W),
(&p(15), A), (&p(18), A)
]
);
}
#[test]
#[allow(clippy::mutable_key_type)] fn mix_and_match() {
use rand::Rng;
fn random_vec<T: Rng>(rng: &mut T, len: usize) -> Vec<Payload> {
let mut res = Vec::with_capacity(len);
for _ in 0..len {
res.push(p(rng.random()))
}
res
}
fn build_pack(data: &[Payload]) -> Pack {
let mut res = PackBuilder::empty();
for item in data {
res.insert_unchecked(item.clone());
}
let res = res.finalize();
check_pack(&res);
res
}
fn sort_and_dedup(mut vec: Vec<Payload>) -> Vec<Payload> {
vec.sort();
vec.dedup();
vec
}
let mut rng = rand_pcg::Pcg32::new(
0xcafef00dd15ea5e5, 0xa02bdbf7bb3c0a7
);
let v1 = random_vec(&mut rng, 100);
let v2 = random_vec(&mut rng, 10);
let v3 = random_vec(&mut rng, 50);
let p1 = build_pack(&v1);
let p2 = build_pack(&v2);
let p3 = build_pack(&v3);
let v1 = sort_and_dedup(v1);
let v2 = sort_and_dedup(v2);
let v3 = sort_and_dedup(v3);
assert!(p1.iter().eq(v1.iter()));
assert!(p2.iter().eq(v2.iter()));
assert!(p3.iter().eq(v3.iter()));
let mut v = v1.clone();
v.extend_from_slice(&v2);
v.extend_from_slice(&v3);
v.sort();
v.dedup();
let v = v;
let mut s = SetBuilder::empty();
s.insert_pack(p1.clone());
s.insert_pack(p2.clone());
s.insert_pack(p3.clone());
let s = s.finalize();
assert!(s.iter().eq(v.iter()));
let h1 = v1.iter().cloned().collect::<HashSet<_>>();
let h2 = v2.iter().cloned().collect::<HashSet<_>>();
let h3 = v3.iter().cloned().collect::<HashSet<_>>();
let s1 = Set::from(p1);
let s2 = Set::from(p2);
let s3 = Set::from(p3);
let d2 = s2.diff_from(&s1);
let d3 = s3.diff_from(&s2);
fn check_diff(
d: &Diff, from: &HashSet<Payload>, to: &HashSet<Payload>
) {
let mut announced =
to.difference(from).cloned().collect::<Vec<_>>();
announced.sort();
let mut withdrawn =
from.difference(to).cloned().collect::<Vec<_>>();
withdrawn.sort();
assert!(d.announced.iter().eq(announced.iter()));
assert!(d.withdrawn.iter().eq(withdrawn.iter()));
}
check_diff(&d2, &h1, &h2);
check_diff(&d3, &h2, &h3);
assert!(d2.apply(&s1).unwrap().iter().eq(s2.iter()));
assert!(d3.apply(&s2).unwrap().iter().eq(s3.iter()));
assert!(
d2.extend(&d3).unwrap().apply(&s1).unwrap().iter().eq(s3.iter())
);
}
#[test]
fn owned_block_iter() {
fn test_iter<const N: usize>(payload: [Payload; N], block: Block) {
let piter = payload.iter();
let mut oiter = block.owned_iter();
for p_item in piter {
assert_eq!(p_item, oiter.peek().unwrap());
assert_eq!(p_item, oiter.next().unwrap());
}
assert!(oiter.peek().is_none());
assert!(oiter.next().is_none());
}
test_iter(
[],
block([], 0..0)
);
test_iter(
[],
block([7, 8, 10, 12, 18, 19], 3..3)
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
block([7, 8, 10, 12, 18, 19], 0..6)
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
block([2, 3, 7, 8, 10, 12, 18, 19], 2..8)
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
block([7, 8, 10, 12, 18, 19, 21, 22], 0..6)
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
block([2, 3, 7, 8, 10, 12, 18, 19, 21], 2..8)
);
test_iter(
[p(7)],
block([2, 3, 7, 8, 10, 12, 18, 19, 21], 2..3)
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
block([7, 8, 10, 12, 18, 19], 0..6)
);
}
#[test]
fn set_iters() {
fn test_iter<const N: usize>(payload: [Payload; N], set: Set) {
let piter = payload.iter();
let mut iter = set.iter();
let mut oiter = set.owned_iter();
for p_item in piter {
assert_eq!(p_item, iter.next().unwrap());
assert_eq!(p_item, oiter.peek().unwrap());
assert_eq!(p_item.as_ref(), oiter.next().unwrap());
}
assert!(iter.next().is_none());
assert!(oiter.peek().is_none());
assert!(oiter.next().is_none());
}
test_iter(
[],
Set::from(pack([]))
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
Set::from(pack([7, 8, 10, 12, 18, 19]))
);
test_iter(
[],
Set::from(block([7, 8, 10, 12, 18, 19], 3..3))
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
Set::from(block([7, 8, 10, 12, 18, 19], 0..6))
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
Set::from(block([2, 3, 7, 8, 10, 12, 18, 19], 2..8))
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
Set::from(block([7, 8, 10, 12, 18, 19, 21, 22], 0..6))
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
Set::from(block([2, 3, 7, 8, 10, 12, 18, 19, 21], 2..8))
);
test_iter(
[p(7)],
Set::from(block([2, 3, 7, 8, 10, 12, 18, 19, 21], 2..3))
);
test_iter(
[p(7), p(8), p(10), p(12), p(18), p(19)],
set([
block([2, 7, 8, 10], 1..3),
block([10], 0..1),
block([2, 12, 18, 19], 1..4)
])
);
}
}