rpgm_common_types/
tone.rs

1use ruby_marshal::FromValue;
2use ruby_marshal::FromValueContext;
3use ruby_marshal::FromValueError;
4use ruby_marshal::IntoValue;
5use ruby_marshal::IntoValueError;
6use ruby_marshal::SymbolValue;
7use ruby_marshal::UserDefinedValue;
8use ruby_marshal::Value;
9use ruby_marshal::ValueArena;
10use ruby_marshal::ValueHandle;
11
12pub const USER_DEFINED_NAME: &[u8] = b"Tone";
13
14const SIZE: usize = 8 * 4;
15
16#[derive(Debug)]
17pub enum ToneFromValueError {
18    InvalidSize { size: usize },
19}
20
21impl std::fmt::Display for ToneFromValueError {
22    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
23        match self {
24            Self::InvalidSize { size } => {
25                write!(f, "invalid Tone data size of {size}, expected {SIZE}")
26            }
27        }
28    }
29}
30
31impl std::error::Error for ToneFromValueError {}
32
33#[derive(Debug, serde::Serialize, serde::Deserialize)]
34pub struct Tone {
35    pub red: f64,
36    pub green: f64,
37    pub blue: f64,
38    pub gray: f64,
39}
40
41impl FromValue<'_> for Tone {
42    fn from_value(ctx: &FromValueContext, value: &Value) -> Result<Self, FromValueError> {
43        let user_defined: &UserDefinedValue = FromValue::from_value(ctx, value)?;
44        let name = user_defined.name();
45        let name: &SymbolValue = ctx.from_value(name.into())?;
46        let name = name.value();
47        if name != USER_DEFINED_NAME {
48            return Err(FromValueError::UnexpectedObjectName { name: name.into() });
49        }
50
51        let value = user_defined.value();
52
53        let value_len = value.len();
54        if value_len != SIZE {
55            return Err(FromValueError::new_other(ToneFromValueError::InvalidSize {
56                size: value_len,
57            }));
58        }
59
60        let (red, value) = value.split_at(8);
61        let (green, value) = value.split_at(8);
62        let (blue, value) = value.split_at(8);
63        let (gray, _value) = value.split_at(8);
64
65        let red = f64::from_le_bytes(red.try_into().unwrap());
66        let green = f64::from_le_bytes(green.try_into().unwrap());
67        let blue = f64::from_le_bytes(blue.try_into().unwrap());
68        let gray = f64::from_le_bytes(gray.try_into().unwrap());
69
70        Ok(Self {
71            red,
72            green,
73            blue,
74            gray,
75        })
76    }
77}
78
79impl IntoValue for Tone {
80    fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
81        let name = arena.create_symbol(USER_DEFINED_NAME.into());
82
83        let mut value = Vec::with_capacity(32);
84        value.extend(self.red.to_le_bytes());
85        value.extend(self.green.to_le_bytes());
86        value.extend(self.blue.to_le_bytes());
87        value.extend(self.gray.to_le_bytes());
88
89        Ok(arena.create_user_defined(name, value).into())
90    }
91}