rpgmvx_types/
event_command_parameter.rs

1use crate::Color;
2use crate::MoveCommand;
3use crate::MoveRoute;
4use crate::Se;
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    UnexpectedUserDefinedName { name: Vec<u8> },
23    EmptyArray,
24    UnexpectedArrayValueKind { kind: ValueKind },
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::UnexpectedUserDefinedName { name } => {
37                let name = DisplayByteString(name);
38                write!(
39                    f,
40                    "unexpected event command parameter user defined name: {name}"
41                )
42            }
43            Self::EmptyArray => write!(f, "the event command parameter array is empty"),
44            Self::UnexpectedArrayValueKind { kind } => {
45                write!(
46                    f,
47                    "unexpected event command parameter array value kind: {kind:?}"
48                )
49            }
50        }
51    }
52}
53
54impl std::error::Error for EventCommandParameterFromValueError {}
55
56#[derive(Debug, serde::Serialize, serde::Deserialize)]
57pub enum EventCommandParameter {
58    String(String),
59    Int(i32),
60    Bool(bool),
61    Nil,
62    StringArray(Vec<String>),
63    MoveRoute(MoveRoute),
64    MoveCommand(MoveCommand),
65    Se(Se),
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::Fixnum(value) => {
81                let value = value.value();
82                Ok(Self::Int(value))
83            }
84            Value::Bool(value) => {
85                let value = value.value();
86                Ok(Self::Bool(value))
87            }
88            Value::Nil(_) => Ok(Self::Nil),
89            Value::Array(value) => {
90                let value = value.value();
91                // TODO: Maybe make the internal array elements polymorphic.
92                // If empty, static typing is impossible.
93                let first = value.first().ok_or(FromValueError::new_other(
94                    EventCommandParameterFromValueError::EmptyArray,
95                ))?;
96                let first: &Value = ctx.from_value(*first)?;
97                let first_kind = first.kind();
98
99                match first_kind {
100                    ValueKind::String => {
101                        let mut new_value = Vec::with_capacity(value.len());
102                        for value in value.iter().copied() {
103                            let value: &StringValue = ctx.from_value(value)?;
104                            let value = std::str::from_utf8(value.value())
105                                .map_err(FromValueError::new_other)?
106                                .to_string();
107                            new_value.push(value);
108                        }
109
110                        Ok(Self::StringArray(new_value))
111                    }
112                    _ => Err(FromValueError::new_other(
113                        EventCommandParameterFromValueError::UnexpectedArrayValueKind {
114                            kind: first_kind,
115                        },
116                    )),
117                }
118            }
119            Value::Object(object_value) => {
120                let name = object_value.name();
121                let name: &SymbolValue = ctx.from_value(name.into())?;
122                let name = name.value();
123
124                match name {
125                    crate::move_route::OBJECT_NAME => {
126                        let value = FromValue::from_value(ctx, value)?;
127                        Ok(Self::MoveRoute(value))
128                    }
129                    crate::move_command::OBJECT_NAME => {
130                        let value = FromValue::from_value(ctx, value)?;
131                        Ok(Self::MoveCommand(value))
132                    }
133                    crate::se::OBJECT_NAME => {
134                        let value = FromValue::from_value(ctx, value)?;
135                        Ok(Self::Se(value))
136                    }
137                    _ => Err(FromValueError::UnexpectedObjectName { name: name.into() }),
138                }
139            }
140            Value::UserDefined(user_defined_value) => {
141                let name = user_defined_value.name();
142                let name: &SymbolValue = ctx.from_value(name.into())?;
143                let name = name.value();
144
145                match name {
146                    crate::tone::USER_DEFINED_NAME => {
147                        let value = FromValue::from_value(ctx, value)?;
148                        Ok(Self::Tone(value))
149                    }
150                    crate::color::USER_DEFINED_NAME => {
151                        let value = FromValue::from_value(ctx, value)?;
152                        Ok(Self::Color(value))
153                    }
154                    _ => Err(FromValueError::new_other(
155                        EventCommandParameterFromValueError::UnexpectedUserDefinedName {
156                            name: name.into(),
157                        },
158                    )),
159                }
160            }
161            _ => Err(FromValueError::new_other(
162                EventCommandParameterFromValueError::UnexpectedValueKind { kind: value.kind() },
163            )),
164        }
165    }
166}
167
168impl IntoValue for EventCommandParameter {
169    fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
170        match self {
171            Self::String(value) => Ok(arena.create_string(value.into()).into()),
172            Self::Int(value) => value.into_value(arena),
173            Self::Bool(value) => value.into_value(arena),
174            Self::Nil => Ok(arena.create_nil().into()),
175            Self::StringArray(value) => {
176                let values: Vec<_> = value
177                    .into_iter()
178                    .map(|value| arena.create_string(value.into()).into())
179                    .collect();
180                Ok(arena.create_array(values).into())
181            }
182            Self::MoveRoute(value) => value.into_value(arena),
183            Self::MoveCommand(value) => value.into_value(arena),
184            Self::Se(value) => value.into_value(arena),
185            Self::Tone(value) => value.into_value(arena),
186            Self::Color(value) => value.into_value(arena),
187        }
188    }
189}