diff --git a/libimagbookmark/src/collection.rs b/libimagbookmark/src/collection.rs index d97fcf95..206e31cd 100644 --- a/libimagbookmark/src/collection.rs +++ b/libimagbookmark/src/collection.rs @@ -41,10 +41,11 @@ use libimagentrylink::external::iter::UrlIter; use libimagentrylink::internal::InternalLinker; use libimagentrylink::internal::Link as StoreLink; use libimagerror::into::IntoError; -use url::Url; use link::Link; +use self::iter::LinksMatchingRegexIter; + pub struct BookmarkCollection<'a> { fle: FileLockEntry<'a>, store: &'a Store, @@ -127,18 +128,12 @@ impl<'a> BookmarkCollection<'a> { .map_err_into(BEK::LinkError) } - pub fn get_links_matching(&self, r: Regex) -> Result { - use std::result::Result as RResult; + pub fn get_links_matching(&self, r: Regex) -> Result> { + use self::iter::IntoLinksMatchingRegexIter; self.get_external_links(self.store) .map_err_into(BEK::LinkError) - .map(|v| { - v.filter_map(RResult::ok) // TODO: Do not ignore errors here - .map(Url::into_string) - .filter(|urlstr| r.is_match(&urlstr[..])) - .map(Link::from) - .collect() - }) + .map(|iter| iter.matching_regex(r)) } pub fn remove_link(&mut self, l: Link) -> Result<()> { @@ -153,3 +148,75 @@ impl<'a> BookmarkCollection<'a> { } +pub mod iter { + use link::Link; + use result::Result; + use error::{MapErrInto, BookmarkErrorKind as BEK}; + + pub struct LinkIter(I) + where I: Iterator; + + impl> LinkIter { + pub fn new(i: I) -> LinkIter { + LinkIter(i) + } + } + + impl> Iterator for LinkIter { + type Item = Link; + + fn next(&mut self) -> Option { + self.0.next() + } + } + + impl From for LinkIter where I: Iterator { + fn from(i: I) -> LinkIter { + LinkIter(i) + } + } + + use libimagentrylink::external::iter::UrlIter; + use regex::Regex; + + pub struct LinksMatchingRegexIter<'a>(UrlIter<'a>, Regex); + + impl<'a> LinksMatchingRegexIter<'a> { + pub fn new(i: UrlIter<'a>, r: Regex) -> LinksMatchingRegexIter<'a> { + LinksMatchingRegexIter(i, r) + } + } + + impl<'a> Iterator for LinksMatchingRegexIter<'a> { + type Item = Result; + + fn next(&mut self) -> Option { + loop { + let n = match self.0.next() { + Some(Ok(n)) => n, + Some(Err(e)) => return Some(Err(e).map_err_into(BEK::LinkError)), + None => return None, + }; + + let s = n.into_string(); + if self.1.is_match(&s[..]) { + return Some(Ok(Link::from(s))) + } else { + continue; + } + } + } + } + + pub trait IntoLinksMatchingRegexIter<'a> { + fn matching_regex(self, Regex) -> LinksMatchingRegexIter<'a>; + } + + impl<'a> IntoLinksMatchingRegexIter<'a> for UrlIter<'a> { + fn matching_regex(self, r: Regex) -> LinksMatchingRegexIter<'a> { + LinksMatchingRegexIter(self, r) + } + } + +} +