rpgmxp_types/
move_command.rs

1use crate::EventCommandParameter;
2use ruby_marshal::FromValue;
3use ruby_marshal::FromValueContext;
4use ruby_marshal::FromValueError;
5use ruby_marshal::IntoValue;
6use ruby_marshal::IntoValueError;
7use ruby_marshal::ObjectValue;
8use ruby_marshal::SymbolValue;
9use ruby_marshal::Value;
10use ruby_marshal::ValueArena;
11use ruby_marshal::ValueHandle;
12
13pub(crate) const OBJECT_NAME: &[u8] = b"RPG::MoveCommand";
14
15const PARAMETERS_FIELD: &[u8] = b"@parameters";
16const CODE_FIELD: &[u8] = b"@code";
17
18#[derive(Debug, serde::Serialize, serde::Deserialize)]
19pub struct MoveCommand {
20    pub parameters: Vec<EventCommandParameter>,
21    pub code: i32,
22}
23
24impl<'a> FromValue<'a> for MoveCommand {
25    fn from_value(ctx: &FromValueContext<'a>, value: &Value) -> Result<Self, FromValueError> {
26        let object: &ObjectValue = FromValue::from_value(ctx, value)?;
27
28        let name = object.name();
29        let name: &SymbolValue = ctx.from_value(name.into())?;
30        let name = name.value();
31
32        if name != OBJECT_NAME {
33            return Err(FromValueError::UnexpectedObjectName { name: name.into() });
34        }
35
36        let instance_variables = object.instance_variables();
37
38        let mut parameters_field = None;
39        let mut code_field = None;
40
41        for (key, value) in instance_variables.iter().copied() {
42            let key: &SymbolValue = ctx.from_value(key.into())?;
43            let key = key.value();
44
45            match key {
46                PARAMETERS_FIELD => {
47                    if parameters_field.is_some() {
48                        return Err(FromValueError::DuplicateInstanceVariable { name: key.into() });
49                    }
50
51                    parameters_field = Some(ctx.from_value(value)?);
52                }
53                CODE_FIELD => {
54                    if code_field.is_some() {
55                        return Err(FromValueError::DuplicateInstanceVariable { name: key.into() });
56                    }
57
58                    code_field = Some(ctx.from_value(value)?);
59                }
60                _ => {
61                    return Err(FromValueError::UnknownInstanceVariable { name: key.into() });
62                }
63            }
64        }
65
66        let parameters =
67            parameters_field.ok_or_else(|| FromValueError::MissingInstanceVariable {
68                name: PARAMETERS_FIELD.into(),
69            })?;
70        let code = code_field.ok_or_else(|| FromValueError::MissingInstanceVariable {
71            name: CODE_FIELD.into(),
72        })?;
73
74        Ok(Self { parameters, code })
75    }
76}
77
78impl IntoValue for MoveCommand {
79    fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
80        let object_name = arena.create_symbol(OBJECT_NAME.into());
81
82        let parameters_field_key = arena.create_symbol(PARAMETERS_FIELD.into());
83        let code_field_key = arena.create_symbol(CODE_FIELD.into());
84
85        let parameters_field_value = self.parameters.into_value(arena)?;
86        let code_field_value = self.code.into_value(arena)?;
87
88        let fields = vec![
89            (parameters_field_key, parameters_field_value),
90            (code_field_key, code_field_value),
91        ];
92
93        let object = arena.create_object(object_name, fields);
94
95        Ok(object.into())
96    }
97}