1use alox_48::Value;
26
27use crate::rgss_structs::{Color, Tone};
28use crate::shared::{AudioFile, MoveCommand, MoveRoute};
29
30#[derive(Debug, Clone, PartialEq, Default)]
31#[derive(serde::Deserialize, serde::Serialize)]
32#[derive(alox_48::Deserialize, alox_48::Serialize)]
33#[marshal(from = "alox_48::Value", into = "alox_48::Value")] #[allow(missing_docs)]
35pub enum ParameterType {
36 Integer(i32),
37 String(String),
38 Color(Color),
39 Tone(Tone),
40 AudioFile(AudioFile),
41 Float(f64),
42 MoveRoute(MoveRoute),
43 MoveCommand(MoveCommand),
44 Array(Vec<ParameterType>),
45 Bool(bool),
46
47 #[default]
48 None,
49}
50
51impl From<alox_48::Value> for ParameterType {
53 fn from(value: alox_48::Value) -> Self {
54 match value {
55 Value::Nil => Self::None,
56 Value::Integer(v) => Self::Integer(v),
57 Value::Float(v) => Self::Float(v),
58 Value::String(v) => Self::String(String::from_utf8(v.data).unwrap()),
59 Value::Array(v) => Self::Array(v.into_iter().map(|v| v.into()).collect()),
60 Value::Bool(v) => Self::Bool(v),
61 Value::Userdata(userdata) => match userdata.class.as_str() {
62 "Color" => Self::Color(Color::from(userdata)),
63 "Tone" => Self::Tone(Tone::from(userdata)),
64 _ => panic!("Unsupported userdata type: {:#?}", userdata),
65 },
66 Value::Object(alox_48::Object { ref class, .. }) => match class.as_str() {
67 "RPG::AudioFile" => Self::AudioFile(alox_48::from_value(&value).unwrap()),
68 "RPG::MoveRoute" => Self::MoveRoute(alox_48::from_value(&value).unwrap()),
69 "RPG::MoveCommand" => Self::MoveCommand(alox_48::from_value(&value).unwrap()),
70 _ => panic!("Unsupported object type: {:#?}", value),
71 },
72 Value::Instance(i) => (*i.value).into(),
73 _ => panic!("Unsupported value type: {:#?}", value),
74 }
75 }
76}
77
78impl From<ParameterType> for alox_48::Value {
79 fn from(value: ParameterType) -> Self {
80 match value {
81 ParameterType::None => Value::Nil,
82 ParameterType::Integer(v) => Value::Integer(v),
83 ParameterType::Float(v) => Value::Float(v),
84 ParameterType::String(v) => Value::String(v.into()),
85 ParameterType::Array(v) => Value::Array(v.into_iter().map(|v| v.into()).collect()),
86 ParameterType::Bool(v) => Value::Bool(v),
87 ParameterType::Color(v) => Value::Userdata(v.into()),
88 ParameterType::Tone(v) => Value::Userdata(v.into()),
89 ParameterType::AudioFile(v) => alox_48::to_value(v).unwrap(),
90 ParameterType::MoveRoute(v) => alox_48::to_value(v).unwrap(),
91 ParameterType::MoveCommand(v) => alox_48::to_value(v).unwrap(),
92 }
93 }
94}
95
96macro_rules! variant_impl {
97
98 ($($name:ident, $type:ty),*) => {
99
100 $(paste::paste! {
101 impl ParameterType {
102 #[doc = "Converts this parameter into a `" $name "` if it is not already, and returns the contained value."]
103 pub fn [<into_ $name:lower>](&mut self) -> &mut $type {
104 match self {
105 ParameterType::$name(ref mut v) => v,
106 _ => {
107 #[cfg(debug_assertions)]
108 eprintln!(concat!("Parameter was of wrong type, expected ", stringify!($name), " got {:#?} instead"), self);
109
110 *self = ParameterType::$name(Default::default());
111
112 match self {
113 ParameterType::$name(ref mut v) => v,
114 _ => unreachable!(),
115 }
116 }
117 }
118 }
119
120 #[doc = "Converts this parameter into a `" $name "` if it is not already, replacing it with the provided default."]
121 pub fn [<into_ $name:lower _with>](&mut self, default: $type) -> &mut $type {
122 match self {
123 ParameterType::$name(ref mut v) => v,
124 _ => {
125 #[cfg(debug_assertions)]
126 eprintln!(concat!("Parameter was of wrong type, expected ", stringify!($name), " got {:#?} instead"), self);
127
128 *self = ParameterType::$name(default);
129
130 match self {
131 ParameterType::$name(ref mut v) => v,
132 _ => unreachable!(),
133 }
134 }
135 }
136 }
137
138 #[doc = "Gets this parameter as a reference to `" $name "` and returns None if the parameter was not a `" $name "`."]
139 pub fn [<as_ $name:lower>](&self) -> Option<&$type> {
140 match self {
141 ParameterType::$name(ref v) => Some(v),
142 _ => None
143 }
144 }
145
146 #[doc = "Gets this parameter as a mutable reference to `" $name "` and returns None if the parameter was not a `" $name "`."]
147 pub fn [<as_ $name:lower _mut>](&mut self) -> Option<&mut $type> {
148 match self {
149 ParameterType::$name(ref mut v) => Some(v),
150 _ => None
151 }
152 }
153
154 pub fn [<is_ $name:lower>](&self) -> bool {
155 matches!(self, ParameterType::$name(_))
156 }
157
158 pub fn [<new_ $name:lower>](v: $type) -> Self {
159 ParameterType::$name(v)
160 }
161 }
162
163 impl From<$type> for ParameterType {
164 fn from(v: $type) -> Self {
165 ParameterType::$name(v)
166 }
167 }
168
169 impl TryFrom<ParameterType> for $type {
170 type Error = ParameterType;
171
172 fn try_from(v: ParameterType) -> Result<Self, Self::Error> {
173 match v {
174 ParameterType::$name(v) => Ok(v),
175 v => Err(v)
176 }
177 }
178 }
179 })*
180 };
181}
182
183variant_impl! {
184 Integer, i32,
185 String, String,
186 Color, Color,
187 Tone, Tone,
188 AudioFile, AudioFile,
189 Float, f64,
190 MoveRoute, MoveRoute,
191 MoveCommand, MoveCommand,
192 Array, Vec<ParameterType>,
193 Bool, bool
194}
195
196impl ParameterType {
197 pub fn truthy(&self) -> bool {
198 !self.falsey()
199 }
200
201 pub fn falsey(&self) -> bool {
202 matches!(self, Self::None | Self::Bool(false) | Self::Integer(0))
203 }
204
205 pub fn is_none(&self) -> bool {
206 matches!(self, Self::None)
207 }
208
209 pub fn new_none() -> Self {
210 Self::None
211 }
212}
213
214impl From<()> for ParameterType {
215 fn from(_: ()) -> Self {
216 Self::None
217 }
218}
219
220impl From<&str> for ParameterType {
221 fn from(value: &str) -> Self {
222 Self::String(value.to_string())
223 }
224}