1use super::{
6 elem_type::ImmOrPNode,
7 interface::{IEnumeration, INode, ISelector},
8 ivalue::IValue,
9 node_base::{NodeAttributeBase, NodeBase, NodeElementBase},
10 store::{CacheStore, IntegerId, NodeId, NodeStore, ValueStore},
11 Device, GenApiError, GenApiResult, ValueCtxt,
12};
13
14#[derive(Debug, Clone)]
15pub struct EnumerationNode {
16 pub(crate) attr_base: NodeAttributeBase,
17 pub(crate) elem_base: NodeElementBase,
18
19 pub(crate) streamable: bool,
20 pub(crate) entries: Vec<NodeId>,
21 pub(crate) value: ImmOrPNode<IntegerId>,
22 pub(crate) p_selected: Vec<NodeId>,
23 pub(crate) polling_time: Option<u64>,
24}
25
26impl EnumerationNode {
27 #[must_use]
28 pub fn value_elem(&self) -> ImmOrPNode<IntegerId> {
29 self.value
30 }
31
32 #[must_use]
33 pub fn p_selected(&self) -> &[NodeId] {
34 &self.p_selected
35 }
36
37 #[must_use]
38 pub fn polling_time(&self) -> Option<u64> {
39 self.polling_time
40 }
41}
42
43impl INode for EnumerationNode {
44 fn node_base(&self) -> NodeBase {
45 NodeBase::new(&self.attr_base, &self.elem_base)
46 }
47
48 fn streamable(&self) -> bool {
49 self.streamable
50 }
51}
52
53impl IEnumeration for EnumerationNode {
54 #[tracing::instrument(skip(self, device, store, cx),
55 level = "trace",
56 fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
57 fn current_value<T: ValueStore, U: CacheStore>(
58 &self,
59 device: &mut impl Device,
60 store: &impl NodeStore,
61 cx: &mut ValueCtxt<T, U>,
62 ) -> GenApiResult<i64> {
63 self.value.value(device, store, cx)
64 }
65
66 #[tracing::instrument(skip(self, device, store, cx),
67 level = "trace",
68 fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
69 fn current_entry<T: ValueStore, U: CacheStore>(
70 &self,
71 device: &mut impl Device,
72 store: &impl NodeStore,
73 cx: &mut ValueCtxt<T, U>,
74 ) -> GenApiResult<NodeId> {
75 let value = self.value.value(device, store, cx)?;
76 for nid in self.entries(store) {
77 let ent = nid.expect_enum_entry(store).unwrap(); if ent.value() == value {
79 return Ok(*nid);
80 }
81 }
82
83 Err(GenApiError::invalid_node(
84 format!(
85 "no entry found corresponding to the current value of {}",
86 store.name_by_id(self.node_base().id()).unwrap()
87 )
88 .into(),
89 ))
90 }
91
92 fn entries(&self, _: &impl NodeStore) -> &[NodeId] {
93 &self.entries
94 }
95
96 #[tracing::instrument(skip(self, device, store, cx),
97 level = "trace",
98 fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
99 fn set_entry_by_symbolic<T: ValueStore, U: CacheStore>(
100 &self,
101 name: &str,
102 device: &mut impl Device,
103 store: &impl NodeStore,
104 cx: &mut ValueCtxt<T, U>,
105 ) -> GenApiResult<()> {
106 let value = self
107 .entries(store)
108 .iter()
109 .map(|nid| nid.expect_enum_entry(store).unwrap())
110 .find(|ent| ent.symbolic() == name)
111 .ok_or_else(|| {
112 GenApiError::invalid_data(
113 format! {"no `EenumEntryNode`: `{}` not found in `{}`",
114 name,
115 store.name_by_id(self.node_base().id()).unwrap()}
116 .into(),
117 )
118 })?
119 .value();
120
121 self.set_entry_by_value(value, device, store, cx)
122 }
123
124 fn set_entry_by_value<T: ValueStore, U: CacheStore>(
125 &self,
126 value: i64,
127 device: &mut impl Device,
128 store: &impl NodeStore,
129 cx: &mut ValueCtxt<T, U>,
130 ) -> GenApiResult<()> {
131 if !self
132 .entries(store)
133 .iter()
134 .map(|nid| nid.expect_enum_entry(store).unwrap())
135 .any(|ent| ent.value() == value)
136 {
137 return Err(GenApiError::invalid_data(
138 format!("not found entry with the value `{}`", value).into(),
139 ));
140 };
141 cx.invalidate_cache_by(self.node_base().id());
142 self.value.set_value(value, device, store, cx)
143 }
144
145 #[tracing::instrument(skip(self, device, store, cx),
146 level = "trace",
147 fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
148 fn is_readable<T: ValueStore, U: CacheStore>(
149 &self,
150 device: &mut impl Device,
151 store: &impl NodeStore,
152 cx: &mut ValueCtxt<T, U>,
153 ) -> GenApiResult<bool> {
154 Ok(self.elem_base.is_readable(device, store, cx)?
155 && IValue::<i64>::is_readable(&self.value, device, store, cx)?)
156 }
157
158 #[tracing::instrument(skip(self, device, store, cx),
159 level = "trace",
160 fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
161 fn is_writable<T: ValueStore, U: CacheStore>(
162 &self,
163 device: &mut impl Device,
164 store: &impl NodeStore,
165 cx: &mut ValueCtxt<T, U>,
166 ) -> GenApiResult<bool> {
167 Ok(self.elem_base.is_writable(device, store, cx)?
168 && IValue::<i64>::is_writable(&self.value, device, store, cx)?)
169 }
170}
171
172impl ISelector for EnumerationNode {
173 fn selecting_nodes(&self, _: &impl NodeStore) -> GenApiResult<&[NodeId]> {
174 Ok(self.p_selected())
175 }
176}
177
178#[derive(Debug, Clone)]
179pub struct EnumEntryNode {
180 pub(crate) attr_base: NodeAttributeBase,
181 pub(crate) elem_base: NodeElementBase,
182
183 pub(crate) value: i64,
184 pub(crate) numeric_value: Option<f64>,
185 pub(crate) symbolic: String,
186 pub(crate) is_self_clearing: bool,
187}
188
189impl EnumEntryNode {
190 #[must_use]
191 pub fn value(&self) -> i64 {
192 self.value
193 }
194
195 #[must_use]
196 #[allow(clippy::cast_precision_loss)]
197 pub fn numeric_value(&self) -> f64 {
198 self.numeric_value.unwrap_or(self.value as f64)
199 }
200
201 #[must_use]
202 pub fn symbolic(&self) -> &str {
203 &self.symbolic
204 }
205
206 #[must_use]
207 pub fn is_self_clearing(&self) -> bool {
208 self.is_self_clearing
209 }
210
211 pub fn is_locked<T: ValueStore, U: CacheStore>(
212 &self,
213 device: &mut impl Device,
214 store: &impl NodeStore,
215 cx: &mut ValueCtxt<T, U>,
216 ) -> GenApiResult<bool> {
217 self.elem_base.is_locked(device, store, cx)
218 }
219
220 pub fn is_implemented<T: ValueStore, U: CacheStore>(
221 &self,
222 device: &mut impl Device,
223 store: &impl NodeStore,
224 cx: &mut ValueCtxt<T, U>,
225 ) -> GenApiResult<bool> {
226 self.elem_base.is_implemented(device, store, cx)
227 }
228
229 pub fn is_available<T: ValueStore, U: CacheStore>(
230 &self,
231 device: &mut impl Device,
232 store: &impl NodeStore,
233 cx: &mut ValueCtxt<T, U>,
234 ) -> GenApiResult<bool> {
235 self.elem_base.is_available(device, store, cx)
236 }
237}
238
239impl INode for EnumEntryNode {
240 fn node_base(&self) -> NodeBase {
241 NodeBase::new(&self.attr_base, &self.elem_base)
242 }
243
244 fn streamable(&self) -> bool {
245 false
246 }
247}