epics_seq/
channel_store.rs1use std::sync::Mutex;
2
3use epics_base_rs::types::EpicsValue;
4
5#[derive(Debug, Clone)]
7pub struct ChannelValueSlot {
8 pub value: EpicsValue,
9 pub status: i16,
10 pub severity: i16,
11}
12
13impl Default for ChannelValueSlot {
14 fn default() -> Self {
15 Self {
16 value: EpicsValue::Double(0.0),
17 status: 0,
18 severity: 0,
19 }
20 }
21}
22
23pub struct ChannelStore {
28 slots: Vec<Mutex<ChannelValueSlot>>,
29}
30
31impl ChannelStore {
32 pub fn new(num_channels: usize) -> Self {
33 let slots = (0..num_channels)
34 .map(|_| Mutex::new(ChannelValueSlot::default()))
35 .collect();
36 Self { slots }
37 }
38
39 pub fn set(&self, ch_id: usize, value: EpicsValue) {
41 if let Some(slot) = self.slots.get(ch_id) {
42 let mut s = slot.lock().unwrap();
43 s.value = value;
44 }
45 }
46
47 pub fn set_full(&self, ch_id: usize, value: EpicsValue, status: i16, severity: i16) {
49 if let Some(slot) = self.slots.get(ch_id) {
50 let mut s = slot.lock().unwrap();
51 s.value = value;
52 s.status = status;
53 s.severity = severity;
54 }
55 }
56
57 pub fn get(&self, ch_id: usize) -> Option<EpicsValue> {
59 self.slots
60 .get(ch_id)
61 .map(|slot| slot.lock().unwrap().value.clone())
62 }
63
64 pub fn get_full(&self, ch_id: usize) -> Option<ChannelValueSlot> {
66 self.slots
67 .get(ch_id)
68 .map(|slot| slot.lock().unwrap().clone())
69 }
70
71 pub fn num_channels(&self) -> usize {
72 self.slots.len()
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_set_and_get() {
82 let store = ChannelStore::new(3);
83 store.set(0, EpicsValue::Double(42.0));
84 match store.get(0).unwrap() {
85 EpicsValue::Double(v) => assert!((v - 42.0).abs() < 1e-10),
86 _ => panic!("wrong type"),
87 }
88 }
89
90 #[test]
91 fn test_default_value() {
92 let store = ChannelStore::new(1);
93 match store.get(0).unwrap() {
94 EpicsValue::Double(v) => assert!((v - 0.0).abs() < 1e-10),
95 _ => panic!("wrong type"),
96 }
97 }
98
99 #[test]
100 fn test_set_full() {
101 let store = ChannelStore::new(2);
102 store.set_full(1, EpicsValue::Long(7), 1, 2);
103 let slot = store.get_full(1).unwrap();
104 assert_eq!(slot.status, 1);
105 assert_eq!(slot.severity, 2);
106 match slot.value {
107 EpicsValue::Long(v) => assert_eq!(v, 7),
108 _ => panic!("wrong type"),
109 }
110 }
111
112 #[test]
113 fn test_invalid_channel() {
114 let store = ChannelStore::new(1);
115 assert!(store.get(99).is_none());
116 store.set(99, EpicsValue::Double(1.0));
118 }
119
120 #[test]
121 fn test_concurrent_access() {
122 use std::sync::Arc;
123 use std::thread;
124
125 let store = Arc::new(ChannelStore::new(1));
126 let store2 = store.clone();
127
128 let writer = thread::spawn(move || {
129 for i in 0..100 {
130 store2.set(0, EpicsValue::Double(i as f64));
131 }
132 });
133
134 let reader = thread::spawn(move || {
135 for _ in 0..100 {
136 let _ = store.get(0);
137 }
138 });
139
140 writer.join().unwrap();
141 reader.join().unwrap();
142 }
143}