fyrox_core/visitor/mod.rs
1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Visitor is a tree-based serializer/deserializer with intermediate representation for stored data.
22//! When data is serialized, it will be transformed into an intermediate representation and only then
23//! will be dumped onto the disk. Deserialization is the same: the data (binary or text) is read
24//! and converted into an intermediate representation (IR). End users can use this IR to save or load
25//! their structures of pretty much any complexity.
26//!
27//! # Overview
28//!
29//! Visitor uses a tree to create structured data storage. Basic unit is a *node* - it is a container
30//! for data fields. Each node has a name, handle to parent, set of handles to children nodes and a
31//! container for data fields. Data field is a pair of a name and a value, the value can be any of
32//! simple Rust types and some of the trivially copyable data structures (vectors, matrices, etc.).
33//! The main criteria of what could be the field and what not is the ability to be represented as
34//! a set of bytes.
35//!
36//! See [`Visitor`] docs for more info.
37
38#![warn(missing_docs)]
39
40pub mod blackboard;
41pub mod error;
42pub mod field;
43mod impls;
44pub mod pod;
45mod reader;
46mod writer;
47
48pub use fyrox_core_derive::Visit;
49
50pub mod prelude {
51 //! Types to use `#[derive(Visit)]`
52 pub use super::{Visit, VisitResult, Visitor};
53 pub use crate::visitor::error::VisitError;
54}
55
56use crate::{
57 array_as_u8_slice_mut,
58 io::{self},
59 pool::{Handle, Pool},
60 visitor::{
61 reader::{ascii::AsciiReader, binary::BinaryReader, Reader},
62 writer::{ascii::AsciiWriter, binary::BinaryWriter, Writer},
63 },
64};
65use bitflags::bitflags;
66use blackboard::Blackboard;
67use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
68use error::VisitError;
69use field::{Field, FieldKind};
70use fxhash::FxHashMap;
71use std::{
72 any::Any,
73 fmt::{Debug, Formatter},
74 fs::File,
75 hash::Hash,
76 io::{BufWriter, Cursor, Read, Write},
77 ops::{Deref, DerefMut},
78 path::Path,
79 rc::Rc,
80 sync::Arc,
81};
82
83/// Version of the visitor.
84#[repr(u32)]
85pub enum VisitorVersion {
86 /// Version of the old format.
87 Legacy = 0,
88 /// Flattened vector structure.
89 VectorFlattening,
90 /// Removal of `[N:` and `{N:` counters in ascii format.
91 AsciiNoCounters,
92
93 /// ^^ Add a new version above this line ^^.
94 ///
95 /// There are few major rules:
96 ///
97 /// 1) New version name should be something like `VectorFlattening`, and clearly describe the
98 /// changes introduced by the new version. Always add a doc comment that contains a clear
99 /// description of what was changed.
100 /// 2) Do **NOT** add explicit number value for a new version. The compiler will do that for you,
101 /// and there will be no chance of mistake. `Legacy` variant is an exception.
102 /// 3) Existing version entries must **NOT** be deleted or moved.
103 /// 4) `Last` variant must always be the last.
104 Last,
105}
106
107/// Current version number of the visitor.
108pub const CURRENT_VERSION: u32 = (VisitorVersion::Last as u32).saturating_sub(1);
109
110/// Proxy struct for plain data. It is used to serialize arrays of trivially copyable data (`Vec<u8>`)
111/// directly as a large chunk of data. For example, an attempt to serialize `Vec<u8>` serialize each
112/// byte as a separate node which is very inefficient.
113///
114/// BinaryBlob stores data very much like [`crate::visitor::pod::PodVecView`] except that BinaryBlob
115/// has less type safety. In practice, it is used with `T` = `u8` for Strings and Paths. However,
116/// it accepts any type T that is Copy, and it lacks the type_id system that PodVecView has for
117/// checking that the data it is reading comes from the expected type.
118pub struct BinaryBlob<'a, T>
119where
120 T: Copy,
121{
122 /// A reference to a vector that represents a binary blob.
123 pub vec: &'a mut Vec<T>,
124}
125
126impl<T> Visit for BinaryBlob<'_, T>
127where
128 T: Copy + bytemuck::Pod,
129{
130 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
131 if visitor.reading {
132 if let Some(field) = visitor.find_field(name) {
133 match &field.kind {
134 FieldKind::BinaryBlob(data) => {
135 let len = data.len() / size_of::<T>();
136 let mut vec = Vec::<T>::with_capacity(len);
137
138 unsafe {
139 std::ptr::copy_nonoverlapping(
140 data.as_ptr(),
141 array_as_u8_slice_mut(&mut vec).as_mut_ptr(),
142 data.len(),
143 );
144
145 vec.set_len(len);
146 }
147
148 *self.vec = vec;
149
150 Ok(())
151 }
152 _ => Err(VisitError::FieldTypeDoesNotMatch {
153 expected: stringify!(FieldKind::BinaryBlob),
154 actual: format!("{:?}", field.kind),
155 }),
156 }
157 } else {
158 Err(VisitError::field_does_not_exist(name, visitor))
159 }
160 } else if visitor.find_field(name).is_some() {
161 Err(VisitError::FieldAlreadyExists(name.to_owned()))
162 } else {
163 let node = visitor.current_node();
164
165 let len_bytes = self.vec.len() * std::mem::size_of::<T>();
166 let mut bytes = Vec::<u8>::with_capacity(len_bytes);
167 bytes.extend_from_slice(unsafe {
168 std::slice::from_raw_parts(self.vec.as_ptr() as *const u8, len_bytes)
169 });
170
171 node.fields
172 .push(Field::new(name, FieldKind::BinaryBlob(bytes)));
173
174 Ok(())
175 }
176 }
177}
178
179/// The result of a [Visit::visit] or of a Visitor encoding operation such as [Visitor::save_binary_to_file].
180/// It has no value unless an error occurred.
181pub type VisitResult = Result<(), VisitError>;
182
183trait VisitableElementaryField {
184 fn write(&self, file: &mut dyn Write) -> VisitResult;
185 fn read(&mut self, file: &mut dyn Read) -> VisitResult;
186}
187
188macro_rules! impl_visitable_elementary_field {
189 ($ty:ty, $write:ident, $read:ident $(, $endian:ident)*) => {
190 impl VisitableElementaryField for $ty {
191 fn write(&self, file: &mut dyn Write) -> VisitResult {
192 file.$write::<$($endian)*>(*self)?;
193 Ok(())
194 }
195
196 fn read(&mut self, file: &mut dyn Read) -> VisitResult {
197 *self = file.$read::<$($endian)*>()?;
198 Ok(())
199 }
200 }
201 };
202}
203impl_visitable_elementary_field!(f64, write_f64, read_f64, LittleEndian);
204impl_visitable_elementary_field!(f32, write_f32, read_f32, LittleEndian);
205impl_visitable_elementary_field!(u8, write_u8, read_u8);
206impl_visitable_elementary_field!(i8, write_i8, read_i8);
207impl_visitable_elementary_field!(u16, write_u16, read_u16, LittleEndian);
208impl_visitable_elementary_field!(i16, write_i16, read_i16, LittleEndian);
209impl_visitable_elementary_field!(u32, write_u32, read_u32, LittleEndian);
210impl_visitable_elementary_field!(i32, write_i32, read_i32, LittleEndian);
211impl_visitable_elementary_field!(u64, write_u64, read_u64, LittleEndian);
212impl_visitable_elementary_field!(i64, write_i64, read_i64, LittleEndian);
213
214/// A node is a collection of [Fields](Field) that exists within a tree of nodes that allows a
215/// [Visitor] to store its data. Each node has a name, and may have a parent node and child nodes.
216/// A node is used when visiting complex data, that cannot be represented by a simple memory block.
217#[derive(Debug)]
218pub struct VisitorNode {
219 name: String,
220 fields: Vec<Field>,
221 parent: Handle<VisitorNode>,
222 children: Vec<Handle<VisitorNode>>,
223}
224
225impl VisitorNode {
226 fn new(name: &str, parent: Handle<VisitorNode>) -> Self {
227 Self {
228 name: name.to_owned(),
229 fields: Vec::new(),
230 parent,
231 children: Vec::new(),
232 }
233 }
234}
235
236impl Default for VisitorNode {
237 fn default() -> Self {
238 Self {
239 name: String::new(),
240 fields: Vec::new(),
241 parent: Handle::NONE,
242 children: Vec::new(),
243 }
244 }
245}
246
247/// A RegionGuard is a [Visitor] wrapper that automatically leaves the current region when it is
248/// dropped.
249#[must_use = "the guard must be used"]
250pub struct RegionGuard<'a>(&'a mut Visitor);
251
252impl Deref for RegionGuard<'_> {
253 type Target = Visitor;
254
255 fn deref(&self) -> &Self::Target {
256 self.0
257 }
258}
259
260impl DerefMut for RegionGuard<'_> {
261 fn deref_mut(&mut self) -> &mut Self::Target {
262 self.0
263 }
264}
265
266impl Drop for RegionGuard<'_> {
267 fn drop(&mut self) {
268 // If we acquired RegionGuard instance, then it is safe to assert that
269 // `leave_region` was successful.
270 self.0.leave_region().unwrap();
271 }
272}
273
274bitflags! {
275 /// Flags that can be used to influence the behavior of [Visit::visit] methods.
276 #[derive(Debug)]
277 pub struct VisitorFlags: u32 {
278 /// No flags set, do nothing special.
279 const NONE = 0;
280 /// Tell [crate::variable::InheritableVariable::visit] to assume that it's
281 /// [VariableFlags::MODIFIED](create::variable::VariableFlags::MODIFIED) is set,
282 /// and therefore write its data. Otherwise, InheritableVariable has the special
283 /// property of *not writing itself* when the `MODIFIED` flag is not set.
284 const SERIALIZE_EVERYTHING = 1 << 1;
285 }
286}
287
288/// Visitor is a tree-based serializer/deserializer with intermediate representation for stored data.
289/// When data is serialized, it will be transformed into an intermediate representation and only then
290/// will be dumped onto the disk. Deserialization is the same: the data (binary or text) is read
291/// and converted into an intermediate representation (IR). End users can use this IR to save or load
292/// their structures of pretty much any complexity.
293///
294/// # Overview
295///
296/// Visitor uses a tree to create structured data storage. Basic unit is a *node* - it is a container
297/// for data fields. Each node has a name, handle to parent, set of handles to children nodes and a
298/// container for data fields. Data field is a pair of a name and a value, the value can be any of
299/// simple Rust types and some of the trivially copyable data structures (vectors, matrices, etc.).
300/// The main criteria of what could be the field and what not is the ability to be represented as
301/// a set of bytes.
302///
303/// Instead of calling visitor methods to read or write the visitor's data, reading and writing
304/// happen in the [Visit::visit] method of a variable that will either store the read value
305/// or holds the value to be written.
306///
307/// For example, `x.visit("MyValue", &mut visitor)` will do one of:
308///
309/// 1. Take the value of `x` and store it in `visitor` under the name "MyValue", if `visitor.is_reading()` is false.
310/// 2. Read a value named "MyValue" from `visitor` and store it in `x`, if `visitor.is_reading()` is true.
311///
312/// Whether the value of `x` gets written into `visitor` or overwritten with a value from `visitor` is determined
313/// by whether [Visitor::is_reading()] returns true or false.
314pub struct Visitor {
315 /// The nodes that make up this visitors tree.
316 nodes: Pool<VisitorNode>,
317 /// The id for the next `Rc` or `Arc` that the visitor encounters.
318 unique_id_counter: u64,
319 /// The name of the type of the `Rc` or `Arc` associated with each id.
320 /// This allows type mismatch errors to include type information.
321 type_name_map: FxHashMap<u64, &'static str>,
322 /// The `Rc` value associated with each id, to allow the visitor to find the `Rc` when reading.
323 rc_map: FxHashMap<u64, Rc<dyn Any>>,
324 /// The `Arc` value associated with each id, to allow the visitor to find the `Arc` when reading.
325 arc_map: FxHashMap<u64, Arc<dyn Any + Send + Sync>>,
326 /// True if this visitor is being read from, during loading.
327 /// False if this visitor is being written to, during saving.
328 reading: bool,
329 /// The handle of the node that is currently being written to or read from.
330 current_node: Handle<VisitorNode>,
331 /// The handle of the start of the tree.
332 root: Handle<VisitorNode>,
333 /// The version number of the visitor. See [`VisitorVersion`].
334 version: u32,
335 /// A place to store whatever objects may be needed to help with reading and writing values.
336 pub blackboard: Blackboard,
337 /// Flags that can activate special behavior in some Visit values, such as
338 /// [crate::variable::InheritableVariable].
339 pub flags: VisitorFlags,
340}
341
342impl Debug for Visitor {
343 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
344 let mut output = f.debug_struct("Visitor");
345
346 output.field("flags", &self.flags);
347
348 for (i, node) in self.nodes.iter().enumerate() {
349 output.field(&format!("node{i}"), node);
350 }
351
352 output.finish()
353 }
354}
355
356/// Trait of types that can be read from a [Visitor] or written to a Visitor.
357///
358/// ## Code Generation
359///
360/// Procedural macro could be used to generate trivial implementations for this trait, which covers
361/// 99% of the cases. Consider the following example:
362///
363/// ```rust
364/// use fyrox_core::visitor::prelude::*;
365///
366/// #[derive(Visit, Default)]
367/// struct MyType {
368/// field_a: u32,
369/// field_b: String
370/// }
371/// ```
372///
373/// The generated code will be something like this:
374///
375/// ```rust
376/// use fyrox_core::visitor::prelude::*;
377///
378/// struct MyType {
379/// field_a: u32,
380/// field_b: String
381/// }
382///
383/// impl Visit for MyType {
384/// fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
385/// let mut region = visitor.enter_region(name)?;
386///
387/// self.field_a.visit("FieldA", &mut region)?;
388/// self.field_b.visit("FieldB", &mut region)?;
389///
390/// Ok(())
391/// }
392/// }
393/// ```
394///
395/// ### Type Attributes
396///
397/// - `#[visit(optional)]` - marks all the fields of the type as optional and suppresses any errors
398/// on serialization and deserialization. In the generated code, all the fields will be visited like
399/// this `let _ = self.field_a.visit("FieldA", &mut region);`
400/// - `#[visit(pre_visit_method = "function_name")]` - name of a function, that will be called
401/// before the generated body.
402/// - `#[visit(post_visit_method = "function_name")]` - name of a function, that will be called
403/// after the generated body.
404///
405/// ### Field Attributes
406///
407/// - `#[visit(skip)]` - disables serialization and deserialization of the field.
408/// - `#[visit(rename = "new_name")]` - overrides the name of the field with `new_name`. In the
409/// generated code, all the fields will be visited like this `self.field_a.visit("new_name", &mut region)?;`
410/// - `#[visit(optional)]` - marks the field as optional and suppresses any errors on serialization
411/// and deserialization. In the generated code, all the fields will be visited like this
412/// `let _ = self.field_a.visit("FieldA", &mut region);`
413pub trait Visit {
414 /// Read or write this value, depending on whether [Visitor::is_reading()] is true or false.
415 ///
416 /// # In Write Mode
417 ///
418 /// The given name is a key to identify where this value will be stored in the visitor.
419 /// Whether this name indicates a field or a region is determined by the value being visited.
420 /// No two regions can exist with the same name as children of a single node,
421 /// and no two fields can exist with the same name within a single node,
422 /// but a region may share the same name as a field. If a name clash occurs, then an error
423 /// is returned. Otherwise the value is written into the Visitor data at the given name.
424 ///
425 /// # In Read Mode
426 ///
427 /// The given name is a key to identify where this value should be found the visitor.
428 /// Whether the name indicates a field or a region is determined by the the value being visited.
429 /// If the field or region is not found with the given name
430 /// then an error is returned. Otherwise the value being visited will be mutated
431 /// to match the data in the visitor.
432 ///
433 /// # Buiding a Complex Value out of Multiple Fields
434 ///
435 /// If representing this value requires more than one field,
436 /// [Visitor::enter_region] can be used to create a new node within the
437 /// visitor with the given name, and the fields of this value can then read from
438 /// or write to that node using the returned Visitor without risk of name
439 /// clashes.
440 ///
441 /// See the documentation for [the Visit derive macro](fyrox_core_derive::Visit) for examples of how to
442 /// implement Visit for some simple types.
443 ///
444 /// # Abnormal Implementations
445 ///
446 /// Types with special needs may choose to read and write in unusual ways. In addition to choosing
447 /// whether they will store their data in a region or a field, a value might choose to do neither.
448 /// A value may also choose to attempt to read its data in multiple ways so as to remain
449 /// backwards-compatible with older versions where the format of data storage may be different.
450 ///
451 /// See [crate::variable::InheritableVariable::visit] for an example of an abnormal implementation of Visit.
452 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult;
453}
454
455impl Default for Visitor {
456 fn default() -> Self {
457 Self::new()
458 }
459}
460
461/// Format of the data that be used by a [`Visitor`] instance for reading or writing from/to an
462/// external storage.
463#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
464#[must_use]
465pub enum Format {
466 /// The format is unknown and unsupported.
467 Unknown,
468 /// Binary format. The fastest and smallest, but changes cannot be merged by a version control
469 /// system, thus not suitable for collaborative work. It should be used primarily for production
470 /// builds.
471 Binary,
472 /// Slow and "fat" format, but changes can be merged by a version control system. It makes this
473 /// format ideal for collaborative work.
474 Ascii,
475}
476
477impl Visitor {
478 /// Old header marker for binary version.
479 pub const MAGIC_BINARY_OLD: &'static str = "RG3D";
480
481 /// Sequence of bytes that is automatically written at the start when a visitor is encoded into
482 /// bytes. It is written by [Visitor::save_binary_to_file], [Visitor::save_binary_to_memory],
483 /// and [Visitor::save_binary_to_vec].
484 ///
485 /// [Visitor::load_binary_from_file] will return an error if this sequence of bytes is not present
486 /// at the beginning of the file, and [Visitor::load_binary_from_memory] will return an error of
487 /// these bytes are not at the beginning of the given slice.
488 pub const MAGIC_BINARY_CURRENT: &'static str = "FBAF";
489
490 /// Old header marker for ASCII version.
491 pub const MAGIC_ASCII_OLD: &'static str = "FTAF";
492
493 /// Sequence of bytes that is automatically written at the start when a visitor is encoded into
494 /// ascii form. It is written by [Visitor::save_ascii_to_file], [Visitor::save_ascii_to_memory],
495 /// and [Visitor::save_ascii_to_string].
496 ///
497 /// [Visitor::load_ascii_from_file] will return an error if this sequence of bytes is not present
498 /// at the beginning of the file, and [Visitor::load_ascii_from_memory] will return an error of
499 /// these bytes are not at the beginning of the given slice.
500 pub const MAGIC_ASCII_CURRENT: &'static str = "FTAX";
501
502 /// Checks whether the given reader points to a supported file format or not.
503 #[must_use]
504 pub fn is_supported(src: &mut dyn Read) -> bool {
505 Self::detect_format(src) != Format::Unknown
506 }
507
508 /// Tries to extract the information about the file format in the given reader.
509 pub fn detect_format(src: &mut dyn Read) -> Format {
510 let mut magic: [u8; 4] = Default::default();
511 if src.read_exact(&mut magic).is_ok() {
512 if magic.eq(Visitor::MAGIC_BINARY_OLD.as_bytes())
513 || magic.eq(Visitor::MAGIC_BINARY_CURRENT.as_bytes())
514 {
515 return Format::Binary;
516 } else if magic.eq(Visitor::MAGIC_ASCII_OLD.as_bytes())
517 || magic.eq(Visitor::MAGIC_ASCII_CURRENT.as_bytes())
518 {
519 return Format::Ascii;
520 }
521 }
522 Format::Unknown
523 }
524
525 /// Tries to extract the information about the file format in the given slice.
526 pub fn detect_format_from_slice(data: &[u8]) -> Format {
527 let mut src = Cursor::new(data);
528 Self::detect_format(&mut src)
529 }
530
531 /// Creates a Visitor containing only a single node called "`__ROOT__`" which will be the
532 /// current region of the visitor.
533 pub fn new() -> Self {
534 let mut nodes = Pool::new();
535 let root = nodes.spawn(VisitorNode::new("__ROOT__", Handle::NONE));
536 Self {
537 nodes,
538 unique_id_counter: 1,
539 type_name_map: FxHashMap::default(),
540 rc_map: FxHashMap::default(),
541 arc_map: FxHashMap::default(),
542 reading: false,
543 current_node: root,
544 root,
545 version: CURRENT_VERSION,
546 blackboard: Blackboard::new(),
547 flags: VisitorFlags::NONE,
548 }
549 }
550
551 fn gen_unique_id(&mut self) -> u64 {
552 let id = self.unique_id_counter;
553 self.unique_id_counter += 1;
554 id
555 }
556
557 fn rc_id<T>(&mut self, rc: &Rc<T>) -> (u64, bool)
558 where
559 T: Any,
560 {
561 if let Some(id) = self.rc_map.iter().find_map(|(id, ptr)| {
562 if Rc::as_ptr(ptr) as *const T == Rc::as_ptr(rc) {
563 Some(*id)
564 } else {
565 None
566 }
567 }) {
568 (id, false)
569 } else {
570 let id = self.gen_unique_id();
571 self.type_name_map.insert(id, std::any::type_name::<T>());
572 self.rc_map.insert(id, rc.clone());
573 (id, true)
574 }
575 }
576
577 fn arc_id<T>(&mut self, arc: &Arc<T>) -> (u64, bool)
578 where
579 T: Any + Send + Sync,
580 {
581 if let Some(id) = self.arc_map.iter().find_map(|(id, ptr)| {
582 if Arc::as_ptr(ptr) as *const T == Arc::as_ptr(arc) {
583 Some(*id)
584 } else {
585 None
586 }
587 }) {
588 (id, false)
589 } else {
590 let id = self.gen_unique_id();
591 self.type_name_map.insert(id, std::any::type_name::<T>());
592 self.arc_map.insert(id, arc.clone());
593 (id, true)
594 }
595 }
596
597 /// Tries to find a field by its name.
598 pub fn find_field(&mut self, name: &str) -> Option<&mut Field> {
599 self.nodes
600 .borrow_mut(self.current_node)
601 .fields
602 .iter_mut()
603 .find(|field| field.name == name)
604 }
605
606 /// Tries to find a node by its name.
607 pub fn find_node(&self, name: &str) -> Option<&VisitorNode> {
608 self.nodes.iter().find(|n| n.name == name)
609 }
610
611 /// True if this Visitor is changing the values that it visits. In other words,
612 /// `x.visit("MyValue", &mut visitor)` will result in `x` being mutated to match whatever value
613 /// is stored in `visitor`.
614 ///
615 /// False if this visitor is copying and storing the values that it visits. In other words,
616 /// `x.visit("MyValue", &mut visitor)` will result in `x` being unchanged, but `visitor` will
617 /// be mutated to store the value of `x` under the name "MyValue".
618 pub fn is_reading(&self) -> bool {
619 self.reading
620 }
621
622 fn current_node(&mut self) -> &mut VisitorNode {
623 self.nodes.borrow_mut(self.current_node)
624 }
625
626 /// Returns version number of the visitor.
627 pub fn version(&self) -> u32 {
628 self.version
629 }
630
631 /// Returns true of a region with the given name exists as a child of the current node.
632 /// When reading, `has_region` returning true means that `enter_region` will succeed.
633 /// When writing, `has_region` returning true means that `enter_region` will fail.
634 pub fn has_region(&self, name: &str) -> bool {
635 let node = self.nodes.borrow(self.current_node);
636 node.children
637 .iter()
638 .any(|child| self.nodes.borrow(*child).name == name)
639 }
640
641 /// If [Visitor::is_reading], find a node with the given name that is a child of the current
642 /// node, and return a Visitor for the found node. Return an error if no node with that name exists.
643 ///
644 /// If not reading, create a node with the given name as a chld of the current node, and return
645 /// a visitor for the new node. Return an error if a node with that name already exists.
646 pub fn enter_region(&mut self, name: &str) -> Result<RegionGuard, VisitError> {
647 let node = self.nodes.borrow(self.current_node);
648 if self.reading {
649 let mut region = Handle::NONE;
650 for child_handle in node.children.iter() {
651 let child = self.nodes.borrow(*child_handle);
652 if child.name == name {
653 region = *child_handle;
654 break;
655 }
656 }
657 if region.is_some() {
658 self.current_node = region;
659 Ok(RegionGuard(self))
660 } else {
661 Err(VisitError::RegionDoesNotExist(
662 self.breadcrumbs() + " > " + name,
663 ))
664 }
665 } else {
666 // Make sure that node does not exist already.
667 for child_handle in node.children.iter() {
668 let child = self.nodes.borrow(*child_handle);
669 if child.name == name {
670 return Err(VisitError::RegionAlreadyExists(name.to_owned()));
671 }
672 }
673
674 let node_handle = self.nodes.spawn(VisitorNode::new(name, self.current_node));
675 self.nodes
676 .borrow_mut(self.current_node)
677 .children
678 .push(node_handle);
679 self.current_node = node_handle;
680
681 Ok(RegionGuard(self))
682 }
683 }
684
685 /// Return a string representing all the regions from the root
686 /// to the current node.
687 pub fn breadcrumbs(&self) -> String {
688 self.build_breadcrumb(" > ")
689 }
690
691 /// Return a string representing all the regions from the root
692 /// to the current node, using the given string as the separator between
693 /// region names.
694 fn build_breadcrumb(&self, separator: &str) -> String {
695 let mut rev = String::new();
696 let mut handle = self.current_node;
697 loop {
698 let node = self.nodes.try_borrow(handle);
699 let Some(node) = node else {
700 break;
701 };
702 if !rev.is_empty() {
703 rev.extend(separator.chars().rev());
704 }
705 rev.extend(node.name.chars().rev());
706 handle = node.parent;
707 }
708 rev.chars().rev().collect()
709 }
710
711 /// The name of the current region. This should never be None if the Visitor is operating normally,
712 /// because there should be no way to leave the initial `__ROOT__` region.
713 pub fn current_region(&self) -> Option<&str> {
714 self.nodes
715 .try_borrow(self.current_node)
716 .map(|n| n.name.as_str())
717 }
718
719 fn leave_region(&mut self) -> VisitResult {
720 self.current_node = self.nodes.borrow(self.current_node).parent;
721 if self.current_node.is_none() {
722 Err(VisitError::NoActiveNode)
723 } else {
724 Ok(())
725 }
726 }
727
728 /// Get the content of the current node in human-readable form.
729 pub fn debug(&self) -> String {
730 let mut w = Cursor::new(Vec::<u8>::new());
731 let result = self.debug_to(&mut w);
732 match result {
733 Ok(()) => String::from_utf8_lossy(w.get_ref()).into_owned(),
734 Err(err) => err.to_string(),
735 }
736 }
737
738 /// Write the content of the current node in human-readable form.
739 pub fn debug_to<W: Write>(&self, w: &mut W) -> VisitResult {
740 let writer = AsciiWriter::default();
741 writer.write_node(self, &self.nodes[self.current_node], 0, w)?;
742 writeln!(w)?;
743 w.flush()?;
744 Ok(())
745 }
746
747 /// Create a string containing all the data of this Visitor in ascii form. The string is
748 /// formatted to be human-readable with each node on its own line and tabs to indent child nodes.
749 pub fn save_ascii_to_string(&self) -> String {
750 let mut cursor = Cursor::<Vec<u8>>::default();
751 self.save_ascii_to_memory(&mut cursor).unwrap();
752 String::from_utf8(cursor.into_inner()).unwrap()
753 }
754
755 /// Create a string containing all the data of this Visitor in ascii form and saves it to the given
756 /// path. The string is formatted to be human-readable with each node on its own line and tabs
757 /// to indent child nodes.
758 pub fn save_ascii_to_file(&self, path: impl AsRef<Path>) -> VisitResult {
759 let mut writer = BufWriter::new(File::create(path)?);
760 let text = self.save_ascii_to_string();
761 writer.write_all(text.as_bytes())?;
762 Ok(())
763 }
764
765 /// Create a string containing all the data of this Visitor in ascii form and writes it to the
766 /// given writer. The string is formatted to be human-readable with each node on its own line
767 /// and tabs to indent child nodes.
768 pub fn save_ascii_to_memory(&self, mut dest: impl Write) -> VisitResult {
769 let writer = AsciiWriter::default();
770 writer.write(self, &mut dest)
771 }
772
773 /// Tries to create a visitor from the given data. The returned instance can then be used to
774 /// deserialize some data.
775 pub fn load_ascii_from_memory(data: &[u8]) -> Result<Self, VisitError> {
776 let mut src = Cursor::new(data);
777 let mut reader = AsciiReader::new(&mut src);
778 reader.read()
779 }
780
781 /// Tries to create a visitor from the given file. The returned instance can then be used to
782 /// deserialize some data.
783 pub async fn load_ascii_from_file(path: impl AsRef<Path>) -> Result<Self, VisitError> {
784 Self::load_ascii_from_memory(&io::load_file(path).await?)
785 }
786
787 /// Write the data of this Visitor to the given writer. Begin by writing [Visitor::MAGIC_BINARY_CURRENT].
788 pub fn save_binary_to_memory(&self, mut dest: impl Write) -> VisitResult {
789 let writer = BinaryWriter::default();
790 writer.write(self, &mut dest)
791 }
792
793 /// Encode the data of this visitor into bytes and push the bytes into the given `Vec<u8>`.
794 /// Begin by writing [Visitor::MAGIC_BINARY_CURRENT].
795 pub fn save_binary_to_vec(&self) -> Result<Vec<u8>, VisitError> {
796 let mut writer = Cursor::new(Vec::new());
797 self.save_binary_to_memory(&mut writer)?;
798 Ok(writer.into_inner())
799 }
800
801 /// Create a file at the given path and write the data of this visitor into that file in a
802 /// non-human-readable binary format so that the data can be reconstructed using [Visitor::load_binary_from_file].
803 /// Begin by writing [Visitor::MAGIC_BINARY_CURRENT].
804 pub fn save_binary_to_file(&self, path: impl AsRef<Path>) -> VisitResult {
805 let writer = BufWriter::new(File::create(path)?);
806 self.save_binary_to_memory(writer)
807 }
808
809 /// Create a visitor by reading data from the file at the given path, assuming that the file was
810 /// created using [Visitor::save_binary_to_file]. Return a [VisitError::NotSupportedFormat] if
811 /// [Visitor::MAGIC_BINARY_CURRENT] is not the first bytes read from the file.
812 pub async fn load_binary_from_file(path: impl AsRef<Path>) -> Result<Self, VisitError> {
813 Self::load_binary_from_memory(&io::load_file(path).await?)
814 }
815
816 /// Create a visitor by decoding data from the given byte slice, assuming that the bytes are in
817 /// the format that would be produced by [Visitor::save_binary_to_vec]. Return a
818 /// [VisitError::NotSupportedFormat] if [Visitor::MAGIC_BINARY_CURRENT] is not the first bytes read from
819 /// the slice.
820 pub fn load_binary_from_memory(data: &[u8]) -> Result<Self, VisitError> {
821 let mut src = Cursor::new(data);
822 let mut reader = BinaryReader::new(&mut src);
823 reader.read()
824 }
825
826 /// Tries to load a visitor from the given file. This method automatically detects a format of
827 /// the incoming data (binary or ASCII) and tries to load it.
828 pub async fn load_from_file(path: impl AsRef<Path>) -> Result<Self, VisitError> {
829 Self::load_from_memory(&io::load_file(path).await?)
830 }
831
832 /// Tries to load a visitor from the given data. This method automatically detects a format of
833 /// the incoming data (binary or ASCII) and tries to load it.
834 pub fn load_from_memory(data: &[u8]) -> Result<Self, VisitError> {
835 match Self::detect_format_from_slice(data) {
836 Format::Unknown => Err(VisitError::NotSupportedFormat),
837 Format::Binary => Self::load_binary_from_memory(data),
838 Format::Ascii => Self::load_ascii_from_memory(data),
839 }
840 }
841}
842
843#[cfg(test)]
844mod test {
845 use crate::visitor::{BinaryBlob, Visit, VisitResult, Visitor};
846 use nalgebra::{
847 Matrix2, Matrix3, Matrix4, UnitComplex, UnitQuaternion, Vector2, Vector3, Vector4,
848 };
849 use std::sync::Arc;
850 use std::{fs::File, io::Write, path::Path, rc, rc::Rc, sync};
851 use uuid::{uuid, Uuid};
852
853 #[derive(Visit, Default, PartialEq, Debug)]
854 pub struct Model {
855 data: u64,
856 }
857
858 #[derive(Default, PartialEq, Debug)]
859 pub struct Texture {
860 data: Vec<u8>,
861 }
862
863 impl Visit for Texture {
864 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
865 let mut region = visitor.enter_region(name)?;
866 let mut proxy = BinaryBlob {
867 vec: &mut self.data,
868 };
869 proxy.visit("Data", &mut region)?;
870 Ok(())
871 }
872 }
873
874 #[allow(dead_code)]
875 #[derive(Visit, PartialEq, Debug)]
876 pub enum ResourceKind {
877 Unknown,
878 Model(Model),
879 Texture(Texture),
880 }
881
882 impl Default for ResourceKind {
883 fn default() -> Self {
884 Self::Unknown
885 }
886 }
887
888 #[derive(Visit, PartialEq, Debug)]
889 struct Resource {
890 kind: ResourceKind,
891 data: u16,
892 }
893
894 impl Resource {
895 fn new(kind: ResourceKind) -> Self {
896 Self { kind, data: 0 }
897 }
898 }
899
900 impl Default for Resource {
901 fn default() -> Self {
902 Self {
903 kind: ResourceKind::Unknown,
904 data: 0,
905 }
906 }
907 }
908
909 #[derive(Default, Visit, Debug)]
910 struct Weaks {
911 weak_resource_arc: Option<sync::Weak<Resource>>,
912 weak_resource_rc: Option<rc::Weak<Resource>>,
913 }
914
915 impl PartialEq for Weaks {
916 fn eq(&self, other: &Self) -> bool {
917 self.weak_resource_arc.as_ref().and_then(|r| r.upgrade())
918 == other.weak_resource_arc.as_ref().and_then(|r| r.upgrade())
919 && self.weak_resource_rc.as_ref().and_then(|r| r.upgrade())
920 == other.weak_resource_rc.as_ref().and_then(|r| r.upgrade())
921 }
922 }
923
924 #[derive(Default, Visit, Debug, PartialEq)]
925 struct Foo {
926 boolean: bool,
927 num_u8: u8,
928 num_i8: i8,
929 num_u16: u16,
930 num_i16: i16,
931 num_u32: u32,
932 num_i32: i32,
933 num_u64: u64,
934 num_i64: i64,
935 num_f32: f32,
936 num_f64: f64,
937 quat: UnitQuaternion<f32>,
938 mat4: Matrix4<f32>,
939 array: Vec<u8>,
940 mat3: Matrix3<f32>,
941 uuid: Uuid,
942 complex: UnitComplex<f32>,
943 mat2: Matrix2<f32>,
944
945 vec2_u8: Vector2<u8>,
946 vec2_i8: Vector2<i8>,
947 vec2_u16: Vector2<u16>,
948 vec2_i16: Vector2<i16>,
949 vec2_u32: Vector2<u32>,
950 vec2_i32: Vector2<i32>,
951 vec2_u64: Vector2<u64>,
952 vec2_i64: Vector2<i64>,
953
954 vec3_u8: Vector3<u8>,
955 vec3_i8: Vector3<i8>,
956 vec3_u16: Vector3<u16>,
957 vec3_i16: Vector3<i16>,
958 vec3_u32: Vector3<u32>,
959 vec3_i32: Vector3<i32>,
960 vec3_u64: Vector3<u64>,
961 vec3_i64: Vector3<i64>,
962
963 vec4_u8: Vector4<u8>,
964 vec4_i8: Vector4<i8>,
965 vec4_u16: Vector4<u16>,
966 vec4_i16: Vector4<i16>,
967 vec4_u32: Vector4<u32>,
968 vec4_i32: Vector4<i32>,
969 vec4_u64: Vector4<u64>,
970 vec4_i64: Vector4<i64>,
971
972 string: String,
973
974 vec2_f32: Vector2<f32>,
975 vec2_f64: Vector2<f64>,
976 vec3_f32: Vector3<f32>,
977 vec3_f64: Vector3<f64>,
978 vec4_f32: Vector4<f32>,
979 vec4_f64: Vector4<f64>,
980
981 shared_resource: Option<Rc<Resource>>,
982 shared_resource_arc: Option<Arc<Resource>>,
983 weaks: Weaks,
984 }
985
986 impl Foo {
987 fn new(resource: Rc<Resource>, arc_resource: Arc<Resource>) -> Self {
988 Self {
989 boolean: true,
990 num_u8: 123,
991 num_i8: -123,
992 num_u16: 123,
993 num_i16: -123,
994 num_u32: 123,
995 num_i32: -123,
996 num_u64: 123,
997 num_i64: -123,
998 num_f32: 123.321,
999 num_f64: 123.321,
1000 quat: UnitQuaternion::from_euler_angles(1.0, 2.0, 3.0),
1001 mat4: Matrix4::new_scaling(3.0),
1002 array: vec![1, 2, 3, 4],
1003 mat3: Matrix3::new_scaling(3.0),
1004 uuid: uuid!("51a582c0-30d7-4dbc-b5a0-da8ea186edce"),
1005 complex: UnitComplex::new(0.0),
1006 mat2: Matrix2::new_scaling(2.0),
1007 vec2_u8: Vector2::new(1, 2),
1008 vec2_i8: Vector2::new(-1, -2),
1009 vec2_u16: Vector2::new(1, 2),
1010 vec2_i16: Vector2::new(-1, -2),
1011 vec2_u32: Vector2::new(1, 2),
1012 vec2_i32: Vector2::new(-1, -2),
1013 vec2_u64: Vector2::new(1, 2),
1014 vec2_i64: Vector2::new(-1, -2),
1015 vec3_u8: Vector3::new(1, 2, 3),
1016 vec3_i8: Vector3::new(-1, -2, -3),
1017 vec3_u16: Vector3::new(1, 2, 3),
1018 vec3_i16: Vector3::new(-1, -2, -3),
1019 vec3_u32: Vector3::new(1, 2, 3),
1020 vec3_i32: Vector3::new(-1, -2, -3),
1021 vec3_u64: Vector3::new(1, 2, 3),
1022 vec3_i64: Vector3::new(-1, -2, -3),
1023 vec4_u8: Vector4::new(1, 2, 3, 4),
1024 vec4_i8: Vector4::new(-1, -2, -3, -4),
1025 vec4_u16: Vector4::new(1, 2, 3, 4),
1026 vec4_i16: Vector4::new(-1, -2, -3, -4),
1027 vec4_u32: Vector4::new(1, 2, 3, 4),
1028 vec4_i32: Vector4::new(-1, -2, -3, -4),
1029 vec4_u64: Vector4::new(1, 2, 3, 4),
1030 vec4_i64: Vector4::new(-1, -2, -3, -4),
1031 vec2_f32: Vector2::new(123.321, 234.432),
1032 vec2_f64: Vector2::new(123.321, 234.432),
1033 vec3_f32: Vector3::new(123.321, 234.432, 567.765),
1034 vec3_f64: Vector3::new(123.321, 234.432, 567.765),
1035 vec4_f32: Vector4::new(123.321, 234.432, 567.765, 890.098),
1036 vec4_f64: Vector4::new(123.321, 234.432, 567.765, 890.098),
1037 weaks: Weaks {
1038 weak_resource_arc: Some(Arc::downgrade(&arc_resource)),
1039 weak_resource_rc: Some(Rc::downgrade(&resource)),
1040 },
1041 shared_resource: Some(resource),
1042 shared_resource_arc: Some(arc_resource),
1043 string: "This Is A String With Reserved Characters <>:;{}[\\\\\\\\\\] \
1044 and \"quotes\" many \"\"\"quotes\"\"\"\" and line\nbreak\ttabs\t\t\t\t"
1045 .to_string(),
1046 }
1047 }
1048 }
1049
1050 fn resource() -> Rc<Resource> {
1051 Rc::new(Resource::new(ResourceKind::Model(Model { data: 555 })))
1052 }
1053
1054 fn resource_arc() -> Arc<Resource> {
1055 Arc::new(Resource::new(ResourceKind::Model(Model { data: 555 })))
1056 }
1057
1058 fn objects(resource: Rc<Resource>, arc_resource: Arc<Resource>) -> Vec<Foo> {
1059 vec![
1060 Foo::new(resource.clone(), arc_resource.clone()),
1061 Foo::new(resource, arc_resource),
1062 ]
1063 }
1064
1065 fn serialize() -> Visitor {
1066 let mut resource = resource();
1067 let mut resource_arc = resource_arc();
1068 let mut objects = objects(resource.clone(), resource_arc.clone());
1069
1070 let mut visitor = Visitor::new();
1071 resource.visit("SharedResource", &mut visitor).unwrap();
1072 resource_arc
1073 .visit("SharedResourceArc", &mut visitor)
1074 .unwrap();
1075 objects.visit("Objects", &mut visitor).unwrap();
1076 visitor
1077 }
1078
1079 #[test]
1080 fn visitor_test_binary() {
1081 let path = Path::new("test.bin");
1082
1083 // Save
1084 {
1085 let visitor = serialize();
1086
1087 visitor.save_binary_to_file(path).unwrap();
1088 if let Ok(mut file) = File::create(Path::new("test.txt")) {
1089 file.write_all(visitor.save_ascii_to_string().as_bytes())
1090 .unwrap();
1091 }
1092 }
1093
1094 // Load
1095 {
1096 let expected_resource = resource();
1097 let expected_resource_arc = resource_arc();
1098 let expected_objects =
1099 objects(expected_resource.clone(), expected_resource_arc.clone());
1100
1101 let mut visitor = futures::executor::block_on(Visitor::load_from_file(path)).unwrap();
1102 let mut resource: Rc<Resource> = Rc::new(Default::default());
1103 resource.visit("SharedResource", &mut visitor).unwrap();
1104 assert_eq!(resource, expected_resource);
1105
1106 let mut resource_arc: Arc<Resource> = Arc::new(Default::default());
1107 resource_arc
1108 .visit("SharedResourceArc", &mut visitor)
1109 .unwrap();
1110 assert_eq!(resource_arc, expected_resource_arc);
1111
1112 let mut objects: Vec<Foo> = Vec::new();
1113 objects.visit("Objects", &mut visitor).unwrap();
1114 assert_eq!(objects, expected_objects);
1115 }
1116 }
1117
1118 #[test]
1119 fn visitor_test_ascii() {
1120 let path = Path::new("test_ascii.txt");
1121
1122 // Save
1123 {
1124 let visitor = serialize();
1125 visitor.save_ascii_to_file(path).unwrap();
1126 }
1127
1128 // Load
1129 {
1130 let expected_resource = resource();
1131 let expected_resource_arc = resource_arc();
1132 let expected_objects =
1133 objects(expected_resource.clone(), expected_resource_arc.clone());
1134
1135 let mut visitor =
1136 futures::executor::block_on(Visitor::load_ascii_from_file(path)).unwrap();
1137 let mut resource: Rc<Resource> = Rc::new(Default::default());
1138 resource.visit("SharedResource", &mut visitor).unwrap();
1139 assert_eq!(resource, expected_resource);
1140
1141 let mut resource_arc: Arc<Resource> = Arc::new(Default::default());
1142 resource_arc
1143 .visit("SharedResourceArc", &mut visitor)
1144 .unwrap();
1145 assert_eq!(resource_arc, expected_resource_arc);
1146
1147 let mut objects: Vec<Foo> = Vec::new();
1148 objects.visit("Objects", &mut visitor).unwrap();
1149 assert_eq!(objects, expected_objects);
1150 }
1151 }
1152}