tosca_controller/
policy.rs

1use std::collections::HashMap;
2
3use tosca::hazards::Hazards;
4
5// TODO: Eventually rewrite policy IDs as &'static str.
6
7/// A privacy policy manager.
8///
9/// It allows or blocks the requests to devices, or to a specific device,
10/// according to a set of privacy rules.
11#[derive(Debug, PartialEq)]
12pub struct Policy {
13    block_on_hazards: Hazards,
14    block_device_on_hazards: HashMap<usize, Hazards>,
15}
16
17impl Policy {
18    /// Creates a [`Policy`] to block **all** requests that have the given
19    /// [`Hazards`] in their routes.
20    #[must_use]
21    #[inline]
22    pub fn new(block_on_hazards: Hazards) -> Self {
23        Self {
24            block_on_hazards,
25            block_device_on_hazards: HashMap::new(),
26        }
27    }
28
29    /// Creates a [`Policy`] to block **all** [`crate::device::Device`] id
30    /// requests that have the given [`Hazards`] in their routes.
31    #[must_use]
32    #[inline]
33    pub fn only_local_policy(id: usize, hazards: Hazards) -> Self {
34        let policy = Self::init();
35        policy.block_device_on_hazards(id, hazards)
36    }
37
38    /// Adds a new [`Policy`] to block **all** [`crate::device::Device`] id
39    /// requests that have the given [`Hazards`] in their routes.
40    #[must_use]
41    #[inline]
42    pub fn block_device_on_hazards(mut self, id: usize, hazards: Hazards) -> Self {
43        self.block_device_on_hazards.insert(id, hazards);
44        self
45    }
46
47    pub(crate) fn init() -> Self {
48        Self {
49            block_on_hazards: Hazards::new(),
50            block_device_on_hazards: HashMap::new(),
51        }
52    }
53
54    pub(crate) fn global_blocked_hazards(&self, hazards: &Hazards) -> Hazards {
55        let mut blocked_hazards = Hazards::new();
56        for hazard in hazards {
57            if self.block_on_hazards.contains(hazard) {
58                blocked_hazards.add(*hazard);
59            }
60        }
61        blocked_hazards
62    }
63
64    pub(crate) fn local_blocked_hazards(&self, id: usize, hazards: &Hazards) -> Hazards {
65        if let Some(local_hazards) = self.block_device_on_hazards.get(&id) {
66            let mut blocked_hazards = Hazards::new();
67            for hazard in hazards {
68                if local_hazards.contains(hazard) {
69                    blocked_hazards.add(*hazard);
70                }
71            }
72            blocked_hazards
73        } else {
74            Hazards::new()
75        }
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use std::collections::HashMap;
82
83    use tosca::hazards::{Hazard, Hazards};
84
85    use super::Policy;
86
87    fn create_policy() -> (Hazards, Policy) {
88        let hazards = Hazards::new().insert(Hazard::ElectricEnergyConsumption);
89
90        let policy = Policy::new(hazards.clone());
91
92        (hazards, policy)
93    }
94
95    fn check_device_policies(policy: &Policy, block_on_hazards: Hazards, local_hazards: &Hazards) {
96        let mut devices_hazards = HashMap::new();
97        devices_hazards.insert(1, local_hazards.clone());
98        devices_hazards.insert(2, local_hazards.clone());
99
100        assert_eq!(
101            policy,
102            &Policy {
103                block_on_hazards,
104                block_device_on_hazards: devices_hazards,
105            }
106        );
107    }
108
109    #[test]
110    fn only_global_policy() {
111        let (hazards, policy) = create_policy();
112
113        assert_eq!(
114            policy,
115            Policy {
116                block_on_hazards: hazards,
117                block_device_on_hazards: HashMap::new()
118            }
119        );
120    }
121
122    #[test]
123    fn only_local_policy() {
124        let local_hazards = Hazards::new().insert(Hazard::Explosion);
125
126        let policy = Policy::only_local_policy(1, local_hazards.clone())
127            .block_device_on_hazards(2, local_hazards.clone());
128
129        check_device_policies(&policy, Hazards::new(), &local_hazards);
130    }
131
132    #[test]
133    fn complete_policy() {
134        let (global_hazards, policy) = create_policy();
135
136        let local_hazards = Hazards::new().insert(Hazard::Explosion);
137
138        let policy = policy
139            .block_device_on_hazards(1, local_hazards.clone())
140            .block_device_on_hazards(2, local_hazards.clone());
141
142        check_device_policies(&policy, global_hazards, &local_hazards);
143    }
144}