ipaacar_core/components/iu/
links.rs

1use crate::components::iu::core::IUCoreError;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5/// Datastructure that implements IULinks based on a HashMap.
6#[derive(Default, Debug, Serialize, Deserialize, Clone)]
7pub struct IULinks {
8    pub link_map: HashMap<String, Vec<String>>,
9}
10
11impl IULinks {
12    pub fn add_target_to_link(&mut self, link_name: &str, target: impl Into<String>) {
13        if let Some(v) = self.link_map.get_mut(link_name) {
14            v.push(target.into());
15        } else {
16            self.link_map
17                .insert(link_name.to_string(), vec![target.into()]);
18        }
19    }
20
21    pub fn remove_target_from_link(
22        &mut self,
23        link_name: &str,
24        target: &str,
25    ) -> Result<(), IUCoreError> {
26        if let Some(v) = self.link_map.get_mut(link_name) {
27            if let Some(i) = v.iter().position(|x| x == target) {
28                v.remove(i);
29                if v.is_empty() {
30                    self.remove_link(link_name)?;
31                }
32                Ok(())
33            } else {
34                Err(IUCoreError::LinkTargetNotFound)
35            }
36        } else {
37            Err(IUCoreError::LinkNotFound)
38        }
39    }
40
41    pub fn remove_link(&mut self, link_name: &str) -> Result<(), IUCoreError> {
42        self.link_map
43            .remove(link_name)
44            .ok_or(IUCoreError::LinkNotFound)
45            .map(|_| ())
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use crate::components::iu::core::IUCoreError;
52    use crate::components::iu::links::IULinks;
53    use std::collections::HashMap;
54
55    #[test]
56    fn iu_link_test() {
57        let mut iu_links = IULinks::default();
58        iu_links.add_target_to_link("grounded-in", "abc");
59        iu_links.add_target_to_link("grounded-in", "def");
60        iu_links.add_target_to_link("grounded-in", "fff");
61        iu_links.add_target_to_link("joy", "fff");
62        iu_links.add_target_to_link("joy", "ddd");
63
64        assert_eq!(
65            iu_links.link_map,
66            HashMap::from([
67                (
68                    "grounded-in".to_string(),
69                    vec!["abc".to_string(), "def".to_string(), "fff".to_string()]
70                ),
71                (
72                    "joy".to_string(),
73                    vec!["fff".to_string(), "ddd".to_string()]
74                )
75            ])
76        );
77
78        iu_links
79            .remove_target_from_link("grounded-in", "def")
80            .unwrap();
81        assert_eq!(
82            iu_links.remove_target_from_link("grounded-in", "def"),
83            Err(IUCoreError::LinkTargetNotFound)
84        );
85        assert_eq!(
86            iu_links.remove_target_from_link("grounded-in", "ggg"),
87            Err(IUCoreError::LinkTargetNotFound)
88        );
89        assert_eq!(
90            iu_links.remove_target_from_link("ggg", "gdddd-in"),
91            Err(IUCoreError::LinkNotFound)
92        );
93
94        iu_links
95            .remove_target_from_link("grounded-in", "abc")
96            .unwrap();
97        iu_links
98            .remove_target_from_link("grounded-in", "fff")
99            .unwrap();
100
101        assert_eq!(
102            iu_links.remove_link("grounded-in"),
103            Err(IUCoreError::LinkNotFound)
104        );
105
106        iu_links.remove_link("joy").unwrap();
107
108        assert_eq!(iu_links.link_map, HashMap::default())
109    }
110}