rpgmxp_types/
move_route.rs

1use crate::MoveCommand;
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::MoveRoute";
14
15const LIST_FIELD: &[u8] = b"@list";
16const SKIPPABLE_FIELD: &[u8] = b"@skippable";
17const REPEAT_FIELD: &[u8] = b"@repeat";
18
19#[derive(Debug, serde::Serialize, serde::Deserialize)]
20pub struct MoveRoute {
21    pub list: Vec<MoveCommand>,
22    pub skippable: bool,
23    pub repeat: bool,
24}
25
26impl<'a> FromValue<'a> for MoveRoute {
27    fn from_value(ctx: &FromValueContext<'a>, value: &Value) -> Result<Self, FromValueError> {
28        let object: &ObjectValue = FromValue::from_value(ctx, value)?;
29
30        let name = object.name();
31        let name: &SymbolValue = ctx.from_value(name.into())?;
32        let name = name.value();
33        if name != OBJECT_NAME {
34            return Err(FromValueError::UnexpectedObjectName { name: name.into() });
35        }
36
37        let instance_variables = object.instance_variables();
38
39        let mut list_field = None;
40        let mut skippable_field = None;
41        let mut repeat_field = None;
42
43        for (key, value) in instance_variables.iter().copied() {
44            let key: &SymbolValue = ctx.from_value(key.into())?;
45            let key = key.value();
46
47            match key {
48                LIST_FIELD => {
49                    if list_field.is_some() {
50                        return Err(FromValueError::DuplicateInstanceVariable { name: key.into() });
51                    }
52
53                    list_field = Some(ctx.from_value(value)?);
54                }
55                SKIPPABLE_FIELD => {
56                    if skippable_field.is_some() {
57                        return Err(FromValueError::DuplicateInstanceVariable { name: key.into() });
58                    }
59
60                    skippable_field = Some(ctx.from_value(value)?);
61                }
62                REPEAT_FIELD => {
63                    if repeat_field.is_some() {
64                        return Err(FromValueError::DuplicateInstanceVariable { name: key.into() });
65                    }
66
67                    repeat_field = Some(ctx.from_value(value)?);
68                }
69                _ => {
70                    return Err(FromValueError::UnknownInstanceVariable { name: key.into() });
71                }
72            }
73        }
74
75        let list = list_field.ok_or_else(|| FromValueError::MissingInstanceVariable {
76            name: LIST_FIELD.into(),
77        })?;
78        let skippable = skippable_field.ok_or_else(|| FromValueError::MissingInstanceVariable {
79            name: SKIPPABLE_FIELD.into(),
80        })?;
81        let repeat = repeat_field.ok_or_else(|| FromValueError::MissingInstanceVariable {
82            name: REPEAT_FIELD.into(),
83        })?;
84
85        Ok(Self {
86            list,
87            skippable,
88            repeat,
89        })
90    }
91}
92
93impl IntoValue for MoveRoute {
94    fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
95        let object_name = arena.create_symbol(OBJECT_NAME.into());
96
97        let list_field_key = arena.create_symbol(LIST_FIELD.into());
98        let skippable_field_key = arena.create_symbol(SKIPPABLE_FIELD.into());
99        let repeat_field_key = arena.create_symbol(REPEAT_FIELD.into());
100
101        let list_field_value = self.list.into_value(arena)?;
102        let skippable_field_value = arena.create_bool(self.skippable);
103        let repeat_field_value = arena.create_bool(self.repeat);
104
105        let fields = vec![
106            (list_field_key, list_field_value),
107            (skippable_field_key, skippable_field_value.into()),
108            (repeat_field_key, repeat_field_value.into()),
109        ];
110
111        let object = arena.create_object(object_name, fields);
112
113        Ok(object.into())
114    }
115}