cameleon_genapi/
converter.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use super::{
6    elem_type::{DisplayNotation, FloatRepresentation, NamedValue, Slope},
7    formula::{Expr, Formula},
8    interface::{IFloat, INode, IncrementMode},
9    node_base::{NodeAttributeBase, NodeBase, NodeElementBase},
10    store::{CacheStore, NodeId, NodeStore, ValueStore},
11    utils, Device, GenApiError, GenApiResult, ValueCtxt,
12};
13
14#[derive(Debug, Clone)]
15pub struct ConverterNode {
16    pub(crate) attr_base: NodeAttributeBase,
17    pub(crate) elem_base: NodeElementBase,
18
19    pub(crate) streamable: bool,
20    pub(crate) p_variables: Vec<NamedValue<NodeId>>,
21    pub(crate) constants: Vec<NamedValue<f64>>,
22    pub(crate) expressions: Vec<NamedValue<Expr>>,
23    pub(crate) formula_to: Formula,
24    pub(crate) formula_from: Formula,
25    pub(crate) p_value: NodeId,
26    pub(crate) unit: Option<String>,
27    pub(crate) representation: FloatRepresentation,
28    pub(crate) display_notation: DisplayNotation,
29    pub(crate) display_precision: i64,
30    pub(crate) slope: Slope,
31    pub(crate) is_linear: bool,
32}
33
34impl ConverterNode {
35    #[must_use]
36    pub fn p_variables(&self) -> &[NamedValue<NodeId>] {
37        &self.p_variables
38    }
39
40    #[must_use]
41    pub fn constants(&self) -> &[NamedValue<f64>] {
42        &self.constants
43    }
44
45    #[must_use]
46    pub fn expressions(&self) -> &[NamedValue<Expr>] {
47        &self.expressions
48    }
49
50    #[must_use]
51    pub fn formula_to(&self) -> &Formula {
52        &self.formula_to
53    }
54
55    #[must_use]
56    pub fn formula_from(&self) -> &Formula {
57        &self.formula_from
58    }
59
60    #[must_use]
61    pub fn p_value(&self) -> NodeId {
62        self.p_value
63    }
64
65    #[must_use]
66    pub fn unit_elem(&self) -> Option<&str> {
67        self.unit.as_deref()
68    }
69
70    #[must_use]
71    pub fn representation_elem(&self) -> FloatRepresentation {
72        self.representation
73    }
74
75    #[must_use]
76    pub fn display_notation_elem(&self) -> DisplayNotation {
77        self.display_notation
78    }
79
80    #[must_use]
81    pub fn display_precision_elem(&self) -> i64 {
82        self.display_precision
83    }
84
85    #[must_use]
86    pub fn slope(&self) -> Slope {
87        self.slope
88    }
89
90    #[must_use]
91    pub fn is_linear(&self) -> bool {
92        self.is_linear
93    }
94}
95
96impl INode for ConverterNode {
97    fn node_base(&self) -> NodeBase {
98        NodeBase::new(&self.attr_base, &self.elem_base)
99    }
100
101    fn streamable(&self) -> bool {
102        self.streamable
103    }
104}
105
106impl IFloat for ConverterNode {
107    #[tracing::instrument(skip(self, device, store, cx),
108                          level = "trace",
109                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
110    fn value<T: ValueStore, U: CacheStore>(
111        &self,
112        device: &mut impl Device,
113        store: &impl NodeStore,
114        cx: &mut ValueCtxt<T, U>,
115    ) -> GenApiResult<f64> {
116        let mut collector =
117            utils::FormulaEnvCollector::new(&self.p_variables, &self.constants, &self.expressions);
118        collector.insert("TO", self.p_value(), device, store, cx)?;
119        let var_env = collector.collect(device, store, cx)?;
120
121        let eval_result = self.formula_from.eval(&var_env)?;
122        Ok(eval_result.as_float())
123    }
124
125    #[tracing::instrument(skip(self, device, store, cx),
126                          level = "trace",
127                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
128    fn set_value<T: ValueStore, U: CacheStore>(
129        &self,
130        value: f64,
131        device: &mut impl Device,
132        store: &impl NodeStore,
133        cx: &mut ValueCtxt<T, U>,
134    ) -> GenApiResult<()> {
135        cx.invalidate_cache_by(self.node_base().id());
136
137        let mut collector =
138            utils::FormulaEnvCollector::new(&self.p_variables, &self.constants, &self.expressions);
139        collector.insert_imm("FROM", value);
140        let var_env = collector.collect(device, store, cx)?;
141
142        let eval_result = self.formula_to.eval(&var_env)?;
143        utils::set_eval_result(self.p_value, eval_result, device, store, cx)?;
144        Ok(())
145    }
146
147    fn min<T: ValueStore, U: CacheStore>(
148        &self,
149        _: &mut impl Device,
150        _: &impl NodeStore,
151        _: &mut ValueCtxt<T, U>,
152    ) -> GenApiResult<f64> {
153        Ok(f64::MIN)
154    }
155
156    fn max<T: ValueStore, U: CacheStore>(
157        &self,
158        _: &mut impl Device,
159        _: &impl NodeStore,
160        _: &mut ValueCtxt<T, U>,
161    ) -> GenApiResult<f64> {
162        Ok(f64::MAX)
163    }
164
165    fn inc_mode(&self, _: &impl NodeStore) -> Option<IncrementMode> {
166        None
167    }
168
169    fn inc<T: ValueStore, U: CacheStore>(
170        &self,
171        _: &mut impl Device,
172        _: &impl NodeStore,
173        _: &mut ValueCtxt<T, U>,
174    ) -> GenApiResult<Option<f64>> {
175        Ok(None)
176    }
177
178    fn representation(&self, _: &impl NodeStore) -> FloatRepresentation {
179        self.representation
180    }
181
182    fn unit(&self, _: &impl NodeStore) -> Option<&str> {
183        self.unit_elem()
184    }
185
186    fn display_notation(&self, _: &impl NodeStore) -> DisplayNotation {
187        self.display_notation
188    }
189
190    fn display_precision(&self, _: &impl NodeStore) -> i64 {
191        self.display_precision
192    }
193
194    #[tracing::instrument(skip(self, store),
195                          level = "trace",
196                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
197    fn set_min<T: ValueStore, U: CacheStore>(
198        &self,
199        _: f64,
200        _: &mut impl Device,
201        store: &impl NodeStore,
202        _: &mut ValueCtxt<T, U>,
203    ) -> GenApiResult<()> {
204        Err(GenApiError::not_writable())
205    }
206
207    #[tracing::instrument(skip(self, store),
208                          level = "trace",
209                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
210    fn set_max<T: ValueStore, U: CacheStore>(
211        &self,
212        _: f64,
213        _: &mut impl Device,
214        store: &impl NodeStore,
215        _: &mut ValueCtxt<T, U>,
216    ) -> GenApiResult<()> {
217        Err(GenApiError::not_writable())
218    }
219
220    #[tracing::instrument(skip(self, device, store, cx),
221                          level = "trace",
222                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
223    fn is_readable<T: ValueStore, U: CacheStore>(
224        &self,
225        device: &mut impl Device,
226        store: &impl NodeStore,
227        cx: &mut ValueCtxt<T, U>,
228    ) -> GenApiResult<bool> {
229        let collector =
230            utils::FormulaEnvCollector::new(&self.p_variables, &self.constants, &self.expressions);
231        Ok(self.elem_base.is_readable(device, store, cx)?
232            && utils::is_nid_readable(self.p_value, device, store, cx)?
233            && collector.is_readable(device, store, cx)?)
234    }
235
236    #[tracing::instrument(skip(self, device, store, cx),
237                          level = "trace",
238                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
239    fn is_writable<T: ValueStore, U: CacheStore>(
240        &self,
241        device: &mut impl Device,
242        store: &impl NodeStore,
243        cx: &mut ValueCtxt<T, U>,
244    ) -> GenApiResult<bool> {
245        let collector =
246            utils::FormulaEnvCollector::new(&self.p_variables, &self.constants, &self.expressions);
247        Ok(self.elem_base.is_writable(device, store, cx)?
248            && utils::is_nid_writable(self.p_value, device, store, cx)?
249            && collector.is_readable(device, store, cx)?) // Collector is needed to be readable to write a value.
250    }
251}