From 378951a16bb2e70d25ab0be8d7c2e468a564f9dd Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 15 Oct 2016 14:41:20 +0200 Subject: [PATCH] Add module external::iter --- libimagentrylink/src/external.rs | 139 +++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/libimagentrylink/src/external.rs b/libimagentrylink/src/external.rs index 48c3956d..1a1b748b 100644 --- a/libimagentrylink/src/external.rs +++ b/libimagentrylink/src/external.rs @@ -111,6 +111,145 @@ pub trait ExternalLinker : InternalLinker { } +pub mod iter { + use libimagutil::debug_result::*; + use libimagstore::store::Store; + + use internal::Link; + use internal::iter::LinkIter; + use error::LinkErrorKind as LEK; + use error::MapErrInto; + use result::Result; + + use url::Url; + + /// Helper for building `OnlyExternalIter` and `NoExternalIter` + /// + /// The boolean value defines, how to interpret the `is_external_link_storeid()` return value + /// (here as "pred"): + /// + /// pred | bool | xor | take? + /// ---- | ---- | --- | ---- + /// 0 | 0 | 0 | 1 + /// 0 | 1 | 1 | 0 + /// 1 | 1 | 1 | 0 + /// 1 | 1 | 0 | 1 + /// + /// If `bool` says "take if return value is false", we take the element if the `pred` returns + /// false... and so on. + /// + /// As we can see, the operator between these two operants is `!(a ^ b)`. + struct ExternalFilterIter(LinkIter, bool); + + impl Iterator for ExternalFilterIter { + type Item = Link; + + fn next(&mut self) -> Option { + use super::is_external_link_storeid; + + while let Some(elem) = self.0.next() { + if !(self.1 ^ is_external_link_storeid(&elem)) { + return Some(elem); + } + } + None + } + } + + pub struct OnlyExternalIter(ExternalFilterIter); + + impl OnlyExternalIter { + pub fn new(li: LinkIter) -> OnlyExternalIter { + OnlyExternalIter(ExternalFilterIter(li, true)) + } + + pub fn urls<'a>(self, store: &'a Store) -> UrlIter<'a> { + UrlIter(self, store) + } + } + + impl Iterator for OnlyExternalIter { + type Item = Link; + + fn next(&mut self) -> Option { + self.0.next() + } + } + + pub struct NoExternalIter(ExternalFilterIter); + + impl NoExternalIter { + pub fn new(li: LinkIter) -> NoExternalIter { + NoExternalIter(ExternalFilterIter(li, false)) + } + } + + impl Iterator for NoExternalIter { + type Item = Link; + + fn next(&mut self) -> Option { + self.0.next() + } + } + + pub trait OnlyExternalLinks : Sized { + fn only_external_links(self) -> OnlyExternalIter ; + + fn no_internal_links(self) -> OnlyExternalIter { + self.only_external_links() + } + } + + impl OnlyExternalLinks for LinkIter { + fn only_external_links(self) -> OnlyExternalIter { + OnlyExternalIter::new(self) + } + } + + pub trait OnlyInternalLinks : Sized { + fn only_internal_links(self) -> NoExternalIter; + + fn no_external_links(self) -> NoExternalIter { + self.only_internal_links() + } + } + + impl OnlyInternalLinks for LinkIter { + fn only_internal_links(self) -> NoExternalIter { + NoExternalIter::new(self) + } + } + + pub struct UrlIter<'a>(OnlyExternalIter, &'a Store); + + impl<'a> Iterator for UrlIter<'a> { + type Item = Result; + + fn next(&mut self) -> Option { + use super::get_external_link_from_file; + + self.0 + .next() + .map(|id| { + debug!("Retrieving entry for id: '{:?}'", id); + self.1 + .retrieve(id.clone()) + .map_err_into(LEK::StoreReadError) + .map_dbg_err(|_| format!("Retrieving entry for id: '{:?}' failed", id)) + .and_then(|f| { + debug!("Store::retrieve({:?}) succeeded", id); + debug!("getting external link from file now"); + get_external_link_from_file(&f) + .map_dbg_err(|e| format!("URL -> Err = {:?}", e)) + }) + }) + } + + } + +} + + /// Check whether the StoreId starts with `/link/external/` pub fn is_external_link_storeid(id: &StoreId) -> bool { debug!("Checking whether this is a 'links/external/': '{:?}'", id);