luminol_data/helpers/
parameter_type.rs

1// Copyright (C) 2024 Melody Madeline Lyons
2//
3// This file is part of Luminol.
4//
5// Luminol is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Luminol is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Luminol.  If not, see <http://www.gnu.org/licenses/>.
17//
18//     Additional permission under GNU GPL version 3 section 7
19//
20// If you modify this Program, or any covered work, by linking or combining
21// it with Steamworks API by Valve Corporation, containing parts covered by
22// terms of the Steamworks API by Valve Corporation, the licensors of this
23// Program grant you additional permission to convey the resulting work.
24
25use 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")] // TODO make this serde compatible
34#[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
51// FIXME this really should be try_from and try_into
52impl 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}