entry api
This commit is contained in:
parent
a1a5b08970
commit
577abca2db
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue