use super::chunk_storage::ChunkStorage;
use crate::traits::record::Record;
use crate::traits::valid_key::{BorrowedKey, ValidKey};
use std::borrow::Cow;
use std::fmt::Debug;
pub struct Entry<'a, R, ChunkKey: ?Sized, ItemKey: ?Sized, Element>
where
R: Record<ChunkKey, ItemKey> + 'a,
ChunkKey: BorrowedKey,
ChunkKey::Owned: ValidKey,
ItemKey: BorrowedKey,
ItemKey::Owned: ValidKey,
{
id: R,
idx: Option<usize>,
storage: &'a mut ChunkStorage<ChunkKey, ItemKey, Element>,
}
impl<'a, R, ChunkKey, ItemKey, Element> Entry<'a, R, ChunkKey, ItemKey, Element>
where
R: Record<ChunkKey, ItemKey> + 'a,
ChunkKey: BorrowedKey + ?Sized,
ChunkKey::Owned: ValidKey,
ItemKey: BorrowedKey + ?Sized,
ItemKey::Owned: ValidKey,
Element: Record<ChunkKey, ItemKey>,
{
pub(super) fn new(
id: R,
idx: Option<usize>,
storage: &'a mut ChunkStorage<ChunkKey, ItemKey, Element>,
) -> Self {
Entry { id, idx, storage }
}
pub fn id(&self) -> &R {
&self.id
}
pub fn or_insert_with<F>(mut self, f: F) -> &'a mut Element
where
F: FnOnce() -> Element,
{
if let Some(idx) = self.idx {
self.storage.get_idx_mut(idx)
} else {
let new_value: Element = f();
let new_chunk_key: Cow<ChunkKey> = new_value.chunk_key();
let old_chunk_key: Cow<ChunkKey> = Record::<ChunkKey, ItemKey>::chunk_key(&self.id);
let new_item_key: Cow<ItemKey> = new_value.item_key();
let old_item_key: Cow<ItemKey> = Record::<ChunkKey, ItemKey>::item_key(&self.id);
assert_eq!(
new_chunk_key, old_chunk_key,
"entry: inserted chunk key does not match entry chunk key"
);
assert_eq!(
new_item_key, old_item_key,
"entry: inserted item key does not match entry item key"
);
let idx = self.storage.add(new_value);
self.idx = Some(idx);
self.storage.get_idx_mut(idx)
}
}
pub fn and_modify<F>(mut self, f: F) -> Self
where
F: FnOnce(&mut Element),
{
if let Some(element) = self.get_mut() {
f(element);
}
self
}
pub fn or_panic(self) -> Self
where
R: Debug,
{
self.get().or_else(|| {
panic!(format!(
"retriever: Entry::or_panic(): {:?} doesn't exist",
&self.id
))
});
self
}
pub fn get(&self) -> Option<&Element> {
self.idx.map(|idx| self.storage.get_idx(idx))
}
pub fn get_mut(&mut self) -> Option<&mut Element> {
self.idx.map(move |idx| self.storage.get_idx_mut(idx))
}
pub fn remove(mut self) -> Option<Element> {
let idx = self.idx?;
self.idx = None;
Some(self.storage.remove_idx(idx))
}
pub fn remove_if<F>(self, mut f: F) -> Option<Element>
where
F: FnMut(&Element) -> bool,
{
let should_remove = if let Some(e) = self.get() {
f(e)
} else {
false
};
if should_remove {
self.remove()
} else {
None
}
}
}