1use std::path::PathBuf;
21
22use libimagstore::storeid::StoreId;
23use libimagstore::store::Entry;
24use libimagstore::store::Store;
25
26use toml_query::read::Partial;
27use toml_query::read::TomlValueReadExt;
28use toml_query::insert::TomlValueInsertExt;
29use failure::ResultExt;
30use failure::Fallible as Result;
31use failure::err_msg;
32
33use crate::iter::LinkIter;
34use crate::link::Link;
35
36pub trait Linkable {
37
38 fn links(&self) -> Result<LinkIter>;
40
41 fn unidirectional_links(&self) -> Result<LinkIter>;
43
44 fn directional_links_to(&self) -> Result<LinkIter>;
46
47 fn directional_links_from(&self) -> Result<LinkIter>;
49
50 fn add_link(&mut self, link: &mut Entry) -> Result<()>;
52
53 fn remove_link(&mut self, link: &mut Entry) -> Result<()>;
55
56 fn unlink(&mut self, store: &Store) -> Result<()>;
58
59 fn add_link_to(&mut self, other: &mut Entry) -> Result<()>;
61
62 fn remove_link_to(&mut self, other: &mut Entry) -> Result<()>;
64
65 fn is_linked_to(&self, other: &Entry) -> Result<bool>;
67}
68
69#[derive(Serialize, Deserialize, Debug)]
70struct LinkPartial {
71 internal: Option<Vec<String>>,
72 from: Option<Vec<String>>,
73 to: Option<Vec<String>>,
74}
75
76impl Default for LinkPartial {
77 fn default() -> Self {
78 LinkPartial {
79 internal: None,
80 from: None,
81 to: None,
82 }
83 }
84}
85
86impl<'a> Partial<'a> for LinkPartial {
87 const LOCATION: &'static str = "links";
88 type Output = Self;
89}
90
91impl Linkable for Entry {
92
93 fn links(&self) -> Result<LinkIter> {
94 debug!("Getting internal links");
95 trace!("Getting internal links from header of '{}' = {:?}", self.get_location(), self.get_header());
96
97 let partial : LinkPartial = self
98 .get_header()
99 .read_partial::<LinkPartial>()?
100 .unwrap_or_else(LinkPartial::default);
101
102 partial
103 .internal
104 .unwrap_or_else(|| vec![])
105 .into_iter()
106 .chain(partial.from.unwrap_or_else(|| vec![]).into_iter())
107 .chain(partial.to.unwrap_or_else(|| vec![]).into_iter())
108 .map(PathBuf::from)
109 .map(StoreId::new)
110 .map(|r| r.map(Link::from))
111 .collect::<Result<Vec<Link>>>()
112 .map(LinkIter::new)
113 }
114
115 fn unidirectional_links(&self) -> Result<LinkIter> {
117 debug!("Getting unidirectional links");
118 trace!("Getting unidirectional links from header of '{}' = {:?}", self.get_location(), self.get_header());
119
120 let iter = self.get_header()
121 .read_partial::<LinkPartial>()?
122 .unwrap_or_else(Default::default)
123 .internal
124 .unwrap_or_else(|| vec![])
125 .into_iter();
126
127 link_string_iter_to_link_iter(iter)
128 }
129
130 fn directional_links_to(&self) -> Result<LinkIter> {
132 debug!("Getting directional links (to)");
133 trace!("Getting unidirectional (to) links from header of '{}' = {:?}", self.get_location(), self.get_header());
134
135 let iter = self.get_header()
136 .read_partial::<LinkPartial>()?
137 .unwrap_or_else(Default::default)
138 .to
139 .unwrap_or_else(|| vec![])
140 .into_iter();
141
142 link_string_iter_to_link_iter(iter)
143 }
144
145 fn directional_links_from(&self) -> Result<LinkIter> {
147 debug!("Getting directional links (from)");
148 trace!("Getting unidirectional (from) links from header of '{}' = {:?}", self.get_location(), self.get_header());
149
150 let iter = self.get_header()
151 .read_partial::<LinkPartial>()?
152 .unwrap_or_else(Default::default)
153 .from
154 .unwrap_or_else(|| vec![])
155 .into_iter();
156
157 link_string_iter_to_link_iter(iter)
158 }
159
160 fn add_link(&mut self, other: &mut Entry) -> Result<()> {
161 debug!("Adding internal link: {:?}", other);
162 let left_location = self.get_location().to_str()?;
163 let right_location = other.get_location().to_str()?;
164
165 alter_linking(self, other, |mut left, mut right| {
166 let mut left_internal = left.internal.unwrap_or_else(|| vec![]);
167 trace!("left: {:?} <- {:?}", left_internal, right_location);
168 left_internal.push(right_location);
169 trace!("left: {:?}", left_internal);
170
171 left_internal.sort_unstable();
172 left_internal.dedup();
173
174 let mut right_internal = right.internal.unwrap_or_else(|| vec![]);
175 trace!("right: {:?} <- {:?}", right_internal, left_location);
176 right_internal.push(left_location);
177 trace!("right: {:?}", right_internal);
178
179 right_internal.sort_unstable();
180 right_internal.dedup();
181
182 left.internal = Some(left_internal);
183 right.internal = Some(right_internal);
184
185 trace!("Finished: ({:?}, {:?})", left, right);
186 Ok((left, right))
187 })
188 }
189
190 fn remove_link(&mut self, other: &mut Entry) -> Result<()> {
191 debug!("Remove internal link: {:?}", other);
192 let left_location = self.get_location().to_str()?;
193 let right_location = other.get_location().to_str()?;
194
195 alter_linking(self, other, |mut left, mut right| {
196 let mut left_internal = left.internal.unwrap_or_else(|| vec![]);
197 trace!("left: {:?} retaining {:?}", left_internal, right_location);
198 left_internal.retain(|l| *l != right_location);
199 trace!("left: {:?}", left_internal);
200
201 left_internal.sort_unstable();
202 left_internal.dedup();
203
204 let mut right_internal = right.internal.unwrap_or_else(|| vec![]);
205 trace!("right: {:?} retaining {:?}", right_internal, left_location);
206 right_internal.retain(|l| *l != left_location);
207 trace!("right: {:?}", right_internal);
208
209 right_internal.sort_unstable();
210 right_internal.dedup();
211
212 left.internal = Some(left_internal);
213 right.internal = Some(right_internal);
214
215 trace!("Finished: ({:?}, {:?})", left, right);
216 Ok((left, right))
217 })
218 }
219
220 fn unlink(&mut self, store: &Store) -> Result<()> {
221 debug!("Unlinking {:?}", self);
222 for id in self.links()?.map(|l| l.get_store_id().clone()) {
223 match store.get(id).context("Failed to get entry")? {
224 Some(mut entry) => self.remove_link(&mut entry)?,
225 None => return Err(err_msg("Link target does not exist")),
226 }
227 }
228
229 Ok(())
230 }
231
232 fn add_link_to(&mut self, other: &mut Entry) -> Result<()> {
233 let left_location = self.get_location().to_str()?;
234 let right_location = other.get_location().to_str()?;
235
236 alter_linking(self, other, |mut left, mut right| {
237 let mut left_to = left.to.unwrap_or_else(|| vec![]);
238 trace!("left_to: {:?} <- {:?}", left_to, right_location);
239 left_to.push(right_location);
240 trace!("left_to: {:?}", left_to);
241
242 let mut right_from = right.from.unwrap_or_else(|| vec![]);
243 trace!("right_from: {:?} <- {:?}", right_from, left_location);
244 right_from.push(left_location);
245 trace!("right_from: {:?}", right_from);
246
247 left.to = Some(left_to);
248 right.from = Some(right_from);
249
250 trace!("Finished: ({:?}, {:?})", left, right);
251 Ok((left, right))
252 })
253 }
254
255 fn remove_link_to(&mut self, other: &mut Entry) -> Result<()> {
257 let left_location = self.get_location().to_str()?;
258 let right_location = other.get_location().to_str()?;
259
260 alter_linking(self, other, |mut left, mut right| {
261 let mut left_to = left.to.unwrap_or_else(|| vec![]);
262 trace!("left_to: {:?} retaining {:?}", left_to, right_location);
263 left_to.retain(|l| *l != right_location);
264 trace!("left_to: {:?}", left_to);
265
266 let mut right_from = right.from.unwrap_or_else(|| vec![]);
267 trace!("right_from: {:?} retaining {:?}", right_from, left_location);
268 right_from.retain(|l| *l != left_location);
269 trace!("right_from: {:?}", right_from);
270
271 left.to = Some(left_to);
272 right.from = Some(right_from);
273
274 trace!("Finished: ({:?}, {:?})", left, right);
275 Ok((left, right))
276 })
277 }
278
279 fn is_linked_to(&self, other: &Entry) -> Result<bool> {
281 let left_partial = get_link_partial(self)?
282 .ok_or_else(|| format_err!("Cannot read links from {}", self.get_location()))?;
283 let right_partial = get_link_partial(&other)?
284 .ok_or_else(|| format_err!("Cannot read links from {}", other.get_location()))?;
285
286 let left_id = self.get_location();
287 let right_id = other.get_location();
288
289 let strary_contains = |sary: &Vec<String>, id: &StoreId| -> Result<bool> {
290 sary.iter().map(|e| {
291 StoreId::new(PathBuf::from(e)).map(|e| e == *id)
292 }).fold(Ok(false), |a, e| a.and_then(|_| e))
293 };
294
295 let is_linked_from = |partial: &LinkPartial, id| {
296 partial.from.as_ref().map(|f| strary_contains(f, id)).unwrap_or(Ok(false))
297 };
298 let is_linked_to = |partial: &LinkPartial, id| {
299 partial.to.as_ref().map(|t| strary_contains(t, id)).unwrap_or(Ok(false))
300 };
301
302 Ok({
303 is_linked_from(&left_partial, &right_id)? && is_linked_from(&right_partial, &left_id)?
304 ||
305 is_linked_to(&left_partial, &right_id)? && is_linked_to(&right_partial, &left_id)?
306 })
307 }
308}
309
310fn link_string_iter_to_link_iter<I>(iter: I) -> Result<LinkIter>
311 where I: Iterator<Item = String>
312{
313 iter.map(PathBuf::from)
314 .map(StoreId::new)
315 .map(|r| r.map(Link::from))
316 .collect::<Result<Vec<Link>>>()
317 .map(LinkIter::new)
318}
319
320fn alter_linking<F>(left: &mut Entry, right: &mut Entry, f: F) -> Result<()>
321 where F: FnOnce(LinkPartial, LinkPartial) -> Result<(LinkPartial, LinkPartial)>
322{
323 debug!("Altering linkage of {:?} and {:?}", left, right);
324 let get_partial = |e| -> Result<_> {
325 Ok(get_link_partial(e)?.unwrap_or_else(LinkPartial::default))
326 };
327
328 let left_partial : LinkPartial = get_partial(&left)?;
329 let right_partial : LinkPartial = get_partial(&right)?;
330
331 trace!("Partial left before: {:?}", left_partial);
332 trace!("Partial right before: {:?}", right_partial);
333
334 let (left_partial, right_partial) = f(left_partial, right_partial)?;
335
336 trace!("Partial left after: {:?}", left_partial);
337 trace!("Partial right after: {:?}", right_partial);
338
339 left.get_header_mut().insert_serialized("links", left_partial)?;
340 right.get_header_mut().insert_serialized("links", right_partial)?;
341
342 debug!("Finished altering linkage!");
343 Ok(())
344}
345
346fn get_link_partial(entry: &Entry) -> Result<Option<LinkPartial>> {
347 use failure::Error;
348 entry.get_header().read_partial::<LinkPartial>().map_err(Error::from)
349}
350
351
352#[cfg(test)]
353mod test {
354 use std::path::PathBuf;
355
356 use libimagstore::store::Store;
357
358 use super::Linkable;
359
360 fn setup_logging() {
361 let _ = ::env_logger::try_init();
362 }
363
364 pub fn get_store() -> Store {
365 Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
366 }
367
368 #[test]
369 fn test_new_entry_no_links() {
370 setup_logging();
371 let store = get_store();
372 let entry = store.create(PathBuf::from("test_new_entry_no_links")).unwrap();
373 let links = entry.links();
374 assert!(links.is_ok());
375 let links = links.unwrap();
376 assert_eq!(links.count(), 0);
377 }
378
379 #[test]
380 fn test_link_two_entries() {
381 setup_logging();
382 let store = get_store();
383 let mut e1 = store.create(PathBuf::from("test_link_two_entries1")).unwrap();
384 assert!(e1.links().is_ok());
385
386 let mut e2 = store.create(PathBuf::from("test_link_two_entries2")).unwrap();
387 assert!(e2.links().is_ok());
388
389 {
390 let res = e1.add_link(&mut e2);
391 debug!("Result = {:?}", res);
392 assert!(res.is_ok());
393
394 let e1_links = e1.links().unwrap().collect::<Vec<_>>();
395 let e2_links = e2.links().unwrap().collect::<Vec<_>>();
396
397 debug!("1 has links: {:?}", e1_links);
398 debug!("2 has links: {:?}", e2_links);
399
400 assert_eq!(e1_links.len(), 1);
401 assert_eq!(e2_links.len(), 1);
402
403 assert!(e1_links.first().map(|l| l.clone().eq_store_id(e2.get_location())).unwrap_or(false));
404 assert!(e2_links.first().map(|l| l.clone().eq_store_id(e1.get_location())).unwrap_or(false));
405 }
406
407 {
408 assert!(e1.remove_link(&mut e2).is_ok());
409
410 debug!("{:?}", e2.to_str());
411 let e2_links = e2.links().unwrap().collect::<Vec<_>>();
412 assert_eq!(e2_links.len(), 0, "Expected [], got: {:?}", e2_links);
413
414 debug!("{:?}", e1.to_str());
415 let e1_links = e1.links().unwrap().collect::<Vec<_>>();
416 assert_eq!(e1_links.len(), 0, "Expected [], got: {:?}", e1_links);
417
418 }
419 }
420
421 #[test]
422 #[clippy::cognitive_complexity = "49"]
423 fn test_multiple_links() {
424 setup_logging();
425 let store = get_store();
426
427 let mut e1 = store.retrieve(PathBuf::from("1")).unwrap();
428 let mut e2 = store.retrieve(PathBuf::from("2")).unwrap();
429 let mut e3 = store.retrieve(PathBuf::from("3")).unwrap();
430 let mut e4 = store.retrieve(PathBuf::from("4")).unwrap();
431 let mut e5 = store.retrieve(PathBuf::from("5")).unwrap();
432
433 assert!(e1.add_link(&mut e2).is_ok());
434
435 assert_eq!(e1.links().unwrap().count(), 1);
436 assert_eq!(e2.links().unwrap().count(), 1);
437 assert_eq!(e3.links().unwrap().count(), 0);
438 assert_eq!(e4.links().unwrap().count(), 0);
439 assert_eq!(e5.links().unwrap().count(), 0);
440
441 assert!(e1.add_link(&mut e3).is_ok());
442
443 assert_eq!(e1.links().unwrap().count(), 2);
444 assert_eq!(e2.links().unwrap().count(), 1);
445 assert_eq!(e3.links().unwrap().count(), 1);
446 assert_eq!(e4.links().unwrap().count(), 0);
447 assert_eq!(e5.links().unwrap().count(), 0);
448
449 assert!(e1.add_link(&mut e4).is_ok());
450
451 assert_eq!(e1.links().unwrap().count(), 3);
452 assert_eq!(e2.links().unwrap().count(), 1);
453 assert_eq!(e3.links().unwrap().count(), 1);
454 assert_eq!(e4.links().unwrap().count(), 1);
455 assert_eq!(e5.links().unwrap().count(), 0);
456
457 assert!(e1.add_link(&mut e5).is_ok());
458
459 assert_eq!(e1.links().unwrap().count(), 4);
460 assert_eq!(e2.links().unwrap().count(), 1);
461 assert_eq!(e3.links().unwrap().count(), 1);
462 assert_eq!(e4.links().unwrap().count(), 1);
463 assert_eq!(e5.links().unwrap().count(), 1);
464
465 assert!(e5.remove_link(&mut e1).is_ok());
466
467 assert_eq!(e1.links().unwrap().count(), 3);
468 assert_eq!(e2.links().unwrap().count(), 1);
469 assert_eq!(e3.links().unwrap().count(), 1);
470 assert_eq!(e4.links().unwrap().count(), 1);
471 assert_eq!(e5.links().unwrap().count(), 0);
472
473 assert!(e4.remove_link(&mut e1).is_ok());
474
475 assert_eq!(e1.links().unwrap().count(), 2);
476 assert_eq!(e2.links().unwrap().count(), 1);
477 assert_eq!(e3.links().unwrap().count(), 1);
478 assert_eq!(e4.links().unwrap().count(), 0);
479 assert_eq!(e5.links().unwrap().count(), 0);
480
481 assert!(e3.remove_link(&mut e1).is_ok());
482
483 assert_eq!(e1.links().unwrap().count(), 1);
484 assert_eq!(e2.links().unwrap().count(), 1);
485 assert_eq!(e3.links().unwrap().count(), 0);
486 assert_eq!(e4.links().unwrap().count(), 0);
487 assert_eq!(e5.links().unwrap().count(), 0);
488
489 assert!(e2.remove_link(&mut e1).is_ok());
490
491 assert_eq!(e1.links().unwrap().count(), 0);
492 assert_eq!(e2.links().unwrap().count(), 0);
493 assert_eq!(e3.links().unwrap().count(), 0);
494 assert_eq!(e4.links().unwrap().count(), 0);
495 assert_eq!(e5.links().unwrap().count(), 0);
496
497 }
498
499 #[test]
500 fn test_link_deleting() {
501 setup_logging();
502 let store = get_store();
503
504 let mut e1 = store.retrieve(PathBuf::from("1")).unwrap();
505 let mut e2 = store.retrieve(PathBuf::from("2")).unwrap();
506
507 assert_eq!(e1.links().unwrap().count(), 0);
508 assert_eq!(e2.links().unwrap().count(), 0);
509
510 assert!(e1.add_link(&mut e2).is_ok());
511
512 assert_eq!(e1.links().unwrap().count(), 1);
513 assert_eq!(e2.links().unwrap().count(), 1);
514
515 assert!(e1.remove_link(&mut e2).is_ok());
516
517 assert_eq!(e1.links().unwrap().count(), 0);
518 assert_eq!(e2.links().unwrap().count(), 0);
519 }
520
521 #[test]
522 fn test_link_deleting_multiple_links() {
523 setup_logging();
524 let store = get_store();
525
526 let mut e1 = store.retrieve(PathBuf::from("1")).unwrap();
527 let mut e2 = store.retrieve(PathBuf::from("2")).unwrap();
528 let mut e3 = store.retrieve(PathBuf::from("3")).unwrap();
529
530 assert_eq!(e1.links().unwrap().count(), 0);
531 assert_eq!(e2.links().unwrap().count(), 0);
532 assert_eq!(e3.links().unwrap().count(), 0);
533
534 assert!(e1.add_link(&mut e2).is_ok()); assert!(e1.add_link(&mut e3).is_ok()); assert_eq!(e1.links().unwrap().count(), 2);
538 assert_eq!(e2.links().unwrap().count(), 1);
539 assert_eq!(e3.links().unwrap().count(), 1);
540
541 assert!(e2.add_link(&mut e3).is_ok()); assert_eq!(e1.links().unwrap().count(), 2);
544 assert_eq!(e2.links().unwrap().count(), 2);
545 assert_eq!(e3.links().unwrap().count(), 2);
546
547 assert!(e1.remove_link(&mut e2).is_ok()); assert_eq!(e1.links().unwrap().count(), 1);
550 assert_eq!(e2.links().unwrap().count(), 1);
551 assert_eq!(e3.links().unwrap().count(), 2);
552
553 assert!(e1.remove_link(&mut e3).is_ok()); assert_eq!(e1.links().unwrap().count(), 0);
556 assert_eq!(e2.links().unwrap().count(), 1);
557 assert_eq!(e3.links().unwrap().count(), 1);
558
559 assert!(e2.remove_link(&mut e3).is_ok());
560
561 assert_eq!(e1.links().unwrap().count(), 0);
562 assert_eq!(e2.links().unwrap().count(), 0);
563 assert_eq!(e3.links().unwrap().count(), 0);
564 }
565
566 #[test]
567 fn test_directional_link() {
568 use libimagstore::store::Entry;
569
570 setup_logging();
571 let store = get_store();
572 let mut entry1 = store.create(PathBuf::from("test_directional_link-1")).unwrap();
573 let mut entry2 = store.create(PathBuf::from("test_directional_link-2")).unwrap();
574
575 assert!(entry1.unidirectional_links().unwrap().next().is_none());
576 assert!(entry2.unidirectional_links().unwrap().next().is_none());
577
578 assert!(entry1.directional_links_to().unwrap().next().is_none());
579 assert!(entry2.directional_links_to().unwrap().next().is_none());
580
581 assert!(entry1.directional_links_from().unwrap().next().is_none());
582 assert!(entry2.directional_links_from().unwrap().next().is_none());
583
584 assert!(entry1.add_link_to(&mut entry2).is_ok());
585
586 assert_eq!(entry1.unidirectional_links().unwrap().collect::<Vec<_>>(), vec![]);
587 assert_eq!(entry2.unidirectional_links().unwrap().collect::<Vec<_>>(), vec![]);
588
589 let get_directional_links_to = |e: &Entry| -> Result<Vec<String>, _> {
590 e.directional_links_to()
591 .unwrap()
592 .map(|l| l.to_str())
593 .collect::<Result<Vec<_>, _>>()
594 };
595
596 let get_directional_links_from = |e: &Entry| {
597 e.directional_links_from()
598 .unwrap()
599 .map(|l| l.to_str())
600 .collect::<Result<Vec<_>, _>>()
601 };
602
603 {
604 let entry1_dir_links = get_directional_links_to(&entry1).unwrap();
605 assert_eq!(entry1_dir_links, vec!["test_directional_link-2"]);
606 }
607 {
608 let entry2_dir_links = get_directional_links_to(&entry2).unwrap();
609 assert!(entry2_dir_links.is_empty());
610 }
611
612 {
613 let entry1_dir_links = get_directional_links_from(&entry1).unwrap();
614 assert!(entry1_dir_links.is_empty());
615 }
616 {
617 let entry2_dir_links = get_directional_links_from(&entry2).unwrap();
618 assert_eq!(entry2_dir_links, vec!["test_directional_link-1"]);
619 }
620
621 }
622
623}