pfx_scene/types/
tunable.rs1use 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}