Rewrite libimagentrylink::external::Link to be a trait

This commit is contained in:
Matthias Beyer 2017-08-28 10:31:13 +02:00
parent 29d93a73f0
commit 4b42b3328d

View file

@ -35,12 +35,12 @@ use std::collections::BTreeMap;
use std::fmt::Debug; use std::fmt::Debug;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId; use libimagstore::storeid::IntoStoreId;
use libimagstore::toml_ext::TomlValueExt; use libimagstore::toml_ext::TomlValueExt;
use libimagutil::debug_result::*; use libimagutil::debug_result::*;
use libimagerror::into::IntoError;
use error::LinkError as LE; use error::LinkError as LE;
use error::LinkErrorKind as LEK; use error::LinkErrorKind as LEK;
@ -56,37 +56,32 @@ use url::Url;
use crypto::sha1::Sha1; use crypto::sha1::Sha1;
use crypto::digest::Digest; use crypto::digest::Digest;
/// "Link" Type, just an abstraction over `FileLockEntry` to have some convenience internally. pub trait Link {
pub struct Link<'a> {
link: FileLockEntry<'a> fn get_link_uri_from_filelockentry(&self) -> Result<Option<Url>>;
fn get_url(&self) -> Result<Option<Url>>;
} }
impl<'a> Link<'a> { impl Link for Entry {
pub fn new(fle: FileLockEntry<'a>) -> Link<'a> { fn get_link_uri_from_filelockentry(&self) -> Result<Option<Url>> {
Link { link: fle } self.get_header()
}
/// 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") .read("imag.content.url")
.ok() .map_err_into(LEK::EntryHeaderReadError)
.and_then(|opt| match opt { .and_then(|opt| match opt {
Some(Value::String(s)) => { Some(Value::String(s)) => {
debug!("Found url, parsing: {:?}", s); debug!("Found url, parsing: {:?}", s);
Url::parse(&s[..]).ok() Url::parse(&s[..]).map_err_into(LEK::InvalidUri).map(Some)
}, },
_ => None Some(_) => Err(LEK::LinkParserFieldTypeError.into_error()),
None => Ok(None),
}) })
} }
pub fn get_url(&self) -> Result<Option<Url>> { fn get_url(&self) -> Result<Option<Url>> {
let opt = self.link match self.get_header().read("imag.content.url") {
.get_header()
.read("imag.content.url");
match opt {
Ok(Some(Value::String(s))) => { Ok(Some(Value::String(s))) => {
Url::parse(&s[..]) Url::parse(&s[..])
.map(Some) .map(Some)
@ -259,23 +254,32 @@ pub mod iter {
type Item = Result<Url>; type Item = Result<Url>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
use super::get_external_link_from_file; use external::Link;
self.0 loop {
.next() let next = self.0
.map(|id| { .next()
debug!("Retrieving entry for id: '{:?}'", id); .map(|id| {
self.1 debug!("Retrieving entry for id: '{:?}'", id);
.retrieve(id.clone()) self.1
.map_err_into(LEK::StoreReadError) .retrieve(id.clone())
.map_dbg_err(|_| format!("Retrieving entry for id: '{:?}' failed", id)) .map_err_into(LEK::StoreReadError)
.and_then(|f| { .map_dbg_err(|_| format!("Retrieving entry for id: '{:?}' failed", id))
debug!("Store::retrieve({:?}) succeeded", id); .and_then(|f| {
debug!("getting external link from file now"); debug!("Store::retrieve({:?}) succeeded", id);
get_external_link_from_file(&f) debug!("getting external link from file now");
.map_dbg_err(|e| format!("URL -> Err = {:?}", e)) f.get_link_uri_from_filelockentry()
}) .map_dbg_err(|e| format!("URL -> Err = {:?}", e))
}) })
});
match next {
Some(Ok(Some(link))) => return Some(Ok(link)),
Some(Ok(None)) => continue,
Some(Err(e)) => return Some(Err(e)),
None => return None
}
}
} }
} }
@ -289,11 +293,6 @@ pub fn is_external_link_storeid<A: AsRef<StoreId> + Debug>(id: A) -> bool {
id.as_ref().local().starts_with("links/external") 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 /// 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 /// 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. /// entry in the store can only have one external link.