From 0829eb41c4f2e6f0e4ec4911b109622ccb7878c8 Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Mon, 20 Nov 2023 19:30:16 -0800 Subject: [PATCH] Inliners & flake --- flake.nix | 6 ++ src/inliner.rs | 137 +++++++++++++++++--------------------- src/lib.rs | 8 +-- src/store/at_most_once.rs | 6 +- src/store/memory.rs | 20 +++++- src/store/traits.rs | 11 +++ 6 files changed, 103 insertions(+), 85 deletions(-) diff --git a/flake.nix b/flake.nix index 72f3d65..a8121f7 100644 --- a/flake.nix +++ b/flake.nix @@ -137,6 +137,12 @@ category = "test"; command = "${pkgs.cargo}/bin/cargo test"; } + { + name = "docs"; + help = "Open refreshed docs"; + category = "dev"; + command = "${pkgs.cargo}/bin/cargo doc --open"; + } ]; }; diff --git a/src/inliner.rs b/src/inliner.rs index 74043bd..9e7c609 100644 --- a/src/inliner.rs +++ b/src/inliner.rs @@ -1,107 +1,92 @@ +pub mod quiet; + use crate::iterator::post_order::PostOrderIpldIter; use crate::store::traits::Store; use libipld::{cid::Cid, ipld::Ipld}; -use std::cell::RefCell; -use std::clone::Clone; -use std::collections::BTreeMap; +use quiet::Quiet; +use std::{cell::RefCell, clone::Clone, ops::ControlFlow}; #[derive(Clone, Debug)] pub struct Inliner<'a, S: Store> { - po_cell: RefCell, - store: &'a S, // FIXME check clone performance - stack: Vec, + inliner: Quiet<'a, S>, + stuck_at: Option, } -impl<'a, S: Store + Clone> Inliner<'a, S> { +impl<'a, S: Store> Inliner<'a, S> { pub fn new(ipld: Ipld, store: &'a S) -> Self { - Inliner { + let inliner = Quiet { po_cell: RefCell::new(PostOrderIpldIter::from(ipld)), stack: vec![], store, + }; + + Inliner { + inliner, + stuck_at: None, } } - pub fn quiet_last(&mut self) -> Option { - self.fold(None, |acc, result| match result { - Ok(ipld) => Some(ipld), - Err(stuck) => { - stuck.ignore(); - acc - } - }) + pub fn wants(&self) -> Option { + self.stuck_at } -} -impl<'a, S: Store + Clone> Iterator for Inliner<'a, S> { - type Item = Result>; + pub fn next_until_stuck(&mut self) -> Option> { + let found = self.try_fold(None, |_, result| match result { + Ok(_) => ControlFlow::Continue(Some(result)), + Err(_) => ControlFlow::Break(Some(result)), + }); - fn next(&mut self) -> Option { - for node in self.po_cell.get_mut() { - match node { - Ipld::Link(cid) => { - if let Ok(ipld) = self.store.get(&cid) { - let mut inner = BTreeMap::new(); - inner.insert("link".to_string(), Ipld::Link(cid)); - inner.insert("data".to_string(), ipld.clone()); - - let mut outer = BTreeMap::new(); - outer.insert("/".to_string(), Ipld::Map(inner)); - - self.stack.push(Ipld::Map(outer)); - } else { - return Some(Err(Stuck { - need: cid, - inliner: Box::new(self.clone()), - })); - } - } - - Ipld::Map(btree) => { - let keys = btree.keys(); - let vals = self.stack.split_off(self.stack.len() - keys.len()); - let new_btree = keys.cloned().zip(vals).collect(); - self.stack.push(Ipld::Map(new_btree)); - } - - Ipld::List(vec) => { - let new_vec = self.stack.split_off(self.stack.len() - vec.len()); - self.stack.push(Ipld::List(new_vec)); - } - - node => { - self.stack.push(node.clone()); - } - } + match found { + ControlFlow::Break(opt_result) => opt_result, + ControlFlow::Continue(opt_result) => opt_result, } + } - let root = self - .stack - .pop() - .expect("should have exactly one item on the stack"); + pub fn ignore(&mut self) -> Option<()> { + self.stuck_at.map(|cid| { + self.inliner.stack.push(Ipld::Link(cid)); + self.stuck_at = None; + }) + } - Some(Ok(root)) + // FIXME don't 100% love this + pub fn resolve(&mut self, ipld: Ipld) -> Option<()> { + self.stuck_at.map(|_| { + self.inliner.stack.push(ipld); + self.stuck_at = None; + }) } } -#[derive(Clone, Debug)] -pub struct Stuck<'a, S: Store + Clone> { - need: Cid, - inliner: Box>, +impl<'a, S: Store> From> for Inliner<'a, S> { + fn from(inliner: Quiet<'a, S>) -> Self { + Inliner { + inliner, + stuck_at: None, + } + } } -impl<'a, S: Store + Clone> Stuck<'a, S> { - pub fn wants(&self) -> &Cid { - &self.need +impl<'a, S: Store> From> for Quiet<'a, S> { + fn from(inliner: Inliner<'a, S>) -> Self { + inliner.inliner } +} - pub fn resolve(self, ipld: Ipld) -> Option> { - let mut il = *self.inliner; - il.stack.push(ipld); - Some(il) - } +impl<'a, S: Store> Iterator for Inliner<'a, S> { + type Item = Result; - pub fn ignore(self) -> Option> { - let cid = self.need; - self.resolve(Ipld::Link(cid)) + fn next(&mut self) -> Option { + if self.stuck_at.is_some() { + return None; + } + + match self.inliner.next() { + Some(Err(cid)) => { + self.stuck_at = Some(cid); + Some(Err(cid)) + } + otherwise => otherwise, + } } } diff --git a/src/lib.rs b/src/lib.rs index e6a42e2..c030a3f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,14 +9,14 @@ use crate::store::traits::Store; use libipld::{cid::Version, codec_impl::IpldCodec, Ipld}; use multihash::Code::Sha2_256; -pub fn inline(ipld: Ipld, store: &S) -> Ipld { +pub fn inline(ipld: Ipld, store: &impl Store) -> Ipld { Inliner::new(ipld, store) - .quiet_last() + .last() + .expect("should have at least the `Ipld` that was passed in") .expect("should have at least the `Ipld` that was passed in") } -pub fn extract(ipld: Ipld) -> S { - let mut store: S = Default::default(); +pub fn extract(ipld: Ipld, store: &mut S) -> &S { store.extract(ipld, IpldCodec::DagCbor, &Sha2_256, Version::V1); store } diff --git a/src/store/at_most_once.rs b/src/store/at_most_once.rs index 0ed3766..85b0ae8 100644 --- a/src/store/at_most_once.rs +++ b/src/store/at_most_once.rs @@ -3,10 +3,12 @@ use libipld::{error::BlockNotFound, Cid, Ipld}; use std::cell::RefCell; use std::collections::hash_set::HashSet; +// NOTE opposite of inliner::Quiet + #[derive(Clone, Debug)] pub struct AtMostOnceStore { - pub store: S, - pub tombstones: RefCell>, + store: S, + tombstones: RefCell>, } impl From for AtMostOnceStore { diff --git a/src/store/memory.rs b/src/store/memory.rs index 4e22700..ca94247 100644 --- a/src/store/memory.rs +++ b/src/store/memory.rs @@ -3,17 +3,31 @@ use libipld::error::BlockNotFound; use libipld::{Cid, Ipld}; use std::collections::BTreeMap; +// More convenient to use and clearer to read than BTree + #[derive(Clone, Debug, Default)] pub struct MemoryStore { - pub store: BTreeMap, + store: BTreeMap, +} + +impl From> for MemoryStore { + fn from(store: BTreeMap) -> Self { + MemoryStore { store } + } +} + +impl From for BTreeMap { + fn from(ms: MemoryStore) -> Self { + ms.store + } } impl Store for MemoryStore { fn get(&self, cid: &Cid) -> Result<&Ipld, BlockNotFound> { - self.store.get(cid).ok_or(BlockNotFound(*cid)) + Store::get(&self.store, cid) } fn put_keyed(&mut self, cid: Cid, ipld: Ipld) { - self.store.insert(cid, ipld); + self.store.put_keyed(cid, ipld) } } diff --git a/src/store/traits.rs b/src/store/traits.rs index e9c8451..4a28ee1 100644 --- a/src/store/traits.rs +++ b/src/store/traits.rs @@ -9,6 +9,7 @@ use libipld::{ IpldCodec, }; use multihash::MultihashDigest; +use std::collections::BTreeMap; use thiserror::Error; pub trait Store { @@ -73,3 +74,13 @@ pub enum GetRawError { #[error("failed to encode to bytes")] EncodeFailed(#[from] libipld::error::Error), } + +impl Store for BTreeMap { + fn get(&self, cid: &Cid) -> Result<&Ipld, BlockNotFound> { + self.get(cid).ok_or(BlockNotFound(*cid)) + } + + fn put_keyed(&mut self, cid: Cid, ipld: Ipld) { + self.insert(cid, ipld); + } +} -- knotmirror 0.0.1