1use crate::export::{Export, Result};
2use crate::path::Path;
3use crate::sensor_id::SensorId;
4use std::any::Any;
5use std::collections::HashMap;
6use std::rc::Rc;
7use std::str::FromStr;
8
9pub type LocalSensors = HashMap<SensorId, Rc<Box<dyn Any>>>;
11
12pub type NbrSensors = HashMap<SensorId, HashMap<i32, Rc<Box<dyn Any>>>>;
14
15pub type Exports = HashMap<i32, Export>;
17
18#[derive(Debug, Clone)]
28pub struct Context {
29 self_id: i32,
30 local_sensor: LocalSensors,
31 nbr_sensor: NbrSensors,
32 exports: Exports,
33}
34
35impl Context {
36 pub fn new(
52 self_id: i32,
53 local_sensor: LocalSensors,
54 nbr_sensor: NbrSensors,
55 exports: Exports,
56 ) -> Self {
57 Self {
58 self_id,
59 local_sensor,
60 nbr_sensor,
61 exports,
62 }
63 }
64
65 pub fn self_id(&self) -> &i32 {
66 &self.self_id
67 }
68
69 pub fn exports(&self) -> &Exports {
70 &self.exports
71 }
72
73 pub fn put_export(&mut self, id: i32, data: Export) {
80 self.exports.insert(id, data);
81 }
82
83 pub fn read_export_value<A: 'static + FromStr + Clone>(
98 &self,
99 id: &i32,
100 path: &Path,
101 ) -> Result<A> {
102 self.exports
103 .get(id)
104 .ok_or("Export not found".into())
105 .and_then(|export| export.get(path))
106 }
107
108 pub fn local_sensors(&self) -> &LocalSensors {
109 &self.local_sensor
110 }
111
112 pub fn local_sense<A: 'static>(&self, local_sensor_id: &SensorId) -> Option<&A> {
125 self.local_sensor
126 .get(local_sensor_id)
127 .and_then(|value| value.downcast_ref::<A>())
128 }
129
130 pub fn nbr_sensors(&self) -> &NbrSensors {
131 &self.nbr_sensor
132 }
133
134 pub fn nbr_sense<A: 'static>(&self, sensor_id: &SensorId, nbr_id: &i32) -> Option<&A> {
149 self.nbr_sensor
150 .get(sensor_id)
151 .and_then(|value| value.get(nbr_id))
152 .and_then(|value| value.downcast_ref::<A>())
153 }
154}
155
156#[cfg(test)]
157mod test {
158 use super::*;
159 use crate::path::Path;
160 use crate::sensor_id::{sensor, SensorId};
161 use crate::slot::Slot::{Branch, Nbr, Rep};
162 use crate::{export, path};
163 use std::any::Any;
164 use std::collections::HashMap;
165 use std::rc::Rc;
166
167 fn context_builder() -> Context {
168 let local_sensor = HashMap::from([(sensor("test"), Rc::new(Box::new(10) as Box<dyn Any>))]);
169 let nbr_sensor = HashMap::from([(
170 sensor("test"),
171 HashMap::from([(0, Rc::new(Box::new(10) as Box<dyn Any>))]),
172 )]);
173 let export = HashMap::from([(0, export!((path!(Rep(0), Nbr(0)), 10)))]);
174 Context::new(7, local_sensor, nbr_sensor, export)
175 }
176
177 #[test]
178 fn assert_on_fields() {
179 let context = context_builder();
180 assert_eq!(context.self_id, 7);
181 assert_eq!(context.exports.len(), 1);
182 assert_eq!(context.local_sensor.len(), 1);
183 assert_eq!(context.nbr_sensor.len(), 1);
184 }
185
186 #[test]
187 fn test_put_export() {
188 let mut context = context_builder();
189 assert_eq!(context.exports.len(), 1);
190 let add_export = export!((path!(Branch(0), Nbr(0)), 5));
191 context.put_export(1, add_export);
192 assert_eq!(context.exports.len(), 2)
193 }
194
195 #[test]
196 fn test_read_export_value() {
197 let context = context_builder();
198 assert_eq!(
199 context
200 .read_export_value::<i32>(&0, &path!(Rep(0), Nbr(0)))
201 .unwrap(),
202 10
203 );
204 assert!(context.read_export_value::<i32>(&1, &Path::new()).is_err());
205 assert!(context.read_export_value::<i32>(&0, &Path::new()).is_err());
206 }
207
208 #[test]
209 fn test_local_sense() {
210 let context = context_builder();
211 assert_eq!(
212 context
213 .local_sense::<i32>(&SensorId::new("test".to_string()))
214 .unwrap(),
215 &10
216 );
217 }
218
219 #[test]
220 fn test_nbr_sense() {
221 let context = context_builder();
222 assert_eq!(
223 context
224 .nbr_sense::<i32>(&SensorId::new("test".to_string()), &0)
225 .unwrap(),
226 &10
227 );
228 }
229}