Skip to main content

soil_network/
utils.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! `soil-network` utilities
8
9use futures::{stream::unfold, FutureExt, Stream, StreamExt};
10use futures_timer::Delay;
11use linked_hash_set::LinkedHashSet;
12
13use std::{hash::Hash, num::NonZeroUsize, time::Duration};
14
15/// Creates a stream that returns a new value every `duration`.
16pub fn interval(duration: Duration) -> impl Stream<Item = ()> + Unpin {
17	unfold((), move |_| Delay::new(duration).map(|_| Some(((), ())))).map(drop)
18}
19
20/// Wrapper around `LinkedHashSet` with bounded growth.
21///
22/// In the limit, for each element inserted the oldest existing element will be removed.
23#[derive(Debug, Clone)]
24pub struct LruHashSet<T: Hash + Eq> {
25	set: LinkedHashSet<T>,
26	limit: NonZeroUsize,
27}
28
29impl<T: Hash + Eq> LruHashSet<T> {
30	/// Create a new `LruHashSet` with the given (exclusive) limit.
31	pub fn new(limit: NonZeroUsize) -> Self {
32		Self { set: LinkedHashSet::new(), limit }
33	}
34
35	/// Insert element into the set.
36	///
37	/// Returns `true` if this is a new element to the set, `false` otherwise.
38	/// Maintains the limit of the set by removing the oldest entry if necessary.
39	/// Inserting the same element will update its LRU position.
40	pub fn insert(&mut self, e: T) -> bool {
41		if self.set.insert(e) {
42			if self.set.len() == usize::from(self.limit) {
43				self.set.pop_front(); // remove oldest entry
44			}
45			return true;
46		}
47		false
48	}
49}
50
51#[cfg(test)]
52mod tests {
53	use super::*;
54
55	#[test]
56	fn maintains_limit() {
57		let three = NonZeroUsize::new(3).unwrap();
58		let mut set = LruHashSet::<u8>::new(three);
59
60		// First element.
61		assert!(set.insert(1));
62		assert_eq!(vec![&1], set.set.iter().collect::<Vec<_>>());
63
64		// Second element.
65		assert!(set.insert(2));
66		assert_eq!(vec![&1, &2], set.set.iter().collect::<Vec<_>>());
67
68		// Inserting the same element updates its LRU position.
69		assert!(!set.insert(1));
70		assert_eq!(vec![&2, &1], set.set.iter().collect::<Vec<_>>());
71
72		// We reached the limit. The next element forces the oldest one out.
73		assert!(set.insert(3));
74		assert_eq!(vec![&1, &3], set.set.iter().collect::<Vec<_>>());
75	}
76}