rpgmxp_types/
event_command_parameter.rs

1use crate::AudioFile;
2use crate::Color;
3use crate::MoveCommand;
4use crate::MoveRoute;
5use crate::Tone;
6use ruby_marshal::DisplayByteString;
7use ruby_marshal::FromValue;
8use ruby_marshal::FromValueContext;
9use ruby_marshal::FromValueError;
10use ruby_marshal::IntoValue;
11use ruby_marshal::IntoValueError;
12use ruby_marshal::StringValue;
13use ruby_marshal::SymbolValue;
14use ruby_marshal::Value;
15use ruby_marshal::ValueArena;
16use ruby_marshal::ValueHandle;
17use ruby_marshal::ValueKind;
18
19#[derive(Debug)]
20pub enum EventCommandParameterFromValueError {
21    UnexpectedValueKind { kind: ValueKind },
22    EmptyArray,
23    UnexpectedArrayValueKind { kind: ValueKind },
24    UnexpectedUserDefinedName { name: Vec<u8> },
25}
26
27impl std::fmt::Display for EventCommandParameterFromValueError {
28    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
29        match self {
30            Self::UnexpectedValueKind { kind } => {
31                write!(
32                    f,
33                    "unexpected value kind for event command parameter: {kind:?}"
34                )
35            }
36            Self::EmptyArray => write!(f, "the event command parameter array is empty"),
37            Self::UnexpectedArrayValueKind { kind } => {
38                write!(
39                    f,
40                    "unexpected event command parameter array value kind: {kind:?}"
41                )
42            }
43            Self::UnexpectedUserDefinedName { name } => {
44                let name = DisplayByteString(name);
45                write!(
46                    f,
47                    "unexpected event command parameter user defined name: {name}"
48                )
49            }
50        }
51    }
52}
53
54impl std::error::Error for EventCommandParameterFromValueError {}
55
56/// An event command parameter
57#[derive(Debug, serde::Serialize, serde::Deserialize)]
58#[serde(untagged)]
59pub enum EventCommandParameter {
60    String(String),
61    StringArray(Vec<String>),
62    Int(i32),
63    MoveRoute(MoveRoute),
64    MoveCommand(MoveCommand),
65    AudioFile(AudioFile),
66    Tone(Tone),
67    Color(Color),
68}
69
70impl<'a> FromValue<'a> for EventCommandParameter {
71    fn from_value(ctx: &FromValueContext<'a>, value: &Value) -> Result<Self, FromValueError> {
72        match value {
73            Value::String(value) => {
74                let value = value.value();
75                let value = std::str::from_utf8(value)
76                    .map_err(FromValueError::new_other)?
77                    .to_string();
78                Ok(Self::String(value))
79            }
80            Value::Array(value) => {
81                let value = value.value();
82                // TODO: Maybe make the internal array elements polymorphic.
83                // If empty, static typing is impossible.
84                let first = value.first().ok_or(FromValueError::new_other(
85                    EventCommandParameterFromValueError::EmptyArray,
86                ))?;
87                let first: &Value = ctx.from_value(*first)?;
88                let first_kind = first.kind();
89
90                match first_kind {
91                    ValueKind::String => {
92                        let mut new_value = Vec::with_capacity(value.len());
93                        for value in value.iter().copied() {
94                            let value: &StringValue = ctx.from_value(value)?;
95                            let value = std::str::from_utf8(value.value())
96                                .map_err(FromValueError::new_other)?
97                                .to_string();
98                            new_value.push(value);
99                        }
100
101                        Ok(Self::StringArray(new_value))
102                    }
103                    _ => Err(FromValueError::new_other(
104                        EventCommandParameterFromValueError::UnexpectedArrayValueKind {
105                            kind: first_kind,
106                        },
107                    )),
108                }
109            }
110            Value::Fixnum(value) => {
111                let value = value.value();
112                Ok(Self::Int(value))
113            }
114            Value::Object(object_value) => {
115                let name = object_value.name();
116                let name: &SymbolValue = ctx.from_value(name.into())?;
117                let name = name.value();
118
119                match name {
120                    crate::move_route::OBJECT_NAME => {
121                        let value = FromValue::from_value(ctx, value)?;
122                        Ok(Self::MoveRoute(value))
123                    }
124                    crate::move_command::OBJECT_NAME => {
125                        let value = FromValue::from_value(ctx, value)?;
126                        Ok(Self::MoveCommand(value))
127                    }
128                    crate::audio_file::OBJECT_NAME => {
129                        let value = FromValue::from_value(ctx, value)?;
130                        Ok(Self::AudioFile(value))
131                    }
132                    _ => Err(FromValueError::UnexpectedObjectName { name: name.into() }),
133                }
134            }
135            Value::UserDefined(user_defined_value) => {
136                let name = user_defined_value.name();
137                let name: &SymbolValue = ctx.from_value(name.into())?;
138                let name = name.value();
139
140                match name {
141                    crate::tone::USER_DEFINED_NAME => {
142                        let value = FromValue::from_value(ctx, value)?;
143                        Ok(Self::Tone(value))
144                    }
145                    crate::color::USER_DEFINED_NAME => {
146                        let value = FromValue::from_value(ctx, value)?;
147                        Ok(Self::Color(value))
148                    }
149                    _ => Err(FromValueError::new_other(
150                        EventCommandParameterFromValueError::UnexpectedUserDefinedName {
151                            name: name.into(),
152                        },
153                    )),
154                }
155            }
156            _ => Err(FromValueError::new_other(
157                EventCommandParameterFromValueError::UnexpectedValueKind { kind: value.kind() },
158            )),
159        }
160    }
161}
162
163impl IntoValue for EventCommandParameter {
164    fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
165        match self {
166            Self::String(value) => Ok(arena.create_string(value.into()).into()),
167            Self::StringArray(value) => {
168                let values: Vec<_> = value
169                    .into_iter()
170                    .map(|value| arena.create_string(value.into()).into())
171                    .collect();
172                Ok(arena.create_array(values).into())
173            }
174            Self::Int(value) => value.into_value(arena),
175            Self::MoveRoute(value) => value.into_value(arena),
176            Self::MoveCommand(value) => value.into_value(arena),
177            Self::AudioFile(value) => value.into_value(arena),
178            Self::Tone(value) => value.into_value(arena),
179            Self::Color(value) => value.into_value(arena),
180        }
181    }
182}