You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

385 lines
9.9 KiB
Rust

use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Debug, Formatter};
use std::time::{Duration, Instant};
#[derive(Default)]
pub struct EphemeralMap<K: Ord + Clone, V> {
entry_map: BTreeMap<K, EphemeralNode<V>>,
expiry_map: BTreeMap<Instant, BTreeSet<K>>,
}
impl<K: Ord + Debug + Clone, V: Debug> Debug for EphemeralMap<K, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_map().entries(self.entry_map.iter()).finish()
}
}
impl<K: Ord + Clone + Debug, V> EphemeralMap<K, V> {
pub fn new() -> Self {
EphemeralMap {
entry_map: Default::default(),
expiry_map: Default::default(),
}
}
pub fn clean(&mut self) {
let valid = self.expiry_map.split_off(&Instant::now());
let expired = std::mem::replace(&mut self.expiry_map, valid);
for (_, keys) in expired {
for key in keys {
self.entry_map.remove(&key);
}
}
}
pub fn insert(&mut self, key: K, value: V, expires_at: Instant) -> Option<EphemeralNode<V>> {
let node = EphemeralNode { value, expires_at };
let removed = self.remove(&key);
self.add_expiry(key.clone(), expires_at);
self.entry_map.insert(key, node);
removed
}
pub fn remove(&mut self, key: &K) -> Option<EphemeralNode<V>> {
if let Some(node) = self.entry_map.remove(key) {
self.remove_expiry(key, node.expires_at);
Some(node)
} else {
None
}
}
pub fn remove_value(&mut self, key: &K) -> Option<V> {
self.remove(key).map(|x| x.value)
}
fn add_expiry(&mut self, key: K, expires_at: Instant) {
self.expiry_map
.entry(expires_at)
.or_insert_with(|| BTreeSet::new())
.insert(key);
}
fn remove_expiry(&mut self, key: &K, expires_at: Instant) {
let remove_node = if let Some(item) = self.expiry_map.get_mut(&expires_at) {
item.remove(&key);
item.len() == 0
} else {
false
};
if remove_node {
self.expiry_map.remove(&expires_at);
}
}
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
self.entry_map.iter().filter_map(|(key, entry)| {
if entry.is_expired() {
None
} else {
Some((key, &entry.value))
}
})
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
self.entry_map.iter_mut().filter_map(|(key, entry)| {
if entry.is_expired() {
None
} else {
Some((key, &mut entry.value))
}
})
}
pub fn len(&self) -> usize {
self.iter().count()
}
pub fn contains_key(&self, key: &K) -> bool {
self.get(key).is_some()
}
pub fn get_and_bump(&mut self, key: &K, from_now: Duration) -> Option<&V> {
if self.get_node(key).is_none() {
return None;
}
self.update_expiry(&key, Instant::now() + from_now);
self.get(key)
}
pub fn get(&self, key: &K) -> Option<&V> {
self.get_node(key).map(|x| &x.value)
}
pub fn get_and_bump_mut(&mut self, key: &K, from_now: Duration) -> Option<&mut V> {
if self.get_node(key).is_none() {
return None;
}
self.update_expiry(&key, Instant::now() + from_now);
self.get_mut(key)
}
pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
self.get_node_mut(key).map(|x| &mut x.value)
}
pub fn get_node(&self, key: &K) -> Option<&EphemeralNode<V>> {
let node = if let Some(node) = self.entry_map.get(&key) {
node
} else {
return None;
};
if node.is_expired() {
return None;
}
Some(node)
}
fn get_node_mut(&mut self, key: &K) -> Option<&mut EphemeralNode<V>> {
let node = if let Some(node) = self.entry_map.get_mut(&key) {
node
} else {
return None;
};
if node.is_expired() {
return None;
}
Some(node)
}
pub fn update_expiry(&mut self, key: &K, expires_at: Instant) {
let node = if let Some(node) = self.entry_map.get_mut(key) {
node
} else {
return;
};
let old_expiry = node.expires_at;
node.expires_at = expires_at;
self.remove_expiry(key, old_expiry);
self.add_expiry(key.clone(), expires_at);
}
pub fn entry(&mut self, key: K) -> EphemeralEntry<'_, K, V> {
EphemeralEntry { map: self, key }
}
}
pub struct EphemeralNode<V> {
expires_at: Instant,
value: V,
}
impl<V: Debug> Debug for EphemeralNode<V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EphemeralNode")
.field("expires_at", &self.expires_at)
.field("value", &self.value)
.finish()
}
}
impl<V> EphemeralNode<V> {
pub fn is_expired(&self) -> bool {
self.expires_at <= Instant::now()
}
pub fn expires_at(&self) -> Instant {
self.expires_at
}
pub fn value(&self) -> &V {
&self.value
}
pub fn value_mut(&mut self) -> &mut V {
&mut self.value
}
pub fn into_value(self) -> V {
self.value
}
}
pub struct EphemeralEntry<'map, K: Ord + Clone, V> {
map: &'map mut EphemeralMap<K, V>,
key: K,
}
impl<'map, K: Ord + Clone + Debug, V> EphemeralEntry<'map, K, V> {
pub fn or_insert_with<F: FnOnce() -> V>(self, expires_at: Instant, f: F) -> &'map mut V {
self.or_insert(expires_at, f())
}
pub fn or_insert(self, expires_at: Instant, default: V) -> &'map mut V {
self.map.insert(self.key.clone(), default, expires_at);
self.map.get_mut(&self.key).unwrap()
}
pub fn and_modify<F: FnOnce(&mut V)>(self, f: F) -> Self {
if let Some(item) = self.map.get_mut(&self.key) {
f(item)
}
self
}
}
impl<'map, K: Ord + Clone + Debug, V: Default> EphemeralEntry<'map, K, V> {
pub fn or_insert_default(self, expires_at: Instant) -> &'map mut V {
self.or_insert(expires_at, Default::default())
}
}
#[derive(Default)]
pub struct EphemeralSet<K: Clone + Ord>(EphemeralMap<K, ()>);
impl<K: Debug + Clone + Ord> Debug for EphemeralSet<K> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_map()
.entries(
self.0
.entry_map
.iter()
.map(|(key, node)| (key, node.expires_at)),
)
.finish()
}
}
impl<K: Clone + Ord + Debug> EphemeralSet<K> {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn new() -> Self {
EphemeralSet(EphemeralMap::new())
}
pub fn clean(&mut self) {
self.0.clean()
}
pub fn insert(&mut self, key: K, expires_at: Instant) -> bool {
self.0.insert(key, (), expires_at).is_none()
}
pub fn remove(&mut self, key: &K) -> bool {
self.0.remove(key).is_some()
}
pub fn contains(&self, key: &K) -> bool {
self.0.get_node(key).is_some()
}
pub fn remove_first(&mut self) -> Option<K> {
loop {
let first_key = self.0.entry_map.keys().next().cloned();
let item = if let Some(key) = first_key {
key
} else {
break;
};
if self.contains(&item) {
self.remove(&item);
return Some(item);
}
}
None
}
}
#[derive(Default)]
pub struct EphemeralQueueMap<K: Clone + Ord, V>(EphemeralMap<K, Vec<EphemeralNode<V>>>);
impl<K: Debug + Clone + Ord, V: Debug> Debug for EphemeralQueueMap<K, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_map().entries(self.0.entry_map.iter()).finish()
}
}
impl<K: Clone + Ord + Debug, V> EphemeralQueueMap<K, V> {
pub fn clean(&mut self) {
self.0.clean();
}
pub fn insert(&mut self, key: K, value: V, expires_at: Instant) {
let update_expiry = if let Some(node) = self.0.get_node_mut(&key) {
let mut old = std::mem::replace(&mut node.value, vec![]);
old.push(EphemeralNode { value, expires_at });
while let Some(old_node) = old.pop() {
if old_node.is_expired() {
continue;
}
node.value.push(old_node)
}
node.expires_at < expires_at
} else {
self.0.insert(
key.clone(),
vec![EphemeralNode { value, expires_at }],
expires_at,
);
false
};
if update_expiry {
self.0.update_expiry(&key, expires_at);
}
}
pub fn remove(&mut self, key: &K) {
self.0.remove(key);
}
pub fn pop(&mut self, key: &K) -> Option<V> {
if let Some(node) = self.0.get_node_mut(key) {
let old_values = std::mem::replace(&mut node.value, vec![]);
let mut selected = None;
let mut expiry: Option<Instant> = None;
for value in old_values {
if value.is_expired() {
continue;
}
if selected.is_none() {
selected = Some(value);
continue;
}
if *expiry.get_or_insert(value.expires_at) > value.expires_at {
expiry = Some(value.expires_at)
}
node.value.push(value)
}
if !node.value.is_empty() {
self.0.update_expiry(key, expiry.unwrap());
} else {
self.0.remove(key);
}
selected.map(|x| x.value)
} else {
None
}
}
}