cameleon_genapi/
ivalue.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 ambassador::delegatable_trait;
6
7use super::{
8    elem_type::{ImmOrPNode, PIndex, PValue, ValueKind},
9    interface::{IEnumeration, IFloat, IInteger, IString},
10    store::{CacheStore, FloatId, IntegerId, NodeId, NodeStore, StringId, ValueStore},
11    Device, GenApiError, GenApiResult, ValueCtxt,
12};
13
14#[delegatable_trait]
15pub(super) trait IValue<T> {
16    fn value<U: ValueStore, S: CacheStore>(
17        &self,
18        device: &mut impl Device,
19        store: &impl NodeStore,
20        cx: &mut ValueCtxt<U, S>,
21    ) -> GenApiResult<T>;
22
23    fn set_value<U: ValueStore, S: CacheStore>(
24        &self,
25        value: T,
26        device: &mut impl Device,
27        store: &impl NodeStore,
28        cx: &mut ValueCtxt<U, S>,
29    ) -> GenApiResult<()>;
30
31    fn is_readable<U: ValueStore, S: CacheStore>(
32        &self,
33        device: &mut impl Device,
34        store: &impl NodeStore,
35        cx: &mut ValueCtxt<U, S>,
36    ) -> GenApiResult<bool>;
37
38    fn is_writable<U: ValueStore, S: CacheStore>(
39        &self,
40        device: &mut impl Device,
41        store: &impl NodeStore,
42        cx: &mut ValueCtxt<U, S>,
43    ) -> GenApiResult<bool>;
44}
45
46macro_rules! impl_ivalue_for_imm {
47    ($imm_ty:ty, $result_ty:ty) => {
48        impl IValue<$result_ty> for $imm_ty {
49            fn value<U: ValueStore, S: CacheStore>(
50                &self,
51                _: &mut impl Device,
52                _: &impl NodeStore,
53                _: &mut ValueCtxt<U, S>,
54            ) -> GenApiResult<$result_ty> {
55                Ok(*self as $result_ty)
56            }
57
58            fn set_value<U, S>(
59                &self,
60                _: $result_ty,
61                _: &mut impl Device,
62                _: &impl NodeStore,
63                _: &mut ValueCtxt<U, S>,
64            ) -> GenApiResult<()> {
65                Err(GenApiError::not_writable())
66            }
67
68            fn is_readable<U: ValueStore, S: CacheStore>(
69                &self,
70                _: &mut impl Device,
71                _: &impl NodeStore,
72                _: &mut ValueCtxt<U, S>,
73            ) -> GenApiResult<bool> {
74                Ok(true)
75            }
76
77            fn is_writable<U: ValueStore, S: CacheStore>(
78                &self,
79                _: &mut impl Device,
80                _: &impl NodeStore,
81                _: &mut ValueCtxt<U, S>,
82            ) -> GenApiResult<bool> {
83                Ok(false)
84            }
85        }
86    };
87}
88impl_ivalue_for_imm!(i64, i64);
89impl_ivalue_for_imm!(i64, f64);
90impl_ivalue_for_imm!(f64, i64);
91impl_ivalue_for_imm!(f64, f64);
92
93macro_rules! impl_ivalue_for_vid {
94    ($ty:ty, $vid:ty, $f:ident) => {
95        impl IValue<$ty> for $vid {
96            fn value<U: ValueStore, S: CacheStore>(
97                &self,
98                _: &mut impl Device,
99                _: &impl NodeStore,
100                cx: &mut ValueCtxt<U, S>,
101            ) -> GenApiResult<$ty> {
102                Ok(cx.value_store.$f(*self).unwrap() as $ty)
103            }
104
105            fn set_value<U: ValueStore, S: CacheStore>(
106                &self,
107                value: $ty,
108                _: &mut impl Device,
109                _: &impl NodeStore,
110                cx: &mut ValueCtxt<U, S>,
111            ) -> GenApiResult<()> {
112                cx.value_store_mut().update(*self, value);
113                Ok(())
114            }
115
116            fn is_readable<U: ValueStore, S: CacheStore>(
117                &self,
118                _: &mut impl Device,
119                _: &impl NodeStore,
120                _: &mut ValueCtxt<U, S>,
121            ) -> GenApiResult<bool> {
122                Ok(true)
123            }
124
125            fn is_writable<U: ValueStore, S: CacheStore>(
126                &self,
127                _: &mut impl Device,
128                _: &impl NodeStore,
129                _: &mut ValueCtxt<U, S>,
130            ) -> GenApiResult<bool> {
131                Ok(true)
132            }
133        }
134    };
135}
136impl_ivalue_for_vid!(i64, IntegerId, integer_value);
137impl_ivalue_for_vid!(f64, IntegerId, integer_value);
138impl_ivalue_for_vid!(f64, FloatId, float_value);
139impl_ivalue_for_vid!(i64, FloatId, float_value);
140impl IValue<String> for StringId {
141    fn value<U: ValueStore, S: CacheStore>(
142        &self,
143        _: &mut impl Device,
144        _: &impl NodeStore,
145        cx: &mut ValueCtxt<U, S>,
146    ) -> GenApiResult<String> {
147        Ok(cx.value_store.str_value(*self).unwrap().into())
148    }
149
150    fn set_value<U: ValueStore, S: CacheStore>(
151        &self,
152        value: String,
153        _: &mut impl Device,
154        _: &impl NodeStore,
155        cx: &mut ValueCtxt<U, S>,
156    ) -> GenApiResult<()> {
157        cx.value_store_mut().update(*self, value);
158        Ok(())
159    }
160
161    fn is_readable<U: ValueStore, S: CacheStore>(
162        &self,
163        _: &mut impl Device,
164        _: &impl NodeStore,
165        _: &mut ValueCtxt<U, S>,
166    ) -> GenApiResult<bool> {
167        Ok(true)
168    }
169
170    fn is_writable<U: ValueStore, S: CacheStore>(
171        &self,
172        _: &mut impl Device,
173        _: &impl NodeStore,
174        _: &mut ValueCtxt<U, S>,
175    ) -> GenApiResult<bool> {
176        Ok(true)
177    }
178}
179
180impl IValue<i64> for NodeId {
181    fn value<U: ValueStore, S: CacheStore>(
182        &self,
183        device: &mut impl Device,
184        store: &impl NodeStore,
185        cx: &mut ValueCtxt<U, S>,
186    ) -> GenApiResult<i64> {
187        if let Some(i) = self.as_iinteger_kind(store) {
188            i.value(device, store, cx)
189        } else if let Some(f) = self.as_ifloat_kind(store) {
190            f.value(device, store, cx).map(|f| f as i64)
191        } else if let Some(e) = self.as_ienumeration_kind(store) {
192            e.current_value(device, store, cx)
193        } else {
194            Err(GenApiError::invalid_node(
195                format!("Node {:?} is not an integer, float, or enumeration", self).into(),
196            ))
197        }
198    }
199
200    fn set_value<U: ValueStore, S: CacheStore>(
201        &self,
202        value: i64,
203        device: &mut impl Device,
204        store: &impl NodeStore,
205        cx: &mut ValueCtxt<U, S>,
206    ) -> GenApiResult<()> {
207        if let Some(i) = self.as_iinteger_kind(store) {
208            i.set_value(value, device, store, cx)
209        } else if let Some(f) = self.as_ifloat_kind(store) {
210            f.set_value(value as f64, device, store, cx)
211        } else if let Some(e) = self.as_ienumeration_kind(store) {
212            e.set_entry_by_value(value, device, store, cx)
213        } else {
214            Err(GenApiError::not_writable())
215        }
216    }
217
218    fn is_readable<U: ValueStore, S: CacheStore>(
219        &self,
220        device: &mut impl Device,
221        store: &impl NodeStore,
222        cx: &mut ValueCtxt<U, S>,
223    ) -> GenApiResult<bool> {
224        if let Some(i) = self.as_iinteger_kind(store) {
225            i.is_readable(device, store, cx)
226        } else if let Some(f) = self.as_ifloat_kind(store) {
227            f.is_readable(device, store, cx)
228        } else if let Some(e) = self.as_ienumeration_kind(store) {
229            e.is_readable(device, store, cx)
230        } else {
231            Ok(false)
232        }
233    }
234
235    fn is_writable<U: ValueStore, S: CacheStore>(
236        &self,
237        device: &mut impl Device,
238        store: &impl NodeStore,
239        cx: &mut ValueCtxt<U, S>,
240    ) -> GenApiResult<bool> {
241        if let Some(i) = self.as_iinteger_kind(store) {
242            i.is_writable(device, store, cx)
243        } else if let Some(f) = self.as_ifloat_kind(store) {
244            f.is_writable(device, store, cx)
245        } else {
246            Ok(false)
247        }
248    }
249}
250
251impl IValue<f64> for NodeId {
252    fn value<U: ValueStore, S: CacheStore>(
253        &self,
254        device: &mut impl Device,
255        store: &impl NodeStore,
256        cx: &mut ValueCtxt<U, S>,
257    ) -> GenApiResult<f64> {
258        if let Some(i) = self.as_iinteger_kind(store) {
259            i.value(device, store, cx).map(|i| i as f64)
260        } else if let Some(f) = self.as_ifloat_kind(store) {
261            f.value(device, store, cx)
262        } else if let Some(e) = self.as_ienumeration_kind(store) {
263            e.current_value(device, store, cx).map(|i| i as f64)
264        } else {
265            Err(GenApiError::invalid_node(
266                format!("Node {:?} is not an integer, float, or enumeration", self).into(),
267            ))
268        }
269    }
270
271    fn set_value<U: ValueStore, S: CacheStore>(
272        &self,
273        value: f64,
274        device: &mut impl Device,
275        store: &impl NodeStore,
276        cx: &mut ValueCtxt<U, S>,
277    ) -> GenApiResult<()> {
278        if let Some(i) = self.as_iinteger_kind(store) {
279            i.set_value(value as i64, device, store, cx)
280        } else if let Some(f) = self.as_ifloat_kind(store) {
281            f.set_value(value, device, store, cx)
282        } else if let Some(e) = self.as_ienumeration_kind(store) {
283            e.set_entry_by_value(value as i64, device, store, cx)
284        } else {
285            Err(GenApiError::not_writable())
286        }
287    }
288
289    fn is_readable<U: ValueStore, S: CacheStore>(
290        &self,
291        device: &mut impl Device,
292        store: &impl NodeStore,
293        cx: &mut ValueCtxt<U, S>,
294    ) -> GenApiResult<bool> {
295        if let Some(i) = self.as_iinteger_kind(store) {
296            i.is_readable(device, store, cx)
297        } else if let Some(f) = self.as_ifloat_kind(store) {
298            f.is_readable(device, store, cx)
299        } else if let Some(e) = self.as_ienumeration_kind(store) {
300            e.is_readable(device, store, cx)
301        } else {
302            Ok(false)
303        }
304    }
305
306    fn is_writable<U: ValueStore, S: CacheStore>(
307        &self,
308        device: &mut impl Device,
309        store: &impl NodeStore,
310        cx: &mut ValueCtxt<U, S>,
311    ) -> GenApiResult<bool> {
312        if let Some(i) = self.as_iinteger_kind(store) {
313            i.is_writable(device, store, cx)
314        } else if let Some(f) = self.as_ifloat_kind(store) {
315            f.is_writable(device, store, cx)
316        } else {
317            Ok(false)
318        }
319    }
320}
321
322impl IValue<String> for NodeId {
323    fn value<U: ValueStore, S: CacheStore>(
324        &self,
325        device: &mut impl Device,
326        store: &impl NodeStore,
327        cx: &mut ValueCtxt<U, S>,
328    ) -> GenApiResult<String> {
329        self.expect_istring_kind(store)?.value(device, store, cx)
330    }
331
332    fn set_value<U: ValueStore, S: CacheStore>(
333        &self,
334        value: String,
335        device: &mut impl Device,
336        store: &impl NodeStore,
337        cx: &mut ValueCtxt<U, S>,
338    ) -> GenApiResult<()> {
339        self.expect_istring_kind(store)?
340            .set_value(value, device, store, cx)
341    }
342
343    fn is_readable<U: ValueStore, S: CacheStore>(
344        &self,
345        device: &mut impl Device,
346        store: &impl NodeStore,
347        cx: &mut ValueCtxt<U, S>,
348    ) -> GenApiResult<bool> {
349        self.expect_istring_kind(store)?
350            .is_readable(device, store, cx)
351    }
352
353    fn is_writable<U: ValueStore, S: CacheStore>(
354        &self,
355        device: &mut impl Device,
356        store: &impl NodeStore,
357        cx: &mut ValueCtxt<U, S>,
358    ) -> GenApiResult<bool> {
359        self.expect_istring_kind(store)?
360            .is_writable(device, store, cx)
361    }
362}
363
364impl<T, Ty> IValue<T> for ImmOrPNode<Ty>
365where
366    Ty: IValue<T>,
367    NodeId: IValue<T>,
368{
369    fn value<U: ValueStore, S: CacheStore>(
370        &self,
371        device: &mut impl Device,
372        store: &impl NodeStore,
373        cx: &mut ValueCtxt<U, S>,
374    ) -> GenApiResult<T> {
375        match self {
376            ImmOrPNode::Imm(i) => i.value(device, store, cx),
377            ImmOrPNode::PNode(nid) => nid.value(device, store, cx),
378        }
379    }
380
381    fn set_value<U: ValueStore, S: CacheStore>(
382        &self,
383        value: T,
384        device: &mut impl Device,
385        store: &impl NodeStore,
386        cx: &mut ValueCtxt<U, S>,
387    ) -> GenApiResult<()> {
388        match self {
389            ImmOrPNode::Imm(i) => i.set_value(value, device, store, cx),
390            ImmOrPNode::PNode(nid) => nid.set_value(value, device, store, cx),
391        }
392    }
393
394    fn is_readable<U: ValueStore, S: CacheStore>(
395        &self,
396        device: &mut impl Device,
397        store: &impl NodeStore,
398        cx: &mut ValueCtxt<U, S>,
399    ) -> GenApiResult<bool> {
400        match self {
401            ImmOrPNode::Imm(i) => i.is_readable(device, store, cx),
402            ImmOrPNode::PNode(nid) => nid.is_readable(device, store, cx),
403        }
404    }
405
406    fn is_writable<U: ValueStore, S: CacheStore>(
407        &self,
408        device: &mut impl Device,
409        store: &impl NodeStore,
410        cx: &mut ValueCtxt<U, S>,
411    ) -> GenApiResult<bool> {
412        match self {
413            ImmOrPNode::Imm(i) => i.is_writable(device, store, cx),
414            ImmOrPNode::PNode(nid) => nid.is_writable(device, store, cx),
415        }
416    }
417}
418
419impl<T, Ty> IValue<T> for ValueKind<Ty>
420where
421    Ty: IValue<T>,
422    PValue<Ty>: IValue<T>,
423    PIndex<Ty>: IValue<T>,
424{
425    fn value<U: ValueStore, S: CacheStore>(
426        &self,
427        device: &mut impl Device,
428        store: &impl NodeStore,
429        cx: &mut ValueCtxt<U, S>,
430    ) -> GenApiResult<T> {
431        match self {
432            ValueKind::Value(i) => i.value(device, store, cx),
433            ValueKind::PValue(p_value) => p_value.value(device, store, cx),
434            ValueKind::PIndex(p_index) => p_index.value(device, store, cx),
435        }
436    }
437
438    fn set_value<U: ValueStore, S: CacheStore>(
439        &self,
440        value: T,
441        device: &mut impl Device,
442        store: &impl NodeStore,
443        cx: &mut ValueCtxt<U, S>,
444    ) -> GenApiResult<()> {
445        match self {
446            ValueKind::Value(i) => i.set_value(value, device, store, cx),
447            ValueKind::PValue(p_value) => p_value.set_value(value, device, store, cx),
448            ValueKind::PIndex(p_index) => p_index.set_value(value, device, store, cx),
449        }
450    }
451
452    fn is_readable<U: ValueStore, S: CacheStore>(
453        &self,
454        device: &mut impl Device,
455        store: &impl NodeStore,
456        cx: &mut ValueCtxt<U, S>,
457    ) -> GenApiResult<bool> {
458        match self {
459            ValueKind::Value(i) => i.is_readable(device, store, cx),
460            ValueKind::PValue(p_value) => p_value.is_readable(device, store, cx),
461            ValueKind::PIndex(p_index) => p_index.is_readable(device, store, cx),
462        }
463    }
464
465    fn is_writable<U: ValueStore, S: CacheStore>(
466        &self,
467        device: &mut impl Device,
468        store: &impl NodeStore,
469        cx: &mut ValueCtxt<U, S>,
470    ) -> GenApiResult<bool> {
471        match self {
472            ValueKind::Value(i) => i.is_writable(device, store, cx),
473            ValueKind::PValue(p_value) => p_value.is_writable(device, store, cx),
474            ValueKind::PIndex(p_index) => p_index.is_writable(device, store, cx),
475        }
476    }
477}
478
479impl<T, Ty> IValue<T> for PValue<Ty>
480where
481    NodeId: IValue<T>,
482    T: Copy,
483{
484    fn value<U: ValueStore, S: CacheStore>(
485        &self,
486        device: &mut impl Device,
487        store: &impl NodeStore,
488        cx: &mut ValueCtxt<U, S>,
489    ) -> GenApiResult<T> {
490        self.p_value.value(device, store, cx)
491    }
492
493    fn set_value<U: ValueStore, S: CacheStore>(
494        &self,
495        value: T,
496        device: &mut impl Device,
497        store: &impl NodeStore,
498        cx: &mut ValueCtxt<U, S>,
499    ) -> GenApiResult<()> {
500        self.p_value.set_value(value, device, store, cx)?;
501        for nid in self.p_value_copies() {
502            nid.set_value(value, device, store, cx)?;
503        }
504        Ok(())
505    }
506
507    fn is_readable<U: ValueStore, S: CacheStore>(
508        &self,
509        device: &mut impl Device,
510        store: &impl NodeStore,
511        cx: &mut ValueCtxt<U, S>,
512    ) -> GenApiResult<bool> {
513        self.p_value.is_readable(device, store, cx)
514    }
515
516    fn is_writable<U: ValueStore, S: CacheStore>(
517        &self,
518        device: &mut impl Device,
519        store: &impl NodeStore,
520        cx: &mut ValueCtxt<U, S>,
521    ) -> GenApiResult<bool> {
522        let mut b = self.p_value.is_writable(device, store, cx)?;
523        for nid in self.p_value_copies() {
524            b &= nid.is_writable(device, store, cx)?;
525        }
526        Ok(b)
527    }
528}
529
530impl<T, Ty> IValue<T> for PIndex<Ty>
531where
532    Ty: IValue<T>,
533    ImmOrPNode<Ty>: IValue<T>,
534{
535    fn value<U: ValueStore, S: CacheStore>(
536        &self,
537        device: &mut impl Device,
538        store: &impl NodeStore,
539        cx: &mut ValueCtxt<U, S>,
540    ) -> GenApiResult<T> {
541        let index = self.index(device, store, cx)?;
542        if let Some(value_indexed) = self.value_indexed.iter().find(|vi| vi.index == index) {
543            value_indexed.indexed.value(device, store, cx)
544        } else {
545            self.value_default.value(device, store, cx)
546        }
547    }
548
549    fn set_value<U: ValueStore, S: CacheStore>(
550        &self,
551        value: T,
552        device: &mut impl Device,
553        store: &impl NodeStore,
554        cx: &mut ValueCtxt<U, S>,
555    ) -> GenApiResult<()> {
556        let index = self.index(device, store, cx)?;
557        if let Some(value_indexed) = self.value_indexed.iter().find(|vi| vi.index == index) {
558            value_indexed.indexed.set_value(value, device, store, cx)
559        } else {
560            self.value_default.set_value(value, device, store, cx)
561        }
562    }
563
564    fn is_readable<U: ValueStore, S: CacheStore>(
565        &self,
566        device: &mut impl Device,
567        store: &impl NodeStore,
568        cx: &mut ValueCtxt<U, S>,
569    ) -> GenApiResult<bool> {
570        Ok(self
571            .p_index
572            .expect_iinteger_kind(store)?
573            .is_readable(device, store, cx)?
574            && {
575                let index = self.index(device, store, cx)?;
576                if let Some(value_indexed) = self.value_indexed.iter().find(|vi| vi.index == index)
577                {
578                    value_indexed.indexed.is_readable(device, store, cx)?
579                } else {
580                    self.value_default.is_readable(device, store, cx)?
581                }
582            })
583    }
584
585    fn is_writable<U: ValueStore, S: CacheStore>(
586        &self,
587        device: &mut impl Device,
588        store: &impl NodeStore,
589        cx: &mut ValueCtxt<U, S>,
590    ) -> GenApiResult<bool> {
591        Ok(self
592            .p_index
593            .expect_iinteger_kind(store)?
594            .is_readable(device, store, cx)?
595            && {
596                let index = self.index(device, store, cx)?;
597                if let Some(value_indexed) = self.value_indexed.iter().find(|vi| vi.index == index)
598                {
599                    value_indexed.indexed.is_writable(device, store, cx)?
600                } else {
601                    self.value_default.is_writable(device, store, cx)?
602                }
603            })
604    }
605}
606
607impl<T> PIndex<T> {
608    fn index<U: ValueStore, S: CacheStore>(
609        &self,
610        device: &mut impl Device,
611        store: &impl NodeStore,
612        cx: &mut ValueCtxt<U, S>,
613    ) -> GenApiResult<i64> {
614        self.p_index
615            .expect_iinteger_kind(store)?
616            .value(device, store, cx)
617    }
618}