Skip to main content

pfx_scene/types/
tunable.rs

1use std::fmt;
2
3use serde::de::value::SeqAccessDeserializer;
4use serde::de::{self, Deserializer, MapAccess, SeqAccess, Visitor};
5use serde::{Deserialize, Serialize};
6
7use super::either::invalid;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum TunableKind {
12    Float,
13    Int,
14    Bool,
15    Vector,
16}
17
18impl TunableKind {
19    pub fn name(self) -> &'static str {
20        match self {
21            Self::Float => "float",
22            Self::Int => "int",
23            Self::Bool => "bool",
24            Self::Vector => "vector",
25        }
26    }
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
30#[serde(untagged)]
31pub enum TunableValue {
32    Bool(bool),
33    Int(i64),
34    Float(f32),
35    Vector([f32; 3]),
36}
37
38impl TunableValue {
39    pub fn kind(self) -> TunableKind {
40        match self {
41            Self::Bool(_) => TunableKind::Bool,
42            Self::Int(_) => TunableKind::Int,
43            Self::Float(_) => TunableKind::Float,
44            Self::Vector(_) => TunableKind::Vector,
45        }
46    }
47
48    pub fn finite(self) -> bool {
49        match self {
50            Self::Bool(_) | Self::Int(_) => true,
51            Self::Float(value) => value.is_finite(),
52            Self::Vector(axes) => axes.iter().all(|value| value.is_finite()),
53        }
54    }
55}
56
57impl fmt::Display for TunableValue {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self {
60            Self::Bool(value) => write!(f, "{value}"),
61            Self::Int(value) => write!(f, "{value}"),
62            Self::Float(value) => write!(f, "{value:?}"),
63            Self::Vector([x, y, z]) => write!(f, "[{x:?}, {y:?}, {z:?}]"),
64        }
65    }
66}
67
68const EXPECTED: &str = "true or false, a number or [x, y, z]";
69
70impl<'de> Deserialize<'de> for TunableValue {
71    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
72        struct Pick;
73
74        impl<'de> Visitor<'de> for Pick {
75            type Value = TunableValue;
76
77            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78                f.write_str(EXPECTED)
79            }
80
81            fn visit_bool<E: de::Error>(self, value: bool) -> Result<TunableValue, E> {
82                Ok(TunableValue::Bool(value))
83            }
84
85            fn visit_i64<E: de::Error>(self, value: i64) -> Result<TunableValue, E> {
86                Ok(TunableValue::Int(value))
87            }
88
89            fn visit_u64<E: de::Error>(self, value: u64) -> Result<TunableValue, E> {
90                i64::try_from(value)
91                    .map(TunableValue::Int)
92                    .map_err(|_| invalid(de::Unexpected::Unsigned(value), EXPECTED))
93            }
94
95            fn visit_f64<E: de::Error>(self, value: f64) -> Result<TunableValue, E> {
96                Ok(TunableValue::Float(value as f32))
97            }
98
99            fn visit_seq<A: SeqAccess<'de>>(self, seq: A) -> Result<TunableValue, A::Error> {
100                <[f32; 3]>::deserialize(SeqAccessDeserializer::new(seq)).map(TunableValue::Vector)
101            }
102
103            fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<TunableValue, A::Error> {
104                let _ = map;
105                Err(invalid(de::Unexpected::Map, EXPECTED))
106            }
107        }
108
109        deserializer.deserialize_any(Pick)
110    }
111}
112
113#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
114#[serde(deny_unknown_fields)]
115pub struct Tunable {
116    #[serde(rename = "type")]
117    pub kind: TunableKind,
118    pub default: TunableValue,
119    #[serde(default, skip_serializing_if = "Option::is_none")]
120    pub min: Option<TunableValue>,
121    #[serde(default, skip_serializing_if = "Option::is_none")]
122    pub max: Option<TunableValue>,
123    #[serde(default, skip_serializing_if = "Option::is_none")]
124    pub group: Option<String>,
125}
126
127impl Tunable {
128    pub(crate) fn settle(&mut self) {
129        if self.kind != TunableKind::Float {
130            return;
131        }
132        for value in [&mut self.default]
133            .into_iter()
134            .chain(self.min.as_mut())
135            .chain(self.max.as_mut())
136        {
137            if let TunableValue::Int(whole) = *value {
138                *value = TunableValue::Float(whole as f32);
139            }
140        }
141    }
142}