co_primitives/library/
node_reader.rs1use crate::{from_cbor, MultiCodec, Node, Storage};
5use cid::Cid;
6use serde::de::DeserializeOwned;
7use std::collections::VecDeque;
8
9#[derive(Debug, thiserror::Error)]
10pub enum NodeReaderError {
11 #[error("Invalid argument")]
12 InvalidArgument(#[source] anyhow::Error),
13
14 #[error("Decode failed")]
15 Decode(#[source] anyhow::Error),
16}
17
18pub fn node_reader<T>(storage: &dyn Storage, cid: Option<Cid>) -> impl Iterator<Item = Result<T, NodeReaderError>> + '_
19where
20 T: Clone + DeserializeOwned + 'static,
21{
22 NodeIterator::new(storage, cid)
23}
24
25pub struct NodeIterator<'a, T>
26where
27 T: 'a + Clone + DeserializeOwned,
28{
29 storage: &'a dyn Storage,
30 stack: VecDeque<Cid>,
31 entries: VecDeque<T>,
32}
33
34impl<'a, T> NodeIterator<'a, T>
35where
36 T: Clone + DeserializeOwned,
37{
38 pub fn new(storage: &'a dyn Storage, cid: Option<Cid>) -> Self {
39 let mut stack = VecDeque::new();
40 if let Some(cid) = cid {
41 stack.push_front(cid);
42 }
43 Self { storage, stack, entries: Default::default() }
44 }
45}
46
47impl<'a, T> Iterator for NodeIterator<'a, T>
48where
49 T: 'a + Clone + DeserializeOwned,
50{
51 type Item = Result<T, NodeReaderError>;
52
53 fn next(&mut self) -> Option<Self::Item> {
54 while self.entries.is_empty() && !self.stack.is_empty() {
56 if let Some(next_cid) = self.stack.pop_front() {
57 let node = match read_node(self.storage, &next_cid) {
58 Ok(n) => n,
59 Err(e) => return Some(Err(e)),
60 };
61 match node {
62 Node::Node(links) => {
63 self.stack.extend(links.into_iter().map(|link| -> Cid { link.into() }));
64 },
65 Node::Leaf(entries) => self.entries = entries.into(),
66 }
67 }
68 }
69
70 self.entries.pop_front().map(|entry| Ok(entry))
72 }
73}
74
75fn read_node<T: Clone + DeserializeOwned>(storage: &dyn Storage, cid: &Cid) -> Result<Node<T>, NodeReaderError> {
76 let block = storage.get(MultiCodec::with_cbor(cid).map_err(|err| NodeReaderError::InvalidArgument(err.into()))?);
78
79 let node: Node<T> = from_cbor(block.data()).map_err(|e| NodeReaderError::Decode(e.into()))?;
81
82 Ok(node)
84}