tagable.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. //
  2. // imag - the personal information management suite for the commandline
  3. // Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
  4. //
  5. // This library is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU Lesser General Public
  7. // License as published by the Free Software Foundation; version
  8. // 2.1 of the License.
  9. //
  10. // This library is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. // Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public
  16. // License along with this library; if not, write to the Free Software
  17. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. //
  19. use std::ops::Deref;
  20. use std::ops::DerefMut;
  21. use itertools::Itertools;
  22. use libimagstore::store::{Entry, EntryHeader, FileLockEntry};
  23. use libimagerror::into::IntoError;
  24. use error::TagErrorKind;
  25. use error::MapErrInto;
  26. use result::Result;
  27. use tag::{Tag, TagSlice};
  28. use util::is_tag;
  29. use toml::Value;
  30. pub trait Tagable {
  31. fn get_tags(&self) -> Result<Vec<Tag>>;
  32. fn set_tags(&mut self, ts: &[Tag]) -> Result<()>;
  33. fn add_tag(&mut self, t: Tag) -> Result<()>;
  34. fn remove_tag(&mut self, t: Tag) -> Result<()>;
  35. fn has_tag(&self, t: TagSlice) -> Result<bool>;
  36. fn has_tags(&self, ts: &[Tag]) -> Result<bool>;
  37. }
  38. impl Tagable for EntryHeader {
  39. fn get_tags(&self) -> Result<Vec<Tag>> {
  40. let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));
  41. match tags {
  42. Some(Value::Array(tags)) => {
  43. if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
  44. return Err(TagErrorKind::TagTypeError.into());
  45. }
  46. if tags.iter().any(|t| match *t {
  47. Value::String(ref s) => !is_tag(s),
  48. _ => unreachable!()})
  49. {
  50. return Err(TagErrorKind::NotATag.into());
  51. }
  52. Ok(tags.iter()
  53. .cloned()
  54. .map(|t| {
  55. match t {
  56. Value::String(s) => s,
  57. _ => unreachable!(),
  58. }
  59. })
  60. .collect())
  61. },
  62. None => Ok(vec![]),
  63. _ => Err(TagErrorKind::TagTypeError.into()),
  64. }
  65. }
  66. fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
  67. if ts.iter().any(|tag| !is_tag(tag)) {
  68. debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
  69. return Err(TagErrorKind::NotATag.into());
  70. }
  71. let a = ts.iter().unique().map(|t| Value::String(t.clone())).collect();
  72. self.set("imag.tags", Value::Array(a))
  73. .map(|_| ())
  74. .map_err(Box::new)
  75. .map_err(|e| TagErrorKind::HeaderWriteError.into_error_with_cause(e))
  76. }
  77. fn add_tag(&mut self, t: Tag) -> Result<()> {
  78. if !is_tag(&t) {
  79. debug!("Not a tag: '{}'", t);
  80. return Err(TagErrorKind::NotATag.into());
  81. }
  82. self.get_tags()
  83. .map(|mut tags| {
  84. tags.push(t);
  85. self.set_tags(&tags.into_iter().unique().collect::<Vec<_>>()[..])
  86. })
  87. .map(|_| ())
  88. }
  89. fn remove_tag(&mut self, t: Tag) -> Result<()> {
  90. if !is_tag(&t) {
  91. debug!("Not a tag: '{}'", t);
  92. return Err(TagErrorKind::NotATag.into());
  93. }
  94. self.get_tags()
  95. .map(|mut tags| {
  96. tags.retain(|tag| tag.clone() != t);
  97. self.set_tags(&tags[..])
  98. })
  99. .map(|_| ())
  100. }
  101. fn has_tag(&self, t: TagSlice) -> Result<bool> {
  102. let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));
  103. if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
  104. return Err(TagErrorKind::TagTypeError.into());
  105. }
  106. Ok(tags
  107. .iter()
  108. .any(|tag| {
  109. match *tag {
  110. Value::String(ref s) => { s == t },
  111. _ => unreachable!()
  112. }
  113. }))
  114. }
  115. fn has_tags(&self, tags: &[Tag]) -> Result<bool> {
  116. let mut result = true;
  117. for tag in tags {
  118. result = result && try!(self.has_tag(tag));
  119. }
  120. Ok(result)
  121. }
  122. }
  123. impl Tagable for Entry {
  124. fn get_tags(&self) -> Result<Vec<Tag>> {
  125. self.get_header().get_tags()
  126. }
  127. fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
  128. self.get_header_mut().set_tags(ts)
  129. }
  130. fn add_tag(&mut self, t: Tag) -> Result<()> {
  131. self.get_header_mut().add_tag(t)
  132. }
  133. fn remove_tag(&mut self, t: Tag) -> Result<()> {
  134. self.get_header_mut().remove_tag(t)
  135. }
  136. fn has_tag(&self, t: TagSlice) -> Result<bool> {
  137. self.get_header().has_tag(t)
  138. }
  139. fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
  140. self.get_header().has_tags(ts)
  141. }
  142. }
  143. impl<'a> Tagable for FileLockEntry<'a> {
  144. fn get_tags(&self) -> Result<Vec<Tag>> {
  145. self.deref().get_tags()
  146. }
  147. fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
  148. self.deref_mut().set_tags(ts)
  149. }
  150. fn add_tag(&mut self, t: Tag) -> Result<()> {
  151. self.deref_mut().add_tag(t)
  152. }
  153. fn remove_tag(&mut self, t: Tag) -> Result<()> {
  154. self.deref_mut().remove_tag(t)
  155. }
  156. fn has_tag(&self, t: TagSlice) -> Result<bool> {
  157. self.deref().has_tag(t)
  158. }
  159. fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
  160. self.deref().has_tags(ts)
  161. }
  162. }