From 20f580d03e94cbfaf8c1256a8a08b6cfe3ccab9f Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Wed, 27 Dec 2023 16:51:28 +0200 Subject: [PATCH] WIP killing clones --- inline_ipld/src/extractor.rs | 32 +++++++++++------ inline_ipld/src/inliner.rs | 2 +- inline_ipld/src/inliner/at_least_once.rs | 41 +++++++++++----------- inline_ipld/src/inliner/at_most_once.rs | 44 +++++++++++++----------- inline_ipld/src/inliner/traits.rs | 16 +++++---- inline_ipld/src/ipld/inlined.rs | 12 +++++-- inline_ipld/src/iterator/post_order.rs | 40 ++++++++++++--------- inline_ipld/src/store/traits.rs | 4 +-- 8 files changed, 109 insertions(+), 82 deletions(-) diff --git a/inline_ipld/src/extractor.rs b/inline_ipld/src/extractor.rs index 1e4978c..8338ccc 100644 --- a/inline_ipld/src/extractor.rs +++ b/inline_ipld/src/extractor.rs @@ -11,6 +11,7 @@ use libipld::{ ipld::Ipld, }; use multihash::MultihashDigest; +use std::collections::btree_map::{BTreeMap, Keys}; /// The general [`Ipld`] extraction strategy /// @@ -20,7 +21,7 @@ pub struct Extractor<'a, C, D> where D: MultihashDigest<64>, { - iterator: Peekable, + iterator: Peekable>, stack: Vec, codec: C, @@ -40,9 +41,14 @@ where /// * `codec` - The [`Codec`] to fall back to if the inline IPLD doesn't contain a [`Cid`] /// * `digester` - The hash digest function to use if the inline IPLD doesn't contain a [`Cid`] /// * `cid_version` - The [`Cid`] version to use if the inline IPLD doesn't contain a [`Cid`] - pub fn new(inline_ipld: InlineIpld, codec: C, digester: &'a D, cid_version: Version) -> Self { + pub fn new( + inline_ipld: &'a InlineIpld, + codec: C, + digester: &'a D, + cid_version: Version, + ) -> Self { Extractor { - iterator: >::into(inline_ipld.into()).peekable(), + iterator: PostOrderIpldIter::new(inline_ipld.into()).peekable(), stack: vec![], codec, digester, @@ -51,7 +57,7 @@ where } } -impl> Iterator for Extractor<'_, C, D> +impl<'a, C: Codec, D: MultihashDigest<64>> Iterator for Extractor<'a, C, D> where Ipld: Encode, { @@ -68,12 +74,14 @@ where ) }); } + Some(Ipld::List(inner_list)) => { let substack = self.stack.split_off(self.stack.len() - inner_list.len()); self.stack.push(Ipld::List(substack)); } + Some(Ipld::Map(btree)) => { - let keys: Vec<&String> = btree.keys().collect(); + let keys: Keys<'_, String, Ipld> = btree.keys(); if btree.get("data").is_some() { if keys.len() == 1 && is_delimiter_next(&mut self.iterator) { @@ -82,11 +90,10 @@ where let node = self .stack .pop() - .expect("updated child node of 'data' should be on the stack"); + .expect("updated child node of 'data' should be on the stack"); // FIXME - let cid: Cid = - cid::new(&node, self.codec, self.digester, self.cid_version) - .unwrap(); + let cid = cid::new(&node, self.codec, self.digester, self.cid_version) + .unwrap(); self.stack.push(Ipld::Link(cid)); return Some((cid, node)); @@ -111,9 +118,12 @@ where } let substack: Vec = self.stack.split_off(self.stack.len() - keys.len()); + let inner_map: BTreeMap = keys + .zip(substack) + .map(|(s, i)| (s.clone(), i.clone())) + .collect(); - self.stack - .push(Ipld::Map(keys.into_iter().cloned().zip(substack).collect())); + self.stack.push(Ipld::Map(inner_map)); } Some(node) => { diff --git a/inline_ipld/src/inliner.rs b/inline_ipld/src/inliner.rs index d958e73..2ff3bca 100644 --- a/inline_ipld/src/inliner.rs +++ b/inline_ipld/src/inliner.rs @@ -1,4 +1,4 @@ //! Inlining [`Ipld`][libipld::ipld::Ipld] from a content addressed store pub mod at_least_once; -pub mod at_most_once; +// pub mod at_most_once; pub mod traits; diff --git a/inline_ipld/src/inliner/at_least_once.rs b/inline_ipld/src/inliner/at_least_once.rs index cd53ada..b9013e1 100644 --- a/inline_ipld/src/inliner/at_least_once.rs +++ b/inline_ipld/src/inliner/at_least_once.rs @@ -18,23 +18,15 @@ use serde::{Deserialize, Serialize}; /// In general, you should prefer the use of the [`Inliner`] interface, over [`Iterator`]. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -pub struct AtLeastOnce { - po: PostOrderIpldIter, +pub struct AtLeastOnce<'a> { + po: PostOrderIpldIter<'a>, stack: Vec, - needs: Option, + needs: Option<&'a Cid>, } -impl AtLeastOnce { - // FIXME pass by ref? +impl<'a> AtLeastOnce<'a> { /// Initialize a new [`AtLeastOnce`] inliner - pub fn new(ipld: Ipld) -> Self { - ipld.into() - } -} - -impl From for AtLeastOnce { - // FIXME pass by ref? - fn from(ipld: Ipld) -> Self { + pub fn new(ipld: &'a Ipld) -> Self { AtLeastOnce { po: PostOrderIpldIter::from(ipld), stack: vec![], @@ -43,8 +35,14 @@ impl From for AtLeastOnce { } } -impl Iterator for AtLeastOnce { - type Item = Ipld; +impl<'a> From<&'a Ipld> for AtLeastOnce<'a> { + fn from(ipld: &'a Ipld) -> Self { + AtLeastOnce::new(ipld) + } +} + +impl<'a> Iterator for AtLeastOnce<'a> { + type Item = &'a Ipld; fn next(&mut self) -> Option { self.needs?; @@ -52,8 +50,7 @@ impl Iterator for AtLeastOnce { } } -impl<'a> Inliner<'a> for AtLeastOnce { - // FIXME just rename as something closer to `resolve` or `unstick`? +impl<'a> Inliner<'a> for AtLeastOnce<'a> { fn resolve(&mut self, ipld: Ipld) { self.stack.push(ipld); self.needs = None; @@ -68,7 +65,7 @@ impl<'a> Inliner<'a> for AtLeastOnce { Ipld::Link(cid) => { if let Ok(ipld) = store.get(&cid) { let mut inner = BTreeMap::new(); - inner.insert("link".to_string(), Ipld::Link(cid)); + inner.insert("link".to_string(), Ipld::Link(*cid)); inner.insert("data".to_string(), ipld.clone()); let mut outer = BTreeMap::new(); @@ -83,17 +80,19 @@ impl<'a> Inliner<'a> for AtLeastOnce { Ipld::Map(btree) => { let keys = btree.keys(); let vals: Vec = self.stack.split_off(self.stack.len() - keys.len()); - let new_btree = keys.cloned().zip(vals).collect(); + let new_btree = keys.zip(vals).map(|(k, v)| (k.clone(), v)).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); + node_ref => { + self.stack.push(node_ref.clone()); } } } diff --git a/inline_ipld/src/inliner/at_most_once.rs b/inline_ipld/src/inliner/at_most_once.rs index ba46eb7..1ae4fa5 100644 --- a/inline_ipld/src/inliner/at_most_once.rs +++ b/inline_ipld/src/inliner/at_most_once.rs @@ -18,14 +18,14 @@ use serde::{Deserialize, Serialize}; /// In general, you should prefer the use of the [`Inliner`] interface, over [`Iterator`]. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -pub struct AtMostOnce { - at_least_once: AtLeastOnce, +pub struct AtMostOnce<'a> { + at_least_once: &'a mut AtLeastOnce<'a>, seen: HashSet, } -impl AtMostOnce { +impl<'a> AtMostOnce<'a> { /// Initialize a new [`AtMostOnce`] inliner - pub fn new(ipld: Ipld) -> Self { + pub fn new(ipld: &'a Ipld) -> Self { AtMostOnce { at_least_once: AtLeastOnce::new(ipld), seen: HashSet::new(), @@ -33,14 +33,14 @@ impl AtMostOnce { } } -impl From for AtMostOnce { - fn from(ipld: Ipld) -> Self { +impl<'a> From<&'a Ipld> for AtMostOnce<'a> { + fn from(ipld: &'a Ipld) -> Self { AtMostOnce::new(ipld) } } -impl From for AtMostOnce { - fn from(at_least_once: AtLeastOnce) -> Self { +impl<'a> From> for AtMostOnce<'a> { + fn from(at_least_once: AtLeastOnce<'a>) -> Self { AtMostOnce { at_least_once, seen: HashSet::new(), @@ -48,21 +48,21 @@ impl From for AtMostOnce { } } -impl From for AtLeastOnce { - fn from(at_most_once: AtMostOnce) -> Self { +impl<'a> From> for AtLeastOnce<'a> { + fn from(at_most_once: AtMostOnce<'a>) -> Self { at_most_once.at_least_once } } -impl Iterator for AtMostOnce { - type Item = Ipld; +impl<'a> Iterator for AtMostOnce<'a> { + type Item = &'a Ipld; fn next(&mut self) -> Option { self.at_least_once.next() } } -impl<'a> Inliner<'a> for AtMostOnce { +impl<'a> Inliner<'a> for AtMostOnce<'a> { fn resolve(&mut self, ipld: Ipld) { self.at_least_once.resolve(ipld) } @@ -71,14 +71,16 @@ impl<'a> Inliner<'a> for AtMostOnce { &'a mut self, store: &S, ) -> Option>> { - let result = self.at_least_once.run(store)?; - match result { - Ok(inline) => Some(Ok(inline)), - Err(Stuck { needs, .. }) => { - if self.seen.contains(&needs) { - self.at_least_once.resolve(Ipld::Link(needs)); - let inline = InlineIpld::attest(Ipld::Link(needs)); - Some(Ok(inline)) + match self.at_least_once.run(store)? { + Ok(inline_ipld) => Some(Ok(inline_ipld)), + Err(mut stuck) => { + if self.seen.contains(stuck.needs()) { + let foo: &'a mut AtLeastOnce<'a> = stuck.ignore(); + let inliner: AtMostOnce<'a> = foo.clone().into(); // FIXME + let result: Option>> = + inliner.clone().run(store); + + result } else { None } diff --git a/inline_ipld/src/inliner/traits.rs b/inline_ipld/src/inliner/traits.rs index 2bf9c56..efd8119 100644 --- a/inline_ipld/src/inliner/traits.rs +++ b/inline_ipld/src/inliner/traits.rs @@ -7,7 +7,7 @@ use libipld::{Cid, Ipld}; use serde::{Deserialize, Serialize}; /// A trait for inlining [`Ipld`] -pub trait Inliner<'a>: Iterator { +pub trait Inliner<'a> { /// Unblock a stuck [`Iterator`]. /// /// This is generally achieved by pushing some [`Ipld`] into the [`Inliner`]'s processing queue. @@ -84,7 +84,7 @@ pub trait Inliner<'a>: Iterator { /// let mut inliner = AtLeastOnce::new(Ipld::Null); /// assert_eq!(inliner.stuck_at(cid).needs, cid); /// ``` - fn stuck_at(&'a mut self, needs: Cid) -> Stuck<'a, Self> { + fn stuck_at(&'a mut self, needs: &'a Cid) -> Stuck<'a, Self> { Stuck { needs, inliner: self, @@ -98,13 +98,17 @@ pub trait Inliner<'a>: Iterator { #[derive(PartialEq, Debug)] #[cfg_attr(feature = "serde", derive(Desasassaerialize, Serialize))] pub struct Stuck<'a, I: Inliner<'a> + ?Sized> { - inliner: &'a mut I, + pub(crate) inliner: &'a mut I, - /// The [`Cid`] required for the [`Inliner`] to continue - pub needs: Cid, + needs: &'a Cid, } impl<'a, I: Inliner<'a> + ?Sized> Stuck<'a, I> { + /// Get the [`Cid`] required for the [`Inliner`] to continue + pub fn needs(&self) -> &'a Cid { + self.needs + } + /// Fill the missig [`Ipld`] in-place, and add it to the [`Store`] /// /// # Examples @@ -139,7 +143,7 @@ impl<'a, I: Inliner<'a> + ?Sized> Stuck<'a, I> { /// assert_eq!(store.get(&cid).unwrap(), &ipld!([1, 2, 3])); /// ``` pub fn resolve(&'a mut self, ipld: Ipld, store: &mut S) -> &'a mut I { - store.put_keyed(self.needs, ipld.clone()); + store.put_keyed(self.needs.clone(), ipld.clone()); self.stub(ipld) } diff --git a/inline_ipld/src/ipld/inlined.rs b/inline_ipld/src/ipld/inlined.rs index 1d47c7a..5b5ee46 100644 --- a/inline_ipld/src/ipld/inlined.rs +++ b/inline_ipld/src/ipld/inlined.rs @@ -32,6 +32,12 @@ impl From for Ipld { } } +impl<'a> From<&'a InlineIpld> for &'a Ipld { + fn from(inline: &'a InlineIpld) -> &'a Ipld { + &inline.ipld + } +} + impl InlineIpld { /// Wrap some [`Ipld`] and manually associated [`Cid`] in an inline delimiter /// @@ -56,7 +62,7 @@ impl InlineIpld { /// } /// })); /// ``` - pub fn wrap(cid: Cid, ipld: Ipld) -> InlineIpld { + pub fn wrap(cid: Cid, ipld: Ipld) -> Self { InlineIpld { ipld: ipld!({ "/": { @@ -88,7 +94,7 @@ impl InlineIpld { /// let observed = InlineIpld::wrap_inherit_link(ipld!([1, 2, 3])); /// assert_eq!(observed, ipld!({"/": {"data": ipld!([1, 2, 3])}})); /// ``` - pub fn wrap_inherit_link(ipld: Ipld) -> InlineIpld { + pub fn wrap_inherit_link(ipld: Ipld) -> Self { InlineIpld { ipld: ipld!({"/": {"data": ipld!(ipld)}}), } @@ -170,7 +176,7 @@ impl InlineIpld { /// let observed = InlineIpld::attest(ready.clone()); /// assert_eq!(observed, ready) /// ``` - pub fn attest(ipld: Ipld) -> InlineIpld { + pub fn attest(ipld: Ipld) -> Self { InlineIpld { ipld } } } diff --git a/inline_ipld/src/iterator/post_order.rs b/inline_ipld/src/iterator/post_order.rs index 6ae7ac5..1c0332f 100644 --- a/inline_ipld/src/iterator/post_order.rs +++ b/inline_ipld/src/iterator/post_order.rs @@ -8,13 +8,14 @@ use serde::{Deserialize, Serialize}; /// A post-order [`Ipld`] iterator #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -pub struct PostOrderIpldIter { - inbound: Vec, - outbound: Vec, +pub struct PostOrderIpldIter<'a> { + inbound: Vec<&'a Ipld>, + outbound: Vec<&'a Ipld>, } -impl From for PostOrderIpldIter { - fn from(ipld: Ipld) -> Self { +impl<'a> PostOrderIpldIter<'a> { + /// Initialize a new [`PostOrderIpldIter`] + pub fn new(ipld: &'a Ipld) -> Self { PostOrderIpldIter { inbound: vec![ipld], outbound: vec![], @@ -22,27 +23,32 @@ impl From for PostOrderIpldIter { } } -impl Iterator for PostOrderIpldIter { - type Item = Ipld; +impl<'a> From<&'a Ipld> for PostOrderIpldIter<'a> { + fn from(ipld: &'a Ipld) -> Self { + PostOrderIpldIter::new(ipld) + } +} + +impl<'a> Iterator for PostOrderIpldIter<'a> { + type Item = &'a Ipld; fn next(&mut self) -> Option { loop { - dbg!(self.clone()); match self.inbound.pop() { None => return self.outbound.pop(), - Some(Ipld::Map(btree)) => { - self.outbound.push(Ipld::Map(btree.clone())); + Some(map @ Ipld::Map(btree)) => { + self.outbound.push(map); - for node in btree.clone().values() { - self.inbound.push(node.clone()); + for node in btree.values() { + self.inbound.push(node); } } - Some(Ipld::List(vector)) => { - self.outbound.push(Ipld::List(vector.clone())); + Some(list @ Ipld::List(vector)) => { + self.outbound.push(list); - for node in &vector { - self.inbound.push(node.clone()); + for node in vector { + self.inbound.push(node); } } Some(node) => self.outbound.push(node), @@ -64,7 +70,7 @@ impl Iterator for PostOrderIpldIter { /// /// assert_eq!(is_delimiter_next(&mut poii.peekable()), true); /// ``` -pub fn is_delimiter_next(poii: &mut Peekable) -> bool { +pub fn is_delimiter_next<'a>(poii: &mut Peekable>) -> bool { match poii.peek() { Some(Ipld::Map(next_btree)) => next_btree.keys().eq(["/"].iter()), _ => false, diff --git a/inline_ipld/src/store/traits.rs b/inline_ipld/src/store/traits.rs index d1a6e0b..3b19ba8 100644 --- a/inline_ipld/src/store/traits.rs +++ b/inline_ipld/src/store/traits.rs @@ -199,14 +199,14 @@ pub trait Store { /// ``` fn extract>( &mut self, - ipld: InlineIpld, + inline_ipld: &InlineIpld, codec: C, digester: &D, cid_version: Version, ) where Ipld: Encode, { - for (cid, dag) in Extractor::new(ipld, codec, digester, cid_version) { + for (cid, dag) in Extractor::new(inline_ipld, codec, digester, cid_version) { self.put_keyed(cid, dag); } } -- knotmirror 0.0.1