From cb288eb868468027e01887a03b2e29039059e268 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 21 Feb 2016 14:48:21 +0100 Subject: [PATCH] Rewrite internal linking * so you need to pass Entry instead of Link * interal linking does two-way-linking --- libimaglink/src/error.rs | 8 ++ libimaglink/src/internal.rs | 154 +++++++++++++++++++++++++----------- libimaglink/src/lib.rs | 1 - 3 files changed, 115 insertions(+), 48 deletions(-) diff --git a/libimaglink/src/error.rs b/libimaglink/src/error.rs index 32c5a72b..a57bbbd9 100644 --- a/libimaglink/src/error.rs +++ b/libimaglink/src/error.rs @@ -9,6 +9,8 @@ pub enum LinkErrorKind { EntryHeaderReadError, EntryHeaderWriteError, ExistingLinkTypeWrong, + LinkTargetDoesNotExist, + InternalConversionError, } fn link_error_type_as_str(e: &LinkErrorKind) -> &'static str { @@ -21,6 +23,12 @@ fn link_error_type_as_str(e: &LinkErrorKind) -> &'static str { &LinkErrorKind::ExistingLinkTypeWrong => "Existing link entry has wrong type", + + &LinkErrorKind::LinkTargetDoesNotExist + => "Link target does not exist in the store", + + &LinkErrorKind::InternalConversionError + => "Error while converting values internally", } } diff --git a/libimaglink/src/internal.rs b/libimaglink/src/internal.rs index 39750fae..d9732758 100644 --- a/libimaglink/src/internal.rs +++ b/libimaglink/src/internal.rs @@ -1,80 +1,140 @@ +use libimagstore::storeid::StoreId; use libimagstore::store::Entry; use libimagstore::store::EntryHeader; use libimagstore::store::Result as StoreResult; use error::{LinkError, LinkErrorKind}; -use link::{Link, Links}; use result::Result; use toml::Value; +pub type Link = String; + pub trait InternalLinker { /// Get the internal links from the implementor object - fn get_internal_links(&self) -> Result; + fn get_internal_links(&self) -> Result>; /// Set the internal links for the implementor object - fn set_internal_links(&mut self, links: Links) -> Result; + fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result>; /// Add an internal link to the implementor object - fn add_internal_link(&mut self, link: Link) -> Result<()>; + 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: Link) -> Result<()>; - -} - -impl InternalLinker for EntryHeader { - - fn get_internal_links(self: &EntryHeader) -> Result { - process_rw_result(self.read("imag.links")) - } - - /// Set the links in a header and return the old links, if any. - fn set_internal_links(&mut self, links: Links) -> Result { - let links : Vec = links.into(); - let links : Vec = links.into_iter().map(|link| Value::String(link.into())).collect(); - process_rw_result(self.set("imag.links", Value::Array(links))) - } - - fn add_internal_link(&mut self, link: Link) -> Result<()> { - self.get_internal_links() - .and_then(|mut links| { - links.add(link); - self.set_internal_links(links).map(|_| ()) - }) - } - - fn remove_internal_link(&mut self, link: Link) -> Result<()> { - self.get_internal_links() - .and_then(|mut links| { - links.remove(link); - self.set_internal_links(links).map(|_| ()) - }) - } + fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()>; } impl InternalLinker for Entry { - fn get_internal_links(&self) -> Result { - self.get_header().get_internal_links() + fn get_internal_links(&self) -> Result> { + process_rw_result(self.get_header().read("imag.links")) } - fn set_internal_links(&mut self, links: Links) -> Result { - self.get_header_mut().set_internal_links(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> { + 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); + } + let link = link.get_location().clone(); + let link = link.to_str(); + if link.is_none() { + return Err(LinkError::new(LinkErrorKind::InternalConversionError, None)); + } + let link = link.unwrap(); + + new_links.push(Value::String(String::from(link))); + } + + process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links))) } - fn add_internal_link(&mut self, link: Link) -> Result<()> { - self.get_header_mut().add_internal_link(link) + fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> { + let new_link = link.get_location().clone(); + let new_link = new_link.to_str(); + if new_link.is_none() { + return Err(LinkError::new(LinkErrorKind::InternalConversionError, None)); + } + let new_link = new_link.unwrap(); + + add_foreign_link(link, self.get_location().clone()) + .and_then(|_| { + self.get_internal_links() + .and_then(|mut links| { + links.push(String::from(new_link)); + let links = links.into_iter().map(|s| Value::String(s)).collect(); + let process = self.get_header_mut().set("imag.links", Value::Array(links)); + process_rw_result(process) + .map(|_| ()) + }) + }) } - fn remove_internal_link(&mut self, link: Link) -> Result<()> { - self.get_header_mut().remove_internal_link(link) + fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> { + let own_loc = link.get_location().clone(); + let own_loc = own_loc.to_str(); + if own_loc.is_none() { + return Err(LinkError::new(LinkErrorKind::InternalConversionError, None)); + } + let own_loc = own_loc.unwrap(); + + let other_loc = link.get_location().clone(); + let other_loc = other_loc.to_str(); + if other_loc.is_none() { + return Err(LinkError::new(LinkErrorKind::InternalConversionError, None)); + } + let other_loc = other_loc.unwrap(); + + link.get_internal_links() + .and_then(|mut links| { + let links = links.into_iter() + .filter(|l| l.clone() != own_loc) + .map(|s| Value::String(s)) + .collect(); + process_rw_result(link.get_header_mut().set("imag.links", Value::Array(links))) + .map(|_| ()) + }) + .and_then(|_| { + self.get_internal_links() + .and_then(|mut links| { + let links = links + .into_iter() + .filter(|l| l.clone() != other_loc) + .map(|s| Value::String(s)) + .collect(); + process_rw_result(self.get_header_mut().set("imag.links", Value::Array(links))) + .map(|_| ()) + }) + }) } + } -fn process_rw_result(links: StoreResult>) -> Result { +/// When Linking A -> B, the specification wants us to link back B -> A. +/// This is a helper function which does this. +fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> { + let from = from.to_str(); + if from.is_none() { + debug!("Cannot convert pathbuf '{:?}' to String", from); + return Err(LinkError::new(LinkErrorKind::InternalConversionError, None)); + } + let from = from.unwrap(); + + target.get_internal_links() + .and_then(|mut links| { + links.push(String::from(from)); + let links = links.into_iter().map(|s| Value::String(s)).collect(); + process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links))) + .map(|_| ()) + }) +} + +fn process_rw_result(links: StoreResult>) -> Result> { if links.is_err() { let lerr = LinkError::new(LinkErrorKind::EntryHeaderReadError, Some(Box::new(links.err().unwrap()))); @@ -89,12 +149,12 @@ fn process_rw_result(links: StoreResult>) -> Result { let links : Vec = links.into_iter() .map(|link| { match link { - Value::String(s) => Link::new(s), + Value::String(s) => String::from(s), _ => unreachable!(), } }) .collect(); - Ok(Links::new(links)) + Ok(links) } diff --git a/libimaglink/src/lib.rs b/libimaglink/src/lib.rs index fdfa3d08..0ea1f956 100644 --- a/libimaglink/src/lib.rs +++ b/libimaglink/src/lib.rs @@ -6,6 +6,5 @@ extern crate libimagstore; pub mod error; pub mod external; pub mod internal; -pub mod link; pub mod result;