// // imag - the personal information management suite for the commandline // Copyright (C) 2015, 2016 Matthias Beyer and contributors // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; version // 2.1 of the License. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // //! BookmarkCollection module //! //! A BookmarkCollection is nothing more than a simple store entry. One can simply call functions //! from the libimagentrylink::external::ExternalLinker trait on this to generate external links. //! //! The BookmarkCollection type offers helper functions to get all links or such things. use std::ops::Deref; use std::ops::DerefMut; use regex::Regex; use error::BookmarkErrorKind as BEK; use error::BookmarkError as BE; use error::ResultExt; use error::Result; use module_path::ModuleEntryPath; use libimagstore::store::Store; use libimagstore::storeid::IntoStoreId; use libimagstore::store::FileLockEntry; use libimagentrylink::external::ExternalLinker; use libimagentrylink::external::iter::UrlIter; use libimagentrylink::internal::InternalLinker; use libimagentrylink::internal::Link as StoreLink; use link::Link; use self::iter::LinksMatchingRegexIter; pub struct BookmarkCollection<'a> { fle: FileLockEntry<'a>, store: &'a Store, } /// {Internal, External}Linker is implemented as Deref is implemented impl<'a> Deref for BookmarkCollection<'a> { type Target = FileLockEntry<'a>; fn deref(&self) -> &FileLockEntry<'a> { &self.fle } } impl<'a> DerefMut for BookmarkCollection<'a> { fn deref_mut(&mut self) -> &mut FileLockEntry<'a> { &mut self.fle } } impl<'a> BookmarkCollection<'a> { pub fn new(store: &'a Store, name: &str) -> Result> { ModuleEntryPath::new(name) .into_storeid() .and_then(|id| store.create(id)) .map(|fle| { BookmarkCollection { fle: fle, store: store, } }) .chain_err(|| BEK::StoreReadError) } pub fn get(store: &'a Store, name: &str) -> Result> { ModuleEntryPath::new(name) .into_storeid() .and_then(|id| store.get(id)) .chain_err(|| BEK::StoreReadError) .and_then(|fle| { match fle { None => Err(BE::from_kind(BEK::CollectionNotFound)), Some(e) => Ok(BookmarkCollection { fle: e, store: store, }), } }) } pub fn delete(store: &Store, name: &str) -> Result<()> { ModuleEntryPath::new(name) .into_storeid() .and_then(|id| store.delete(id)) .chain_err(|| BEK::StoreReadError) } pub fn links(&self) -> Result { self.fle.get_external_links(&self.store).chain_err(|| BEK::LinkError) } pub fn link_entries(&self) -> Result> { use libimagentrylink::external::is_external_link_storeid; self.fle .get_internal_links() .map(|v| v.filter(|id| is_external_link_storeid(id)).collect()) .chain_err(|| BEK::StoreReadError) } pub fn add_link(&mut self, l: Link) -> Result<()> { use link::IntoUrl; l.into_url() .and_then(|url| self.add_external_link(self.store, url).chain_err(|| BEK::LinkingError)) .chain_err(|| BEK::LinkError) } pub fn get_links_matching(&self, r: Regex) -> Result> { use self::iter::IntoLinksMatchingRegexIter; self.get_external_links(self.store) .chain_err(|| BEK::LinkError) .map(|iter| iter.matching_regex(r)) } pub fn remove_link(&mut self, l: Link) -> Result<()> { use link::IntoUrl; l.into_url() .and_then(|url| { self.remove_external_link(self.store, url).chain_err(|| BEK::LinkingError) }) .chain_err(|| BEK::LinkError) } } pub mod iter { use link::Link; use error::Result; use error::{ResultExt, 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).chain_err(|| 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) } } }