diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2017-08-13 21:48:17 +0000 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2017-08-27 15:12:09 +0200 |
commit | 59a3662ac47b0c657781bd1db34bbf9a5a692326 (patch) | |
tree | 709f72c44c8d978a5a76abb9036c6f08744a4aa2 /libimagentrylink | |
parent | 31254071e5a4bf2f5db9067c5cdb22c25579ac67 (diff) |
Reorganize code in subdirs
Diffstat (limited to 'libimagentrylink')
-rw-r--r-- | libimagentrylink/Cargo.toml | 28 | ||||
l--------- | libimagentrylink/README.md | 1 | ||||
-rw-r--r-- | libimagentrylink/src/error.rs | 40 | ||||
-rw-r--r-- | libimagentrylink/src/external.rs | 416 | ||||
-rw-r--r-- | libimagentrylink/src/internal.rs | 1060 | ||||
-rw-r--r-- | libimagentrylink/src/lib.rs | 55 | ||||
-rw-r--r-- | libimagentrylink/src/result.rs | 25 |
7 files changed, 0 insertions, 1625 deletions
diff --git a/libimagentrylink/Cargo.toml b/libimagentrylink/Cargo.toml deleted file mode 100644 index 451a0eb9..00000000 --- a/libimagentrylink/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "libimagentrylink" -version = "0.4.0" -authors = ["Matthias Beyer <mail@beyermatthias.de>"] - -description = "Library for the imag core distribution" - -keywords = ["imag", "PIM", "personal", "information", "management"] -readme = "../README.md" -license = "LGPL-2.1" - -documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html" -repository = "https://github.com/matthiasbeyer/imag" -homepage = "http://imag-pim.org" - -[dependencies] -itertools = "0.5" -log = "0.3" -toml = "^0.4" -semver = "0.5" -url = "1.2" -rust-crypto = "0.2" -env_logger = "0.3" -is-match = "0.1" - -libimagstore = { version = "0.4.0", path = "../libimagstore" } -libimagerror = { version = "0.4.0", path = "../libimagerror" } -libimagutil = { version = "0.4.0", path = "../libimagutil" } diff --git a/libimagentrylink/README.md b/libimagentrylink/README.md deleted file mode 120000 index d30d8ab6..00000000 --- a/libimagentrylink/README.md +++ /dev/null @@ -1 +0,0 @@ -../doc/src/05100-lib-entrylink.md
\ No newline at end of file diff --git a/libimagentrylink/src/error.rs b/libimagentrylink/src/error.rs deleted file mode 100644 index 10d83f94..00000000 --- a/libimagentrylink/src/error.rs +++ /dev/null @@ -1,40 +0,0 @@ -// -// imag - the personal information management suite for the commandline -// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> 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 -// - -generate_error_module!( - generate_error_types!(LinkError, LinkErrorKind, - EntryHeaderReadError => "Error while reading an entry header", - EntryHeaderWriteError => "Error while writing an entry header", - ExistingLinkTypeWrong => "Existing link entry has wrong type", - LinkTargetDoesNotExist => "Link target does not exist in the store", - LinkParserError => "Link cannot be parsed", - LinkParserFieldMissingError => "Link cannot be parsed: Field missing", - LinkParserFieldTypeError => "Link cannot be parsed: Field type wrong", - InternalConversionError => "Error while converting values internally", - InvalidUri => "URI is not valid", - StoreReadError => "Store read error", - StoreWriteError => "Store write error", - StoreIdError => "StoreId handling error" - ); -); - -pub use self::error::LinkError; -pub use self::error::LinkErrorKind; -pub use self::error::MapErrInto; - diff --git a/libimagentrylink/src/external.rs b/libimagentrylink/src/external.rs deleted file mode 100644 index daed7a12..00000000 --- a/libimagentrylink/src/external.rs +++ /dev/null @@ -1,416 +0,0 @@ -// -// imag - the personal information management suite for the commandline -// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> 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 -// - -/// External linking is a complex implementation to be able to serve a clean and easy-to-use -/// interface. -/// -/// Internally, there are no such things as "external links" (plural). Each Entry in the store can -/// only have _one_ external link. -/// -/// This library does the following therefor: It allows you to have several external links with one -/// entry, which are internally one file in the store for each link, linked with "internal -/// linking". -/// -/// This helps us greatly with deduplication of URLs. -/// - -use std::ops::DerefMut; -use std::collections::BTreeMap; -use std::fmt::Debug; - -use libimagstore::store::Entry; -use libimagstore::store::FileLockEntry; -use libimagstore::store::Store; -use libimagstore::storeid::StoreId; -use libimagstore::storeid::IntoStoreId; -use libimagstore::toml_ext::TomlValueExt; -use libimagutil::debug_result::*; - -use error::LinkError as LE; -use error::LinkErrorKind as LEK; -use error::MapErrInto; -use result::Result; -use internal::InternalLinker; -use module_path::ModuleEntryPath; - -use self::iter::*; - -use toml::Value; -use url::Url; -use crypto::sha1::Sha1; -use crypto::digest::Digest; - -/// "Link" Type, just an abstraction over `FileLockEntry` to have some convenience internally. -pub struct Link<'a> { - link: FileLockEntry<'a> -} - -impl<'a> Link<'a> { - - pub fn new(fle: FileLockEntry<'a>) -> Link<'a> { - Link { link: fle } - } - - /// Get a link Url object from a `FileLockEntry`, ignore errors. - fn get_link_uri_from_filelockentry(file: &FileLockEntry<'a>) -> Option<Url> { - file.get_header() - .read("imag.content.url") - .ok() - .and_then(|opt| match opt { - Some(Value::String(s)) => { - debug!("Found url, parsing: {:?}", s); - Url::parse(&s[..]).ok() - }, - _ => None - }) - } - - pub fn get_url(&self) -> Result<Option<Url>> { - let opt = self.link - .get_header() - .read("imag.content.url"); - - match opt { - Ok(Some(Value::String(s))) => { - Url::parse(&s[..]) - .map(Some) - .map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e)))) - }, - Ok(None) => Ok(None), - _ => Err(LE::new(LEK::EntryHeaderReadError, None)) - } - } - -} - -pub trait ExternalLinker : InternalLinker { - - /// Get the external links from the implementor object - fn get_external_links<'a>(&self, store: &'a Store) -> Result<UrlIter<'a>>; - - /// Set the external links for the implementor object - fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()>; - - /// Add an external link to the implementor object - fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()>; - - /// Remove an external link from the implementor object - fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()>; - -} - -pub mod iter { - //! Iterator helpers for external linking stuff - //! - //! Contains also helpers to filter iterators for external/internal links - //! - //! - //! # Warning - //! - //! This module uses `internal::Link` as link type, so we operate on _store ids_ here. - //! - //! Not to confuse with `external::Link` which is a real `FileLockEntry` under the hood. - //! - - 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 | 0 | 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)`. - pub struct ExternalFilterIter(LinkIter, bool); - - impl Iterator for ExternalFilterIter { - type Item = Link; - - fn next(&mut self) -> Option<Self::Item> { - 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 - } - } - - /// Helper trait to be implemented on `LinkIter` to select or deselect all external links - /// - /// # See also - /// - /// Also see `OnlyExternalIter` and `NoExternalIter` and the helper traits/functions - /// `OnlyInteralLinks`/`only_internal_links()` and `OnlyExternalLinks`/`only_external_links()`. - pub trait SelectExternal { - fn select_external_links(self, b: bool) -> ExternalFilterIter; - } - - impl SelectExternal for LinkIter { - fn select_external_links(self, b: bool) -> ExternalFilterIter { - ExternalFilterIter(self, b) - } - } - - - 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::Item> { - 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::Item> { - 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<Url>; - - fn next(&mut self) -> Option<Self::Item> { - 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<A: AsRef<StoreId> + Debug>(id: A) -> bool { - debug!("Checking whether this is a 'links/external/': '{:?}'", id); - id.as_ref().local().starts_with("links/external") -} - -fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> { - Link::get_link_uri_from_filelockentry(entry) // TODO: Do not hide error by using this function - .ok_or(LE::new(LEK::StoreReadError, None)) -} - -/// Implement `ExternalLinker` for `Entry`, hiding the fact that there is no such thing as an external -/// link in an entry, but internal links to other entries which serve as external links, as one -/// entry in the store can only have one external link. -impl ExternalLinker for Entry { - - /// Get the external links from the implementor object - fn get_external_links<'a>(&self, store: &'a Store) -> Result<UrlIter<'a>> { - // Iterate through all internal links and filter for FileLockEntries which live in - // /link/external/<SHA> -> load these files and get the external link from their headers, - // put them into the return vector. - self.get_internal_links() - .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e)))) - .map(|iter| { - debug!("Getting external links"); - iter.only_external_links().urls(store) - }) - } - - /// Set the external links for the implementor object - fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()> { - // Take all the links, generate a SHA sum out of each one, filter out the already existing - // store entries and store the other URIs in the header of one FileLockEntry each, in - // the path /link/external/<SHA of the URL> - - debug!("Iterating {} links = {:?}", links.len(), links); - for link in links { // for all links - let hash = { - let mut s = Sha1::new(); - s.input_str(&link.as_str()[..]); - s.result_str() - }; - let file_id = try!( - ModuleEntryPath::new(format!("external/{}", hash)).into_storeid() - .map_err_into(LEK::StoreWriteError) - .map_dbg_err(|_| { - format!("Failed to build StoreId for this hash '{:?}'", hash) - }) - ); - - debug!("Link = '{:?}'", link); - debug!("Hash = '{:?}'", hash); - debug!("StoreId = '{:?}'", file_id); - - // retrieve the file from the store, which implicitely creates the entry if it does not - // exist - let mut file = try!(store - .retrieve(file_id.clone()) - .map_err_into(LEK::StoreWriteError) - .map_dbg_err(|_| { - format!("Failed to create or retrieve an file for this link '{:?}'", link) - })); - - debug!("Generating header content!"); - { - let mut hdr = file.deref_mut().get_header_mut(); - - let mut table = match hdr.read("imag.content") { - Ok(Some(Value::Table(table))) => table, - Ok(Some(_)) => { - warn!("There is a value at 'imag.content' which is not a table."); - warn!("Going to override this value"); - BTreeMap::new() - }, - Ok(None) => BTreeMap::new(), - Err(e) => return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e)))), - }; - - let v = Value::String(link.into_string()); - - debug!("setting URL = '{:?}", v); - table.insert(String::from("url"), v); - - if let Err(e) = hdr.set("imag.content", Value::Table(table)) { - return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e)))); - } else { - debug!("Setting URL worked"); - } - } - - // then add an internal link to the new file or return an error if this fails - if let Err(e) = self.add_internal_link(file.deref_mut()) { - debug!("Error adding internal link"); - return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e)))); - } - } - debug!("Ready iterating"); - Ok(()) - } - - /// Add an external link to the implementor object - fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()> { - // get external links, add this one, save them - debug!("Getting links"); - self.get_external_links(store) - .and_then(|links| { - // TODO: Do not ignore errors here - let mut links = links.filter_map(Result::ok).collect::<Vec<_>>(); - debug!("Adding link = '{:?}' to links = {:?}", link, links); - links.push(link); - debug!("Setting {} links = {:?}", links.len(), links); - self.set_external_links(store, links) - }) - } - - /// Remove an external link from the implementor object - fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()> { - // get external links, remove this one, save them - self.get_external_links(store) - .and_then(|links| { - debug!("Removing link = '{:?}'", link); - let links = links - .filter_map(Result::ok) - .filter(|l| l.as_str() != link.as_str()) - .collect::<Vec<_>>(); - self.set_external_links(store, links) - }) - } - -} - diff --git a/libimagentrylink/src/internal.rs b/libimagentrylink/src/internal.rs deleted file mode 100644 index 62003777..00000000 --- a/libimagentrylink/src/internal.rs +++ /dev/null @@ -1,1060 +0,0 @@ -// -// imag - the personal information management suite for the commandline -// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> 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 -// - -use std::collections::BTreeMap; -#[cfg(test)] -use std::path::PathBuf; - -use libimagstore::storeid::StoreId; -use libimagstore::storeid::IntoStoreId; -use libimagstore::store::Entry; -use libimagstore::store::Result as StoreResult; -use libimagstore::toml_ext::TomlValueExt; -use libimagerror::into::IntoError; - -use error::LinkErrorKind as LEK; -use error::MapErrInto; -use result::Result; -use self::iter::LinkIter; -use self::iter::IntoValues; - -use toml::Value; - -#[derive(Eq, PartialOrd, Ord, Hash, Debug, Clone)] -pub enum Link { - Id { link: StoreId }, - Annotated { link: StoreId, annotation: String }, -} - -impl Link { - - pub fn exists(&self) -> Result<bool> { - match *self { - Link::Id { ref link } => link.exists(), - Link::Annotated { ref link, .. } => link.exists(), - } - .map_err_into(LEK::StoreIdError) - } - - pub fn to_str(&self) -> Result<String> { - match *self { - Link::Id { ref link } => link.to_str(), - Link::Annotated { ref link, .. } => link.to_str(), - } - .map_err_into(LEK::StoreReadError) - } - - - fn eq_store_id(&self, id: &StoreId) -> bool { - match self { - &Link::Id { link: ref s } => s.eq(id), - &Link::Annotated { link: ref s, .. } => s.eq(id), - } - } - - /// Get the StoreId inside the Link, which is always present - pub fn get_store_id(&self) -> &StoreId { - match self { - &Link::Id { link: ref s } => s, - &Link::Annotated { link: ref s, .. } => s, - } - } - - /// Helper wrapper around Link for StoreId - fn without_base(self) -> Link { - match self { - Link::Id { link: s } => Link::Id { link: s.without_base() }, - Link::Annotated { link: s, annotation: ann } => - Link::Annotated { link: s.without_base(), annotation: ann }, - } - } - - /// Helper wrapper around Link for StoreId - #[cfg(test)] - fn with_base(self, pb: PathBuf) -> Link { - match self { - Link::Id { link: s } => Link::Id { link: s.with_base(pb) }, - Link::Annotated { link: s, annotation: ann } => - Link::Annotated { link: s.with_base(pb), annotation: ann }, - } - } - - fn to_value(&self) -> Result<Value> { - match self { - &Link::Id { link: ref s } => - s.to_str().map(Value::String).map_err_into(LEK::InternalConversionError), - &Link::Annotated { ref link, annotation: ref anno } => { - link.to_str() - .map(Value::String) - .map_err_into(LEK::InternalConversionError) - .map(|link| { - let mut tab = BTreeMap::new(); - - tab.insert("link".to_owned(), link); - tab.insert("annotation".to_owned(), Value::String(anno.clone())); - Value::Table(tab) - }) - } - } - } - -} - -impl ::std::cmp::PartialEq for Link { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (&Link::Id { link: ref a }, &Link::Id { link: ref b }) => a.eq(&b), - (&Link::Annotated { link: ref a, annotation: ref ann1 }, - &Link::Annotated { link: ref b, annotation: ref ann2 }) => - (a, ann1).eq(&(b, ann2)), - _ => false, - } - } -} - -impl From<StoreId> for Link { - - fn from(s: StoreId) -> Link { - Link::Id { link: s } - } -} - -impl Into<StoreId> for Link { - fn into(self) -> StoreId { - match self { - Link::Id { link } => link, - Link::Annotated { link, .. } => link, - } - } -} - -impl IntoStoreId for Link { - fn into_storeid(self) -> StoreResult<StoreId> { - match self { - Link::Id { link } => Ok(link), - Link::Annotated { link, .. } => Ok(link), - } - } -} - -impl AsRef<StoreId> for Link { - fn as_ref(&self) -> &StoreId { - match self { - &Link::Id { ref link } => &link, - &Link::Annotated { ref link, .. } => &link, - } - } -} - -pub trait InternalLinker { - - /// Get the internal links from the implementor object - fn get_internal_links(&self) -> Result<LinkIter>; - - /// Set the internal links for the implementor object - fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<LinkIter>; - - /// Add an internal link to the implementor object - fn add_internal_link(&mut self, link: &mut Entry) -> Result<()>; - - /// Remove an internal link from the implementor object - fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()>; - - /// Add internal annotated link - fn add_internal_annotated_link(&mut self, link: &mut Entry, annotation: String) -> Result<()>; -} - -pub mod iter { - use std::vec::IntoIter; - use super::Link; - - use error::LinkErrorKind as LEK; - use error::MapErrInto; - use result::Result; - - use toml::Value; - use itertools::Itertools; - - use libimagstore::store::Store; - use libimagstore::store::FileLockEntry; - - pub struct LinkIter(IntoIter<Link>); - - impl LinkIter { - - pub fn new(v: Vec<Link>) -> LinkIter { - LinkIter(v.into_iter()) - } - - pub fn into_getter(self, store: &Store) -> GetIter { - GetIter(self.0, store) - } - - } - - impl Iterator for LinkIter { - type Item = Link; - - fn next(&mut self) -> Option<Self::Item> { - self.0.next() - } - } - - pub trait IntoValues { - fn into_values(self) -> Vec<Result<Value>>; - } - - impl<I: Iterator<Item = Link>> IntoValues for I { - fn into_values(self) -> Vec<Result<Value>> { - self.map(|s| s.without_base()) - .unique() - .sorted() - .into_iter() // Cannot sort toml::Value, hence uglyness here - .map(|link| link.to_value().map_err_into(LEK::InternalConversionError)) - .collect() - } - } - - /// An Iterator that `Store::get()`s the Entries from the store while consumed - pub struct GetIter<'a>(IntoIter<Link>, &'a Store); - - impl<'a> GetIter<'a> { - pub fn new(i: IntoIter<Link>, store: &'a Store) -> GetIter<'a> { - GetIter(i, store) - } - - /// Turn this iterator into a LinkGcIter, which `Store::delete()`s entries that are not - /// linked to any other entry. - pub fn delete_unlinked(self) -> DeleteUnlinkedIter<'a> { - DeleteUnlinkedIter(self) - } - - /// Turn this iterator into a FilterLinksIter that removes all entries that are not linked - /// to any other entry, by filtering them out the iterator. - /// - /// This does _not_ remove the entries from the store. - pub fn without_unlinked(self) -> FilterLinksIter<'a> { - FilterLinksIter::new(self, Box::new(|links: &[Link]| links.len() > 0)) - } - - /// Turn this iterator into a FilterLinksIter that removes all entries that have less than - /// `n` links to any other entries. - /// - /// This does _not_ remove the entries from the store. - pub fn with_less_than_n_links(self, n: usize) -> FilterLinksIter<'a> { - FilterLinksIter::new(self, Box::new(move |links: &[Link]| links.len() < n)) - } - - /// Turn this iterator into a FilterLinksIter that removes all entries that have more than - /// `n` links to any other entries. - /// - /// This does _not_ remove the entries from the store. - pub fn with_more_than_n_links(self, n: usize) -> FilterLinksIter<'a> { - FilterLinksIter::new(self, Box::new(move |links: &[Link]| links.len() > n)) - } - - /// Turn this iterator into a FilterLinksIter that removes all entries where the predicate - /// `F` returns false - /// - /// This does _not_ remove the entries from the store. - pub fn filtered_for_links(self, f: Box<Fn(&[Link]) -> bool>) -> FilterLinksIter<'a> { - FilterLinksIter::new(self, f) - } - - pub fn store(&self) -> &Store { - self.1 - } - } - - impl<'a> Iterator for GetIter<'a> { - type Item = Result<FileLockEntry<'a>>; - - fn next(&mut self) -> Option<Self::Item> { - self.0.next().and_then(|id| match self.1.get(id).map_err_into(LEK::StoreReadError) { - Ok(None) => None, - Ok(Some(x)) => Some(Ok(x)), - Err(e) => Some(Err(e)), - }) - } - - } - - /// An iterator helper that has a function F. - /// - /// If the function F returns `false` for the number of links, the entry is ignored, else it is - /// taken. - pub struct FilterLinksIter<'a>(GetIter<'a>, Box<Fn(&[Link]) -> bool>); - - impl<'a> FilterLinksIter<'a> { - pub fn new(gi: GetIter<'a>, f: Box<Fn(&[Link]) -> bool>) -> FilterLinksIter<'a> { - FilterLinksIter(gi, f) - } - } - - impl<'a> Iterator for FilterLinksIter<'a> { - type Item = Result<FileLockEntry<'a>>; - - fn next(&mut self) -> Option<Self::Item> { - use internal::InternalLinker; - - loop { - match self.0.next() { - Some(Ok(fle)) => { - let links = match fle.get_internal_links().map_err_into(LEK::StoreReadError) - { - Err(e) => return Some(Err(e)), - Ok(links) => links.collect::<Vec<_>>(), - }; - if !(self.1)(&links) { - continue; - } else { - return Some(Ok(fle)); - } - }, - Some(Err(e)) => return Some(Err(e)), - None => break, - } - } - None - } - - } - - /// An iterator that removes all Items from the iterator that are not linked anymore by calling - /// `Store::delete()` on them. - /// - /// It yields only items which are somehow linked to another entry - /// - /// # Warning - /// - /// Deletes entries from the store. - /// - pub struct DeleteUnlinkedIter<'a>(GetIter<'a>); - - impl<'a> Iterator for DeleteUnlinkedIter<'a> { - type Item = Result<FileLockEntry<'a>>; - - fn next(&mut self) -> Option<Self::Item> { - use internal::InternalLinker; - - loop { - match self.0.next() { - Some(Ok(fle)) => { - let links = match fle.get_internal_links().map_err_into(LEK::StoreReadError) - { - Err(e) => return Some(Err(e)), - Ok(links) => links, - }; - if links.count() == 0 { - match self.0 - .store() - .delete(fle.get_location().clone()) - .map_err_into(LEK::StoreWriteError) - { - Ok(x) => x, - Err(e) => return Some(Err(e)), - } - } else { - return Some(Ok(fle)); - } - }, - Some(Err(e)) => return Some(Err(e)), - None => break, - } - } - None - } - - } - -} - -impl InternalLinker for Entry { - - fn get_internal_links(&self) -> Result<LinkIter> { - process_rw_result(self.get_header().read("imag.links")) - } - - /// Set the links in a header and return the old links, if any. - fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<LinkIter> { - use internal::iter::IntoValues; - - let self_location = self.get_location().clone(); - let mut new_links = vec![]; - - for link in links { - if let Err(e) = add_foreign_link(link, self_location.clone()) { - return Err(e); - } - new_links.push(link.get_location().clone().into()); - } - - let new_links = try!(LinkIter::new(new_links) - .into_values() - .into_iter() - .fold(Ok(vec![]), |acc, elem| { - acc.and_then(move |mut v| { - elem.map_err_into(LEK::InternalConversionError) - .map(|e| { - v.push(e); - v - }) - }) - })); - process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links))) - } - - fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> { - let location = link.get_location().clone().into(); - add_internal_link_with_instance(self, link, location) - } - < |