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