use crate::oid::Oid;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OidTable<V> {
entries: Vec<(Oid, V)>,
}
impl<V> OidTable<V> {
#[must_use]
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
entries: Vec::with_capacity(capacity),
}
}
pub fn insert(&mut self, oid: Oid, value: V) {
match self.entries.binary_search_by(|(o, _)| o.cmp(&oid)) {
Ok(idx) => self.entries[idx].1 = value,
Err(idx) => self.entries.insert(idx, (oid, value)),
}
}
pub fn remove(&mut self, oid: &Oid) -> Option<V> {
match self.entries.binary_search_by(|(o, _)| o.cmp(oid)) {
Ok(idx) => Some(self.entries.remove(idx).1),
Err(_) => None,
}
}
#[must_use]
pub fn get(&self, oid: &Oid) -> Option<&V> {
match self.entries.binary_search_by(|(o, _)| o.cmp(oid)) {
Ok(idx) => Some(&self.entries[idx].1),
Err(_) => None,
}
}
#[must_use]
pub fn get_next(&self, oid: &Oid) -> Option<(&Oid, &V)> {
match self.entries.binary_search_by(|(o, _)| o.cmp(oid)) {
Ok(idx) => {
self.entries.get(idx + 1).map(|(o, v)| (o, v))
}
Err(idx) => {
self.entries.get(idx).map(|(o, v)| (o, v))
}
}
}
#[must_use]
pub fn len(&self) -> usize {
self.entries.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn iter(&self) -> impl Iterator<Item = (&Oid, &V)> {
self.entries.iter().map(|(o, v)| (o, v))
}
}
impl<V> Default for OidTable<V> {
fn default() -> Self {
Self::new()
}
}
impl<V> FromIterator<(Oid, V)> for OidTable<V> {
fn from_iter<T: IntoIterator<Item = (Oid, V)>>(iter: T) -> Self {
let mut entries = iter.into_iter().collect::<Vec<_>>();
entries.sort_by(|(left, _), (right, _)| left.cmp(right));
let mut deduplicated: Vec<(Oid, V)> = Vec::with_capacity(entries.len());
for entry in entries {
if let Some(previous) = deduplicated.last_mut()
&& previous.0 == entry.0
{
*previous = entry;
continue;
}
deduplicated.push(entry);
}
Self {
entries: deduplicated,
}
}
}
impl<V> Extend<(Oid, V)> for OidTable<V> {
fn extend<T: IntoIterator<Item = (Oid, V)>>(&mut self, iter: T) {
let existing = std::mem::take(&mut self.entries);
*self = existing.into_iter().chain(iter).collect();
}
}
impl<V> IntoIterator for OidTable<V> {
type Item = (Oid, V);
type IntoIter = std::vec::IntoIter<(Oid, V)>;
fn into_iter(self) -> Self::IntoIter {
self.entries.into_iter()
}
}
impl<'a, V> IntoIterator for &'a OidTable<V> {
type Item = (&'a Oid, &'a V);
type IntoIter =
std::iter::Map<std::slice::Iter<'a, (Oid, V)>, fn(&'a (Oid, V)) -> (&'a Oid, &'a V)>;
fn into_iter(self) -> Self::IntoIter {
self.entries.iter().map(|(o, v)| (o, v))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::oid;
#[test]
fn test_oid_table_insert_and_get() {
let mut table: OidTable<i32> = OidTable::new();
table.insert(oid!(1, 3, 6, 1, 2), 100);
table.insert(oid!(1, 3, 6, 1, 1), 50);
table.insert(oid!(1, 3, 6, 1, 3), 150);
assert_eq!(table.get(&oid!(1, 3, 6, 1, 1)), Some(&50));
assert_eq!(table.get(&oid!(1, 3, 6, 1, 2)), Some(&100));
assert_eq!(table.get(&oid!(1, 3, 6, 1, 3)), Some(&150));
assert_eq!(table.get(&oid!(1, 3, 6, 1, 4)), None);
}
#[test]
fn test_oid_table_update_existing() {
let mut table: OidTable<i32> = OidTable::new();
table.insert(oid!(1, 3, 6, 1, 1), 50);
table.insert(oid!(1, 3, 6, 1, 1), 100);
assert_eq!(table.get(&oid!(1, 3, 6, 1, 1)), Some(&100));
assert_eq!(table.len(), 1);
}
#[test]
fn test_oid_table_get_next() {
let mut table: OidTable<i32> = OidTable::new();
table.insert(oid!(1, 3, 6, 1, 1), 50);
table.insert(oid!(1, 3, 6, 1, 2), 100);
table.insert(oid!(1, 3, 6, 1, 3), 150);
let next = table.get_next(&oid!(1, 3, 6, 1, 0));
assert!(next.is_some());
assert_eq!(next.unwrap().0, &oid!(1, 3, 6, 1, 1));
let next = table.get_next(&oid!(1, 3, 6, 1, 1));
assert!(next.is_some());
assert_eq!(next.unwrap().0, &oid!(1, 3, 6, 1, 2));
let next = table.get_next(&oid!(1, 3, 6, 1, 1, 5));
assert!(next.is_some());
assert_eq!(next.unwrap().0, &oid!(1, 3, 6, 1, 2));
let next = table.get_next(&oid!(1, 3, 6, 1, 3));
assert!(next.is_none());
let next = table.get_next(&oid!(1, 3, 6, 1, 4));
assert!(next.is_none());
}
#[test]
fn test_oid_table_remove() {
let mut table: OidTable<i32> = OidTable::new();
table.insert(oid!(1, 3, 6, 1, 1), 50);
table.insert(oid!(1, 3, 6, 1, 2), 100);
assert_eq!(table.remove(&oid!(1, 3, 6, 1, 1)), Some(50));
assert_eq!(table.remove(&oid!(1, 3, 6, 1, 1)), None);
assert_eq!(table.len(), 1);
}
#[test]
fn test_oid_table_iter() {
let mut table: OidTable<i32> = OidTable::new();
table.insert(oid!(1, 3, 6, 1, 3), 150);
table.insert(oid!(1, 3, 6, 1, 1), 50);
table.insert(oid!(1, 3, 6, 1, 2), 100);
let entries: Vec<_> = table.iter().collect();
assert_eq!(entries.len(), 3);
assert_eq!(entries[0].0, &oid!(1, 3, 6, 1, 1));
assert_eq!(entries[1].0, &oid!(1, 3, 6, 1, 2));
assert_eq!(entries[2].0, &oid!(1, 3, 6, 1, 3));
}
#[test]
fn test_oid_table_empty() {
let table: OidTable<i32> = OidTable::new();
assert!(table.is_empty());
assert_eq!(table.len(), 0);
assert!(table.get_next(&oid!(1, 3, 6, 1)).is_none());
}
#[test]
fn from_iter_sorts_once_and_retains_last_duplicate() {
let first = oid!(1, 3, 6, 1, 1);
let second = oid!(1, 3, 6, 1, 2);
let third = oid!(1, 3, 6, 1, 3);
let table = OidTable::from_iter([
(third.clone(), "third"),
(first.clone(), "old first"),
(second.clone(), "second"),
(first.clone(), "new first"),
]);
assert_eq!(table.len(), 3);
assert_eq!(table.get(&first), Some(&"new first"));
assert_eq!(
table.iter().map(|(oid, _)| oid).collect::<Vec<_>>(),
[&first, &second, &third]
);
}
#[test]
fn extend_uses_last_new_value_and_owned_iteration_is_sorted() {
let first = oid!(1, 3, 6, 1, 1);
let second = oid!(1, 3, 6, 1, 2);
let third = oid!(1, 3, 6, 1, 3);
let mut table = OidTable::from_iter([(first.clone(), 1), (second.clone(), 2)]);
table.extend([(third.clone(), 3), (first.clone(), 10), (first.clone(), 11)]);
assert_eq!(
table.into_iter().collect::<Vec<_>>(),
[(first, 11), (second, 2), (third, 3)]
);
}
}