rpgmvx_ace_types/
script.rs1use flate2::Compression;
2use flate2::bufread::ZlibDecoder;
3use flate2::bufread::ZlibEncoder;
4use ruby_marshal::ArrayValue;
5use ruby_marshal::FromValue;
6use ruby_marshal::FromValueContext;
7use ruby_marshal::FromValueError;
8use ruby_marshal::IntoValue;
9use ruby_marshal::IntoValueError;
10use ruby_marshal::StringValue;
11use ruby_marshal::Value;
12use ruby_marshal::ValueArena;
13use ruby_marshal::ValueHandle;
14use ruby_marshal::ValueKind;
15use std::io::Read;
16
17const ARRAY_LEN: usize = 3;
18
19#[derive(Debug)]
21pub struct CompressedScriptList {
22 pub scripts: Vec<CompressedScript>,
24}
25
26impl<'a> FromValue<'a> for CompressedScriptList {
27 fn from_value(ctx: &FromValueContext<'a>, value: &Value) -> Result<Self, FromValueError> {
28 Ok(Self {
29 scripts: FromValue::from_value(ctx, value)?,
30 })
31 }
32}
33impl IntoValue for CompressedScriptList {
34 fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
35 self.scripts.into_value(arena)
36 }
37}
38
39#[derive(Debug)]
41pub struct ScriptList {
42 pub scripts: Vec<Script>,
44}
45
46impl<'a> FromValue<'a> for ScriptList {
47 fn from_value(ctx: &FromValueContext<'a>, value: &Value) -> Result<Self, FromValueError> {
48 Ok(Self {
49 scripts: FromValue::from_value(ctx, value)?,
50 })
51 }
52}
53impl IntoValue for ScriptList {
54 fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
55 self.scripts.into_value(arena)
56 }
57}
58
59#[derive(Debug)]
61pub enum ScriptFromValueError {
62 InvalidArrayLen { len: usize },
64
65 InvalidName { error: std::str::Utf8Error },
67}
68
69impl std::fmt::Display for ScriptFromValueError {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 match self {
72 Self::InvalidArrayLen { len } => {
73 write!(f, "invalid script array len of {len}, expected {ARRAY_LEN}")
74 }
75 Self::InvalidName { .. } => {
76 write!(f, "the script name is invalid")
77 }
78 }
79 }
80}
81
82impl std::error::Error for ScriptFromValueError {
83 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
84 match self {
85 Self::InvalidName { error } => Some(error),
86 _ => None,
87 }
88 }
89}
90
91impl From<ScriptFromValueError> for FromValueError {
92 fn from(error: ScriptFromValueError) -> Self {
93 FromValueError::Other {
94 error: error.into(),
95 }
96 }
97}
98
99#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
101pub struct CompressedScript {
102 pub id: i32,
106
107 pub name: String,
109
110 pub data: Vec<u8>,
112}
113
114impl<'a> FromValue<'a> for CompressedScript {
115 fn from_value(ctx: &FromValueContext<'a>, value: &Value) -> Result<Self, FromValueError> {
116 let script: &ArrayValue = FromValue::from_value(ctx, value)?;
117 let script = script.value();
118
119 let array_len = script.len();
120 if array_len != ARRAY_LEN {
121 return Err(ScriptFromValueError::InvalidArrayLen { len: array_len }.into());
122 }
123
124 let script_0_value: &Value = ctx.from_value(script[0])?;
125 let id = match script_0_value.kind() {
126 ValueKind::String => {
127 let id: &StringValue = ctx.from_value(script[0])?;
128 let id = std::str::from_utf8(id.value()).map_err(FromValueError::new_other)?;
129 let id: i32 = id.parse().map_err(FromValueError::new_other)?;
130 id
131 }
132 ValueKind::Fixnum => {
133 let id: i32 = ctx.from_value(script[0])?;
134 id
135 }
136 kind => {
137 return Err(ctx.new_unexpected_value_kind_error(kind));
138 }
139 };
140
141 let name: &StringValue = ctx.from_value(script[1])?;
142 let name = std::str::from_utf8(name.value())
143 .map_err(|error| ScriptFromValueError::InvalidName { error })?;
144
145 let data: &StringValue = ctx.from_value(script[2])?;
146 let data = data.value();
147
148 Ok(Self {
149 id,
150 name: name.into(),
151 data: data.into(),
152 })
153 }
154}
155
156impl IntoValue for CompressedScript {
157 fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
158 let id = arena
159 .create_string(itoa::Buffer::new().format(self.id).into())
160 .into();
161 let name = arena.create_string(self.name.into()).into_raw();
162 let data = arena.create_string(self.data).into_raw();
163 let array = arena.create_array(vec![id, name, data]);
164
165 Ok(array.into())
166 }
167}
168
169#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
171pub struct Script {
172 pub id: i32,
176
177 pub name: String,
179
180 pub data: String,
182}
183
184impl<'a> FromValue<'a> for Script {
185 fn from_value(ctx: &FromValueContext<'a>, value: &Value) -> Result<Self, FromValueError> {
186 let script: CompressedScript = FromValue::from_value(ctx, value)?;
187
188 let mut decoder = ZlibDecoder::new(&*script.data);
189 let mut data = String::new();
190 decoder
191 .read_to_string(&mut data)
192 .map_err(FromValueError::new_other)?;
193
194 Ok(Self {
195 id: script.id,
196 name: script.name,
197 data,
198 })
199 }
200}
201
202impl IntoValue for Script {
203 fn into_value(self, arena: &mut ValueArena) -> Result<ValueHandle, IntoValueError> {
204 let id = arena
205 .create_string(itoa::Buffer::new().format(self.id).into())
206 .into();
207 let name = arena.create_string(self.name.into()).into_raw();
208
209 let compression = Compression::default();
210 let mut encoder = ZlibEncoder::new(self.data.as_bytes(), compression);
211 let mut data = Vec::new();
212 encoder
213 .read_to_end(&mut data)
214 .map_err(IntoValueError::new_other)?;
215
216 let data = arena.create_string(data).into_raw();
217
218 let array = arena.create_array(vec![id, name, data]);
219
220 Ok(array.into())
221 }
222}