1use crate::Error;
2use crate::SymbolValue;
3use crate::TypedValueHandle;
4use crate::Value;
5use crate::ValueArena;
6use crate::ValueHandle;
7use crate::MAJOR_VERSION;
8use crate::MINOR_VERSION;
9use crate::VALUE_KIND_ARRAY;
10use crate::VALUE_KIND_FALSE;
11use crate::VALUE_KIND_FIXNUM;
12use crate::VALUE_KIND_HASH;
13use crate::VALUE_KIND_HASH_DEFAULT;
14use crate::VALUE_KIND_INSTANCE_VARIABLES;
15use crate::VALUE_KIND_NIL;
16use crate::VALUE_KIND_OBJECT;
17use crate::VALUE_KIND_OBJECT_LINK;
18use crate::VALUE_KIND_STRING;
19use crate::VALUE_KIND_SYMBOL;
20use crate::VALUE_KIND_SYMBOL_LINK;
21use crate::VALUE_KIND_TRUE;
22use crate::VALUE_KIND_USER_DEFINED;
23use indexmap::IndexSet;
24use std::io::Write;
25
26pub struct Dumper<'a, W> {
28 writer: W,
29 arena: &'a ValueArena,
30
31 symbol_links: IndexSet<TypedValueHandle<SymbolValue>>,
32 object_links: IndexSet<ValueHandle>,
33}
34
35impl<'a, W> Dumper<'a, W> {
36 fn new(writer: W, arena: &'a ValueArena) -> Self {
38 Self {
39 writer,
40 arena,
41 symbol_links: IndexSet::new(),
42 object_links: IndexSet::new(),
43 }
44 }
45}
46
47impl<W> Dumper<'_, W>
48where
49 W: Write,
50{
51 fn write_header(&mut self) -> Result<(), Error> {
53 self.writer.write_all(&[MAJOR_VERSION, MINOR_VERSION])?;
54 Ok(())
55 }
56
57 fn write_byte(&mut self, byte: u8) -> Result<(), Error> {
59 self.writer.write_all(std::slice::from_ref(&byte))?;
60 Ok(())
61 }
62
63 fn write_byte_string(&mut self, value: &[u8]) -> Result<(), Error> {
67 let len =
68 i32::try_from(value.len()).map_err(|error| Error::USizeInvalidFixnum { error })?;
69
70 self.write_fixnum(len)?;
71 self.writer.write_all(value)?;
72
73 Ok(())
74 }
75
76 fn write_fixnum(&mut self, mut value: i32) -> Result<(), Error> {
78 if value == 0 {
79 self.writer.write_all(&[0])?;
80 return Ok(());
81 }
82
83 if value > 0 && value < 123 {
84 let value = u8::try_from(value).unwrap();
85 self.writer.write_all(&[value + 5])?;
86 return Ok(());
87 }
88
89 if value < 0 && value > -124 {
90 let value = u8::try_from((value - 5) & 0xFF).unwrap();
91 self.writer.write_all(&[value])?;
92 return Ok(());
93 }
94
95 let mut buffer = [0; std::mem::size_of::<i32>() + 1];
96 let mut buffer_size = 0;
97 for i in 1..(std::mem::size_of::<i32>() + 1) {
98 buffer[i] = u8::try_from(value & 0xFF).unwrap();
99 buffer_size = i + 1;
100
101 value >>= 8;
102 if value == 0 {
103 buffer[0] = u8::try_from(i).unwrap();
104 break;
105 }
106 if value == -1 {
107 buffer[0] = (-i8::try_from(i).unwrap()) as u8;
108 break;
109 }
110 }
111 self.writer.write_all(&buffer[..buffer_size])?;
112
113 Ok(())
114 }
115
116 fn try_write_value_object_link(&mut self, handle: ValueHandle) -> Result<bool, Error> {
122 let (index, inserted) = self.object_links.insert_full(handle);
123 if !inserted {
124 self.write_value_object_link(index)?;
125 return Ok(true);
126 }
127
128 Ok(false)
129 }
130
131 fn write_value_symbol_like(
133 &mut self,
134 handle: TypedValueHandle<SymbolValue>,
135 value: &SymbolValue,
136 ) -> Result<(), Error> {
137 match self.symbol_links.get_index_of(&handle) {
138 Some(index) => {
139 let index =
140 i32::try_from(index).map_err(|error| Error::USizeInvalidFixnum { error })?;
141
142 self.write_byte(VALUE_KIND_SYMBOL_LINK)?;
143 self.write_fixnum(index)?;
144 }
145 None => {
146 self.symbol_links.insert(handle);
147
148 self.write_byte(VALUE_KIND_SYMBOL)?;
149 self.write_byte_string(value.value())?;
150 }
151 }
152
153 Ok(())
154 }
155
156 fn write_value_object_link(&mut self, index: usize) -> Result<(), Error> {
158 let index = i32::try_from(index).map_err(|error| Error::USizeInvalidFixnum { error })?;
159
160 self.write_byte(VALUE_KIND_OBJECT_LINK)?;
161 self.write_fixnum(index)?;
162
163 Ok(())
164 }
165
166 fn write_instance_variables(
168 &mut self,
169 instance_variables: &[(TypedValueHandle<SymbolValue>, ValueHandle)],
170 ) -> Result<(), Error> {
171 let num_vars = i32::try_from(instance_variables.len())
172 .map_err(|error| Error::USizeInvalidFixnum { error })?;
173 self.write_fixnum(num_vars)?;
174
175 for (name, value) in instance_variables.iter() {
176 self.write_value((*name).into())?;
177 self.write_value(*value)?;
178 }
179
180 Ok(())
181 }
182
183 fn write_value(&mut self, handle: ValueHandle) -> Result<(), Error> {
185 let value = self
186 .arena
187 .get(handle)
188 .ok_or(Error::InvalidValueHandle { handle })?;
189
190 match value {
191 Value::Nil(_) => self.write_byte(VALUE_KIND_NIL)?,
192 Value::Bool(value) => {
193 if value.value() {
194 self.write_byte(VALUE_KIND_TRUE)?
195 } else {
196 self.write_byte(VALUE_KIND_FALSE)?
197 }
198 }
199 Value::Fixnum(value) => {
200 self.write_byte(VALUE_KIND_FIXNUM)?;
201 self.write_fixnum(value.value())?;
202 }
203 Value::Symbol(value) => {
204 let handle = TypedValueHandle::new_unchecked(handle);
205 self.write_value_symbol_like(handle, value)?;
206 }
207 Value::Array(value) => {
208 if self.try_write_value_object_link(handle)? {
209 return Ok(());
210 }
211
212 let len = i32::try_from(value.len())
213 .map_err(|error| Error::USizeInvalidFixnum { error })?;
214
215 self.write_byte(VALUE_KIND_ARRAY)?;
216 self.write_fixnum(len)?;
217 for value in value.value().iter() {
218 self.write_value(*value)?;
219 }
220 }
221 Value::Hash(value) => {
222 if self.try_write_value_object_link(handle)? {
223 return Ok(());
224 }
225
226 let default_value = value.default_value();
227 let value = value.value();
228
229 if default_value.is_some() {
230 self.write_byte(VALUE_KIND_HASH_DEFAULT)?;
231 } else {
232 self.write_byte(VALUE_KIND_HASH)?;
233 }
234
235 let num_vars = i32::try_from(value.len())
236 .map_err(|error| Error::USizeInvalidFixnum { error })?;
237 self.write_fixnum(num_vars)?;
238
239 for (key, value) in value.iter() {
240 self.write_value(*key)?;
241 self.write_value(*value)?;
242 }
243
244 if let Some(default_value) = default_value {
245 self.write_value(default_value)?;
246 }
247 }
248 Value::Object(value) => {
249 if self.try_write_value_object_link(handle)? {
250 return Ok(());
251 }
252
253 self.write_byte(VALUE_KIND_OBJECT)?;
254 self.write_value(value.name().into())?;
255 self.write_instance_variables(value.instance_variables())?;
256 }
257 Value::String(value) => {
258 if self.try_write_value_object_link(handle)? {
259 return Ok(());
260 }
261
262 match value.instance_variables() {
263 Some(instance_variables) => {
264 self.write_byte(VALUE_KIND_INSTANCE_VARIABLES)?;
265
266 self.write_byte(VALUE_KIND_STRING)?;
267 self.write_byte_string(value.value())?;
268
269 self.write_instance_variables(instance_variables)?;
270 }
271 None => {
272 self.write_byte(VALUE_KIND_STRING)?;
273 self.write_byte_string(value.value())?;
274 }
275 }
276 }
277 Value::UserDefined(value) => {
278 if self.try_write_value_object_link(handle)? {
279 return Ok(());
280 }
281
282 match value.instance_variables() {
283 Some(instance_variables) => {
284 self.write_byte(VALUE_KIND_INSTANCE_VARIABLES)?;
285
286 self.write_byte(VALUE_KIND_USER_DEFINED)?;
287 self.write_value(value.name().into())?;
288 self.write_byte_string(value.value())?;
289
290 self.write_instance_variables(instance_variables)?;
291 }
292 None => {
293 self.write_byte(VALUE_KIND_USER_DEFINED)?;
294 self.write_value(value.name().into())?;
295 self.write_byte_string(value.value())?;
296 }
297 }
298 }
299 }
300
301 Ok(())
302 }
303
304 fn dump(&mut self) -> Result<(), Error> {
306 self.write_header()?;
307 self.write_value(self.arena.root())?;
308
309 Ok(())
310 }
311}
312
313pub fn dump<W>(writer: W, value_arena: &ValueArena) -> Result<(), Error>
315where
316 W: Write,
317{
318 let mut dumper = Dumper::new(writer, value_arena);
319 dumper.dump()?;
320 Ok(())
321}