ruby_marshal/
dump.rs

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
26/// A dumper for ruby data
27pub 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    /// Create a new [`Dumper`] from a writer and entry arena.
37    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    /// Write the header
52    fn write_header(&mut self) -> Result<(), Error> {
53        self.writer.write_all(&[MAJOR_VERSION, MINOR_VERSION])?;
54        Ok(())
55    }
56
57    /// Write a byte
58    fn write_byte(&mut self, byte: u8) -> Result<(), Error> {
59        self.writer.write_all(std::slice::from_ref(&byte))?;
60        Ok(())
61    }
62
63    /// Write a byte string.
64    ///
65    /// This is a fixnum, followed by that many bytes.
66    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    /// Write a Fixnum
77    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    /// Try to write a value object reference, if possible.
117    /// If not successful, this entry is recorded and will be used for future resolutions.
118    ///
119    /// # Returns
120    /// Returns true if successful.
121    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    /// Write a value that is either a symbol or a symbol link.
132    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    /// Write an object link, as a value.
157    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    /// Write instance variables
167    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    /// Write a value
184    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    /// Dump the root node to the writer.
305    fn dump(&mut self) -> Result<(), Error> {
306        self.write_header()?;
307        self.write_value(self.arena.root())?;
308
309        Ok(())
310    }
311}
312
313/// Dump to a writer.
314pub 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}