use crate::{Storage, StorageError};
use cid::Cid;
use co_primitives::{BlockSerializer, MultiCodec, Node};
use serde::de::DeserializeOwned;
use std::collections::VecDeque;
pub fn node_reader<'a, T, S: Storage>(storage: &'a S, cid: &'a Cid) -> impl Iterator<Item = anyhow::Result<T>> + 'a
where
T: Clone + DeserializeOwned + 'static,
{
NodeIterator::new(storage, cid)
}
struct NodeIterator<'a, T, S>
where
T: Clone + DeserializeOwned,
{
storage: &'a S,
stack: VecDeque<Cid>,
entries: VecDeque<T>,
}
impl<'a, T, S> NodeIterator<'a, T, S>
where
T: Clone + DeserializeOwned,
S: Storage,
{
pub fn new(storage: &'a S, cid: &Cid) -> Self {
let mut stack = VecDeque::new();
stack.push_front(*cid);
Self { storage, stack, entries: Default::default() }
}
}
impl<'a, T, S> Iterator for NodeIterator<'a, T, S>
where
T: Clone + DeserializeOwned,
S: Storage,
{
type Item = anyhow::Result<T>;
fn next(&mut self) -> Option<Self::Item> {
while self.entries.is_empty() && !self.stack.is_empty() {
if let Some(next_cid) = self.stack.pop_front() {
let node = match read_node(self.storage, &next_cid) {
Ok(n) => n,
Err(e) => return Some(Err(e.into())),
};
match node {
Node::Node(links) => {
self.stack.extend(links.into_iter().map(|link| -> Cid { link.into() }));
},
Node::Leaf(entries) => self.entries = entries.into(),
}
}
}
self.entries.pop_front().map(|entry| Ok(entry))
}
}
fn read_node<T: Clone + DeserializeOwned, S: Storage>(storage: &S, cid: &Cid) -> Result<Node<T>, StorageError> {
let block = storage.get(MultiCodec::with_cbor(cid)?)?;
let node: Node<T> = BlockSerializer::new()
.deserialize(&block)
.map_err(|e| StorageError::InvalidArgument(e.into()))?;
Ok(node)
}