rpgmxp_types/
audio_file.rs

1use ruby_marshal::FromValue;
2use ruby_marshal::FromValueContext;
3use ruby_marshal::FromValueError;
4use ruby_marshal::IntoValue;
5use ruby_marshal::IntoValueError;
6use ruby_marshal::ObjectValue;
7use ruby_marshal::StringValue;
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::AudioFile";
14
15const VOLUME_FIELD: &[u8] = b"@volume";
16const NAME_FIELD: &[u8] = b"@name";
17const PITCH_FIELD: &[u8] = b"@pitch";
18
19/// An audio file
20#[derive(Debug, serde::Serialize, serde::Deserialize)]
21pub struct AudioFile {
22    /// The volume
23    pub volume: i32,
24
25    /// The audio name
26    pub name: String,
27
28    /// The audio pitch
29    pub pitch: i32,
30}
31
32impl<'a> FromValue<'a> for AudioFile {
33    fn from_value(ctx: &FromValueContext<'a>, value: &Value) -> Result<Self, FromValueError> {
34        let object: &ObjectValue = FromValue::from_value(ctx, value)?;
35        let name: &SymbolValue = ctx.from_value(object.name().into())?;
36        let name = name.value();
37
38        let instance_variables = object.instance_variables();
39
40        if name != OBJECT_NAME {
41            return Err(FromValueError::UnexpectedObjectName { name: name.into() });
42        }
43
44        let mut volume_field = None;
45        let mut name_field = None;
46        let mut pitch_field = None;
47
48        for (key, value) in instance_variables.iter().copied() {
49            let key: &SymbolValue = ctx.from_value(key.into())?;
50            let key = key.value();
51
52            match key {
53                VOLUME_FIELD => {
54                    if volume_field.is_some() {
55                        return Err(FromValueError::DuplicateInstanceVariable {
56                            name: VOLUME_FIELD.into(),
57                        });
58                    }
59                    volume_field = Some(ctx.from_value(value)?);
60                }
61                NAME_FIELD => {
62                    if name_field.is_some() {
63                        return Err(FromValueError::DuplicateInstanceVariable {
64                            name: NAME_FIELD.into(),
65                        });
66                    }
67                    let name: &StringValue = ctx.from_value(value)?;
68                    let name =
69                        std::str::from_utf8(name.value()).map_err(FromValueError::new_other)?;
70                    name_field = Some(name);
71                }
72                PITCH_FIELD => {
73                    if pitch_field.is_some() {
74                        return Err(FromValueError::DuplicateInstanceVariable {
75                            name: PITCH_FIELD.into(),
76                        });
77                    }
78                    pitch_field = Some(ctx.from_value(value)?);
79                }
80                _ => {
81                    return Err(FromValueError::UnknownInstanceVariable { name: key.into() });
82                }
83            }
84        }
85
86        let volume = volume_field.ok_or_else(|| FromValueError::MissingInstanceVariable {
87            name: VOLUME_FIELD.into(),
88        })?;
89        let name = name_field.ok_or_else(|| FromValueError::MissingInstanceVariable {
90            name: NAME_FIELD.into(),
91        })?;
92        let pitch = pitch_field.ok_or_else(|| FromValueError::MissingInstanceVariable {
93            name: PITCH_FIELD.into(),
94        })?;
95
96        Ok(Self {
97            volume,
98            name: name.into(),
99            pitch,
100        })
101    }
102}
103
104impl IntoValue for AudioFile {
105    fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
106        let object_name = arena.create_symbol(OBJECT_NAME.into());
107
108        let volume_field_key = arena.create_symbol(VOLUME_FIELD.into());
109        let name_field_key = arena.create_symbol(NAME_FIELD.into());
110        let pitch_field_key = arena.create_symbol(PITCH_FIELD.into());
111
112        let volume_field_value = self.volume.into_value(arena)?;
113        let name_field_value = arena.create_string(self.name.into());
114        let pitch_field_value = self.pitch.into_value(arena)?;
115
116        let instance_variables = vec![
117            (volume_field_key, volume_field_value),
118            (name_field_key, name_field_value.into()),
119            (pitch_field_key, pitch_field_value),
120        ];
121        let object = arena.create_object(object_name, instance_variables);
122
123        Ok(object.into())
124    }
125}