entry api

This commit is contained in:
Janis 2023-04-05 17:32:33 +02:00
parent a1a5b08970
commit 577abca2db

View file

@ -166,6 +166,7 @@ impl Display for NodeHandle {
} }
} }
/// range of nodes that iterates thru all leaf nodes from start to end, inclusively.
#[derive(Debug)] #[derive(Debug)]
pub struct Range<'tree, R: super::Read> { pub struct Range<'tree, R: super::Read> {
volume: Rc<Volume<R>>, volume: Rc<Volume<R>>,
@ -174,6 +175,66 @@ pub struct Range<'tree, R: super::Read> {
phantom: PhantomData<&'tree ()>, phantom: PhantomData<&'tree ()>,
} }
pub mod entry {
use super::*;
#[derive(Debug, PartialEq, Eq)]
pub enum Entry<'tree> {
Occupied(OccupiedEntry<'tree>),
Vacant(VacantEntry<'tree>),
}
impl<'tree> From<VacantEntry<'tree>> for Entry<'tree> {
fn from(v: VacantEntry<'tree>) -> Self {
Self::Vacant(v)
}
}
impl<'tree> From<OccupiedEntry<'tree>> for Entry<'tree> {
fn from(v: OccupiedEntry<'tree>) -> Self {
Self::Occupied(v)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct OccupiedEntry<'tree> {
key: Key,
node: NodeHandle,
phantom: PhantomData<&'tree ()>,
}
impl<'tree> OccupiedEntry<'tree> {
pub fn new(key: Key, node: NodeHandle) -> Self {
Self {
key,
node,
phantom: PhantomData,
}
}
pub fn key(&self) -> Key {
self.key
}
pub fn item(&self) -> Result<TreeItem> {
Ok(self.node.parse_item()?.1)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct VacantEntry<'tree> {
phantom: PhantomData<&'tree ()>,
}
impl<'tree> VacantEntry<'tree> {
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
}
#[derive(Derivative)] #[derive(Derivative)]
#[derivative(Debug)] #[derivative(Debug)]
pub struct Tree<R: super::Read> { pub struct Tree<R: super::Read> {
@ -250,12 +311,36 @@ impl<R: super::Read> Tree<R> {
self.find_node_inner(key, NodeHandle::find_key) self.find_node_inner(key, NodeHandle::find_key)
} }
pub fn entry<K>(&self, key: &K) -> Result<entry::Entry>
where
K: PartialEq<Key> + PartialOrd<Key>,
{
let entry: entry::Entry = match self.find_node(key)? {
Some(node) => entry::OccupiedEntry::new(node.parse_key(), node).into(),
None => entry::VacantEntry::new().into(),
};
Ok(entry)
}
pub fn entry_rev<K>(&self, key: &K) -> Result<entry::Entry>
where
K: PartialEq<Key> + PartialOrd<Key>,
{
let entry: entry::Entry = match self.find_node_rev(key)? {
Some(node) => entry::OccupiedEntry::new(node.parse_key(), node).into(),
None => entry::VacantEntry::new().into(),
};
Ok(entry)
}
pub fn find_key<K>(&self, key: &K) -> Result<Option<(Item, TreeItem)>> pub fn find_key<K>(&self, key: &K) -> Result<Option<(Item, TreeItem)>>
where where
K: PartialEq<Key> + PartialOrd<Key>, K: PartialEq<Key> + PartialOrd<Key>,
{ {
match self.find_node(key)? { match self.find_node(key)? {
Some(node) => node.parse_item(), Some(node) => node.parse_item().map(|item| Some(item)),
None => Ok(None), None => Ok(None),
} }
} }
@ -265,7 +350,7 @@ impl<R: super::Read> Tree<R> {
K: PartialEq<Key> + PartialOrd<Key>, K: PartialEq<Key> + PartialOrd<Key>,
{ {
match self.find_node_rev(key)? { match self.find_node_rev(key)? {
Some(node) => node.parse_item(), Some(node) => node.parse_item().map(|item| Some(item)),
None => Ok(None), None => Ok(None),
} }
} }
@ -556,19 +641,43 @@ impl Node {
Ok(Self { inner, bytes }) Ok(Self { inner, bytes })
} }
/// returns Ok(None) if `i` is out of bounds
fn read_nth_key(&self, i: usize) -> Option<Key> {
match &self.inner {
BTreeNode::Internal(internal) => {
let item = internal
.children
.get(i)
.map(|child| *unsafe { &*child.as_ptr() }.key());
item
}
BTreeNode::Leaf(leaf) => {
let key = leaf.items.get(i).map(|item| item.key);
key
}
}
}
/// returns None if pointing at an internal node or `i` is out of bounds.
/// returns an Error if parsing the item failed.
pub fn read_nth_item(&self, i: usize) -> Result<Option<(Item, TreeItem)>> { pub fn read_nth_item(&self, i: usize) -> Result<Option<(Item, TreeItem)>> {
match &self.inner { match &self.inner {
BTreeNode::Internal(_) => Ok(None), BTreeNode::Internal(_) => Ok(None),
BTreeNode::Leaf(leaf) => { BTreeNode::Leaf(leaf) => {
// TODO: better error to indicate that it was out of bounds // TODO: better error to indicate that it was out of bounds
let item = leaf.items.get(i).ok_or(Error::ReadFailed)?; let item = if let Some(item) = leaf.items.get(i) {
let start = size_of::<Header>() + item.offset.get() as usize; let start = size_of::<Header>() + item.offset.get() as usize;
let size = item.size.get() as usize; let size = item.size.get() as usize;
let bytes = &self.bytes[start..start + size]; let bytes = &self.bytes[start..start + size];
let value = TreeItem::parse(item, bytes)?; let value = TreeItem::parse(item, bytes)?;
Some((*item, value))
} else {
None
};
Ok(Some((*item, value))) Ok(item)
} }
} }
} }
@ -613,7 +722,7 @@ where
}); });
if self.start.node.inner.is_leaf() { if self.start.node.inner.is_leaf() {
break self.start.as_handle().parse_item().expect("range item"); break Some(self.start.as_handle().parse_item().expect("range item"));
} }
// else repeat // else repeat
} else { } else {
@ -638,7 +747,7 @@ where
}); });
if self.end.node.inner.is_leaf() { if self.end.node.inner.is_leaf() {
break self.end.as_handle().parse_item().expect("range item"); break Some(self.end.as_handle().parse_item().expect("range item"));
} }
// else repeat // else repeat
} else { } else {
@ -658,8 +767,19 @@ impl NodeHandle {
} }
} }
pub fn parse_item(&self) -> Result<Option<(Item, TreeItem)>> { /// returns None if pointing at an internal node or `i` is out of bounds.
self.node.read_nth_item(self.idx as usize) /// returns an Error if parsing the item failed.
pub fn parse_item(&self) -> Result<(Item, TreeItem)> {
self.node
.read_nth_item(self.idx as usize)
.map(|result| result.unwrap())
}
/// returns an Error if the key read fails
pub fn parse_key(&self) -> Key {
self.node
.read_nth_key(self.idx as usize)
.expect("idx out of bounds")
} }
pub fn advance_sideways(self) -> NodeHandleAdvanceResult { pub fn advance_sideways(self) -> NodeHandleAdvanceResult {