savefile/
lib.rs

1#![allow(incomplete_features)]
2#![recursion_limit = "256"]
3#![cfg_attr(feature = "nightly", feature(specialization))]
4#![deny(missing_docs)]
5#![deny(warnings)]
6#![allow(clippy::bool_comparison)]
7#![allow(clippy::box_default)]
8#![allow(clippy::needless_question_mark)]
9#![allow(clippy::needless_return)]
10#![allow(clippy::manual_try_fold)] //Clean this up some day
11#![allow(clippy::needless_range_loop)]
12#![allow(clippy::len_zero)]
13#![allow(clippy::new_without_default)]
14#![allow(renamed_and_removed_lints)]
15#![allow(clippy::transmute_num_to_bytes)] //Clean this up some day
16#![allow(clippy::manual_memcpy)] //Clean up some day
17#![allow(clippy::needless_late_init)]
18#![allow(clippy::uninlined_format_args)]
19#![allow(clippy::io_other_error)]
20
21/*!
22This is the documentation for `savefile`
23
24# Introduction
25
26Savefile is a rust library to conveniently, quickly and correctly
27serialize and deserialize arbitrary rust structs and enums into
28an efficient and compact binary version controlled format.
29
30The design use case is any application that needs to save large
31amounts of data to disk, and support loading files from previous
32versions of that application (but not from later versions!).
33
34
35# Example
36
37Here is a small example where data about a player in a hypothetical
38computer game is saved to disk using Savefile.
39
40
41
42```
43use savefile::prelude::*;
44use savefile_derive::Savefile;
45
46# #[cfg(miri)] fn main() {}
47# #[cfg(not(miri))]
48# fn main() {
49
50
51#[derive(Savefile)]
52struct Player {
53    name : String,
54    strength : u32,
55    inventory : Vec<String>,
56}
57
58fn save_player(player:&Player) {
59    save_file("save.bin", 0, player).unwrap();
60}
61
62fn load_player() -> Player {
63    load_file("save.bin", 0).unwrap()
64}
65
66fn main() {
67    let player = Player { name: "Steve".to_string(), strength: 42,
68        inventory: vec!(
69            "wallet".to_string(),
70            "car keys".to_string(),
71            "glasses".to_string())};
72
73    save_player(&player);
74
75    let reloaded_player = load_player();
76
77    assert_eq!(reloaded_player.name,"Steve".to_string());
78}
79
80# }
81```
82
83# Limitations of Savefile
84
85Savefile does make a few tradeoffs:
86
871: It only supports the "savefile-format". It does not support any sort of pluggable
88architecture with different formats. This format is generally pretty 'raw', data is mostly
89formatted the same way as it is in RAM. There is support for bzip2, but this is just a simple
90post-processing step.
91
922: It does not support serializing 'graphs'. I.e, it does not have a concept of object identity,
93and cannot handle situations where the same object is reachable through many paths. If two
94objects both have a reference to a common object, it will be serialized twice and deserialized
95twice.
96
973: Since it doesn't support 'graphs', it doesn't do well with recursive data structures. When
98schema serialization is activated (which is the default), it also doesn't support 'potentially
99recursive' data structures. I.e, serializing a tree-object where the same node type can occur
100on different levels is not possible, even if the actual links in the tree do not cause any cycles.
101This is because the serialized schema is very detailed, and tries to describe exactly what
102types may be contained in each node. In a tree, it will determine that children of the node
103may be another node, which may itself have children of the same type, which may have children
104of the same type, and so on.
105
106# Handling old versions
107
108Let's expand the above example, by creating a 2nd version of the Player struct. Let's say
109you decide that your game mechanics don't really need to track the strength of the player, but
110you do wish to have a set of skills per player as well as the inventory.
111
112Mark the struct like so:
113
114
115```
116use savefile::prelude::*;
117use std::path::Path;
118use savefile_derive::Savefile;
119# #[cfg(miri)] fn main() {}
120# #[cfg(not(miri))]
121# fn main() {
122
123const GLOBAL_VERSION:u32 = 1;
124#[derive(Savefile)]
125struct Player {
126    name : String,
127    #[savefile_versions="0..0"] //Only version 0 had this field
128    strength : Removed<u32>,
129    inventory : Vec<String>,
130    #[savefile_versions="1.."] //Only versions 1 and later have this field
131    skills : Vec<String>,
132}
133
134fn save_player(file:&'static str, player:&Player) {
135    // Save current version of file.
136    save_file(file, GLOBAL_VERSION, player).unwrap();
137}
138
139fn load_player(file:&'static str) -> Player {
140    // The GLOBAL_VERSION means we have that version of our data structures,
141    // but we can still load any older version.
142    load_file(file, GLOBAL_VERSION).unwrap()
143}
144
145fn main() {
146    if Path::new("save.bin").exists() == false { /* error handling */ return;}
147
148    let mut player = load_player("save.bin"); //Load from previous save
149    assert_eq!("Steve",&player.name); //The name from the previous version saved will remain
150    assert_eq!(0,player.skills.len()); //Skills didn't exist when this was saved
151    player.skills.push("Whistling".to_string());
152    save_player("newsave.bin", &player); //The version saved here will have the vec of skills
153}
154# }
155```
156
157
158# Behind the scenes
159
160For Savefile to be able to load and save a type T, that type must implement traits
161[crate::WithSchema], [crate::Packed], [crate::Serialize] and [crate::Deserialize] .
162The custom derive macro Savefile derives all of these.
163
164You can also implement these traits manually. Manual implementation can be good for:
165
1661: Complex types for which the Savefile custom derive function does not work. For
167example, trait objects or objects containing pointers.
168
1692: Objects for which not all fields should be serialized, or which need complex
170initialization (like running arbitrary code during deserialization).
171
172Note that the four trait implementations for a particular type must be in sync.
173That is, the Serialize and Deserialize traits must follow the schema defined
174by the WithSchema trait for the type, and if the Packed trait promises a packed
175layout, then the format produced by Serialize and Deserialze *must* exactly match
176the in-memory format.
177
178## WithSchema
179
180The [crate::WithSchema] trait represents a type which knows which data layout it will have
181when saved. Savefile includes the schema in the serialized data by default, but this can be disabled
182by using the `save_noschema` function. When reading a file with unknown schema, it
183is up to the user to guarantee that the file is actually of the correct format.
184
185## Serialize
186
187The [crate::Serialize] trait represents a type which knows how to write instances of itself to
188a `Serializer`.
189
190## Deserialize
191
192The [crate::Deserialize] trait represents a type which knows how to read instances of itself from a `Deserializer`.
193
194## Packed
195
196The [crate::Packed] trait has an optional method that can be used to promise that the
197in-memory format is identical to the savefile disk representation. If this is true,
198instances of the type can be serialized by simply writing all the bytes in one go,
199rather than having to visit individual fields. This can speed up saves significantly.
200
201
202# Rules for managing versions
203
204The basic rule is that the Deserialize trait implementation must be able to deserialize data from any previous version.
205
206The WithSchema trait implementation must be able to return the schema for any previous verison.
207
208The Serialize trait implementation only needs to support the latest version, for savefile itself
209to work. However, for SavefileAbi to work, Serialize should support writing old versions.
210The savefile-derive macro does support serializing old versions, with some limitations.
211
212
213# Versions and derive
214
215The derive macro used by Savefile supports multiple versions of structs. To make this work,
216you have to add attributes whenever fields are removed, added or have their types changed.
217
218When adding or removing fields, use the #\[savefile_versions] attribute.
219
220The syntax is one of the following:
221
222```text
223#[savefile_versions = "N.."]  //A field added in version N
224#[savefile_versions = "..N"]  //A field removed in version N+1. That is, it existed up to and including version N.
225#[savefile_versions = "N..M"] //A field that was added in version N and removed in M+1. That is, a field which existed in versions N .. up to and including M.
226```
227
228Removed fields must keep their deserialization type. This is easiest accomplished by substituting their previous type
229using the `Removed<T>` type. `Removed<T>` uses zero space in RAM, but deserializes equivalently to T (with the
230result of the deserialization thrown away).
231
232Savefile tries to validate that the `Removed<T>` type is used correctly. This validation is based on string
233matching, so it may trigger false positives for other types named Removed. Please avoid using a type with
234such a name. If this becomes a problem, please file an issue on github.
235
236Using the #\[savefile_versions] tag is critically important. If this is messed up, data corruption is likely.
237
238When a field is added, its type must implement the Default trait (unless the default_val or default_fn attributes
239are used).
240
241More about the savefile_default_val, default_fn and savefile_versions_as attributes below.
242
243## The savefile_versions attribute
244
245Rules for using the #\[savefile_versions] attribute:
246
247 * You must keep track of what the current version of your data is. Let's call this version N.
248 * You may only save data using version N (supply this number when calling `save`)
249 * When data is loaded, you must supply version N as the memory-version number to `load`. Load will
250   adapt the deserialization operation to the version of the serialized data.
251 * The version number N is "global" (called GLOBAL_VERSION in the previous source example). All components of the saved data must have the same version.
252 * Whenever changes to the data are to be made, the global version number N must be increased.
253 * You may add a new field to your structs, iff you also give it a #\[savefile_versions = "N.."] attribute. N must be the new version of your data.
254 * You may remove a field from your structs.
255    - If previously it had no #\[savefile_versions] attribute, you must add a #\[savefile_versions = "..N-1"] attribute.
256    - If it already had an attribute #[savefile_versions = "M.."], you must close its version interval using the current version of your data: #\[savefile_versions = "M..N-1"].
257    - Whenever a field is removed, its type must simply be changed to `Removed<T>` where T is its previous type.
258    - You may never completely remove items from your structs. Doing so removes backward-compatibility with that version. This will be detected at load.
259    - For example, if you remove a field in version 3, you should add a #\[savefile_versions="..2"] attribute.
260 * You may not change the type of a field in your structs, except when using the savefile_versions_as-macro.
261 * You may add enum variants in future versions, but you may not change the size of the discriminant.
262
263
264## The savefile_default_val attribute
265
266The default_val attribute is used to provide a custom default value for
267primitive types, when fields are added.
268
269Example:
270
271```
272# use savefile_derive::Savefile;
273
274#[derive(Savefile)]
275struct SomeType {
276 old_field: u32,
277 #[savefile_default_val="42"]
278 #[savefile_versions="1.."]
279 new_field: u32
280}
281
282# fn main() {}
283
284```
285
286In the above example, the field `new_field` will have the value 42 when
287deserializing from version 0 of the protocol. If the default_val attribute
288is not used, new_field will have u32::default() instead, which is 0.
289
290The default_val attribute only works for simple types.
291
292## The savefile_default_fn attribute
293
294The default_fn attribute allows constructing more complex values as defaults.
295
296```
297# use savefile_derive::Savefile;
298
299fn make_hello_pair() -> (String,String) {
300 ("Hello".to_string(),"World".to_string())
301}
302#[derive(Savefile)]
303struct SomeType {
304 old_field: u32,
305 #[savefile_default_fn="make_hello_pair"]
306 #[savefile_versions="1.."]
307 new_field: (String,String)
308}
309# fn main() {}
310
311```
312
313## The savefile_ignore attribute
314
315The savefile_ignore attribute can be used to exclude certain fields from serialization. They still
316need to be constructed during deserialization (of course), so you need to use one of the
317default-attributes to make sure the field can be constructed. If none of the  default-attributes
318(described above) are used, savefile will attempt to use the Default trait.
319
320Here is an example, where a cached value is not to be deserialized.
321In this example, the value will be 0.0 after deserialization, regardless
322of the value when serializing.
323
324```
325# use savefile_derive::Savefile;
326
327#[derive(Savefile)]
328struct IgnoreExample {
329 a: f64,
330 b: f64,
331 #[savefile_ignore]
332 cached_product: f64
333}
334# fn main() {}
335
336```
337
338savefile_ignore does not stop the generator from generating an implementation for [Introspect] for the given field. To stop
339this as well, also supply the attribute savefile_introspect_ignore .
340
341## The savefile_versions_as attribute
342
343The savefile_versions_as attribute can be used to support changing the type of a field.
344
345Let's say the first version of our protocol uses the following struct:
346
347```
348# use savefile_derive::Savefile;
349
350#[derive(Savefile)]
351struct Employee {
352 name : String,
353 phone_number : u64
354}
355# fn main() {}
356
357```
358
359After a while, we realize that u64 is a bad choice for datatype for a phone number,
360since it can't represent a number with leading 0, and also can't represent special characters
361which sometimes appear in phone numbers, like '+' or '-' etc.
362
363So, we change the type of phone_number to String:
364
365```
366# use savefile_derive::Savefile;
367
368fn convert(phone_number:u64) -> String {
369 phone_number.to_string()
370}
371#[derive(Savefile)]
372struct Employee {
373 name : String,
374 #[savefile_versions_as="0..0:convert:u64"]
375 #[savefile_versions="1.."]
376 phone_number : String
377}
378# fn main() {}
379
380```
381
382This will cause version 0 of the protocol to be deserialized expecting a u64 for the phone number,
383which will then be converted using the provided function `convert` into a String.
384
385Note, that conversions which are supported by the From trait are done automatically, and the
386function need not be specified in these cases.
387
388Let's say we have the following struct:
389
390```
391# use savefile_derive::Savefile;
392
393#[derive(Savefile)]
394struct Racecar {
395 max_speed_kmh : u8,
396}
397# fn main() {}
398```
399
400We realize that we need to increase the range of the max_speed_kmh variable, and change it like this:
401
402```
403# use savefile_derive::Savefile;
404
405#[derive(Savefile)]
406struct Racecar {
407 #[savefile_versions_as="0..0:u8"]
408 #[savefile_versions="1.."]
409 max_speed_kmh : u16,
410}
411# fn main() {}
412```
413
414Note that in this case we don't need to tell Savefile how the deserialized u8 is to be converted
415to an u16.
416
417
418
419# Speeding things up
420Note: This entire chapter can safely be ignored. Savefile will, in most circumstances,
421perform very well without any special work by the programmer.
422
423Continuing the example from previous chapters, let's say we want to add a list of all
424positions that our player have visited, so that we can provide an instant-replay function to
425our game. The list can become really long, so we want to make sure that the overhead when
426serializing this is as low as possible.
427
428
429```
430use savefile::prelude::*;
431use std::path::Path;
432use savefile_derive::Savefile;
433# #[cfg(miri)] fn main() {}
434# #[cfg(not(miri))]
435# fn main() {
436
437
438#[derive(Clone, Copy, Savefile)]
439#[repr(C)] // Memory layout will become equal to savefile disk format - optimization possible!
440struct Position {
441 x : u32,
442 y : u32,
443}
444
445const GLOBAL_VERSION:u32 = 2;
446#[derive(Savefile)]
447struct Player {
448 name : String,
449 #[savefile_versions="0..0"] //Only version 0 had this field
450 strength : Removed<u32>,
451 inventory : Vec<String>,
452 #[savefile_versions="1.."] //Only versions 1 and later have this field
453 skills : Vec<String>,
454 #[savefile_versions="2.."] //Only versions 2 and later have this field
455 history : Vec<Position>
456}
457
458fn save_player(file:&'static str, player:&Player) {
459 save_file(file, GLOBAL_VERSION, player).unwrap();
460}
461
462fn load_player(file:&'static str) -> Player {
463 load_file(file, GLOBAL_VERSION).unwrap()
464}
465
466fn main() {
467
468 if Path::new("newsave.bin").exists() == false { /* error handling */ return;}
469
470 let mut player = load_player("newsave.bin"); //Load from previous save
471 player.history.push(Position{x:1,y:1});
472 player.history.push(Position{x:2,y:1});
473 player.history.push(Position{x:2,y:2});
474 save_player("newersave.bin", &player);
475}
476# }
477```
478
479Savefile can speed up serialization of arrays/vectors of certain types, when it can
480detect that the type consists entirely of packed plain binary data.
481
482The above will be very fast, even if 'history' contains millions of position-instances.
483
484
485Savefile has a trait [crate::Packed] that must be implemented for each T. The savefile-derive
486macro implements this automatically.
487
488This trait has an unsafe function [crate::Packed::repr_c_optimization_safe] which answers the question:
489 "Is this type such that it can safely be copied byte-per-byte"?
490Answering yes for a specific type T, causes savefile to optimize serialization of `Vec<T>` into being
491a very fast, raw memory copy.
492The exact criteria is that the in-memory representation of the type must be identical to what
493the Serialize trait does for the type.
494
495
496Most of the time, the user doesn't need to implement Packed, as it can be derived automatically
497by the savefile derive macro.
498
499However, implementing it manually can be done, with care. You, as implementor of the `Packed`
500trait take full responsibility that all the following rules are upheld:
501
502* The type T is Copy
503* The in-memory representation of T is identical to the savefile disk format.
504* The host platform is little endian. The savefile disk format uses little endian.
505* The type is represented in memory in an ordered, packed representation. Savefile is not
506
507clever enough to inspect the actual memory layout and adapt to this, so the memory representation
508has to be all the types of the struct fields in a consecutive sequence without any gaps. Note
509that the #\[repr(C)] attribute is not enough to do this - it will include padding if needed for alignment
510reasons. You should not use #\[repr(packed)], since that may lead to unaligned struct fields.
511Instead, you should use #\[repr(C)] combined with manual padding, if necessary.
512If the type is an enum, it must be #\[repr(u8)], #\[repr(u16)] or #\[repr(u32)].
513Enums with fields are not presently optimized.
514
515
516Regarding padding, don't do:
517```
518#[repr(C)]
519struct Bad {
520 f1 : u8,
521 f2 : u32,
522}
523```
524Since the compiler is likely to insert 3 bytes of padding after f1, to ensure that f2 is aligned to 4 bytes.
525
526Instead, do this:
527
528```
529#[repr(C)]
530struct Good {
531 f1 : u8,
532 pad1 :u8,
533 pad2 :u8,
534 pad3 :u8,
535 f2 : u32,
536}
537```
538
539And simpy don't use the pad1, pad2 and pad3 fields. Note, at time of writing, Savefile requires that the struct
540be free of all padding. Even padding at the end is not allowed. This means that the following does not work:
541
542```
543#[repr(C)]
544struct Bad2 {
545 f1 : u32,
546 f2 : u8,
547}
548```
549This restriction may be lifted at a later time.
550
551When it comes to enums, there are requirements to enable the optimization:
552
553This enum is not optimizable, since it doesn't have a defined discrminant size:
554```
555enum BadEnum1 {
556Variant1,
557Variant2,
558}
559```
560
561This will be optimized:
562```
563#[repr(u8)]
564enum GoodEnum1 {
565Variant1,
566Variant2,
567}
568```
569
570This also:
571```
572#[repr(u8)]
573enum GoodEnum2 {
574Variant1(u8),
575Variant2(u8),
576}
577```
578
579However, the following will not be optimized, since there will be padding after Variant1.
580To have the optimization enabled, all variants must be the same size, and without any padding.
581
582```
583#[repr(u8)]
584enum BadEnum2 {
585Variant1,
586Variant2(u8),
587}
588```
589
590This can be fixed with manual padding:
591```
592#[repr(u8)]
593enum BadEnum2Fixed {
594Variant1{padding:u8},
595Variant2(u8),
596}
597```
598
599
600This will be optimized:
601```
602#[repr(u8)]
603enum GoodEnum3 {
604Variant1{x:u8,y:u16,z:u16,w:u16},
605Variant2{x:u8,y:u16,z:u32},
606}
607```
608
609However, the following will not be:
610```
611#[repr(u8,C)]
612enum BadEnum3 {
613Variant1{x:u8,y:u16,z:u16,w:u16},
614Variant2{x:u8,y:u16,z:u32},
615}
616```
617The reason is that the format `#[repr(u8,C)]` will layout the struct as if the fields of each
618variant were a C-struct. This means alignment of Variant2 will be 4, and the offset of 'x' will be 4.
619This in turn means there will be padding between the discriminant and the fields, making the optimization
620impossible.
621
622
623### The attribute savefile_require_fast
624
625When deriving the savefile-traits automatically, specify the attribute ```#[savefile_require_fast]``` to require
626the optimized behaviour. If the type doesn't fulfill the required characteristics, a diagnostic will be printed in
627many situations. Presently, badly aligned data structures are detected at compile time. Other problems are
628only detected at runtime, and result in lower performance but still correct behaviour.
629Using 'savefile_require_fast' is not unsafe, although it used to be in an old version.
630Since the speedups it produces are now produced regardless, it is mostly recommended to not use
631savefile_require_fast, unless compilation failure on bad alignment is desired.
632
633
634# Custom serialization
635
636For most user types, the savefile-derive crate can be used to automatically derive serializers
637and deserializers. This is not always possible, however.
638
639By implementing the traits Serialize, Deserialize and WithSchema, it's possible to create custom
640serializers for any type.
641
642Let's create a custom serializer for an object MyPathBuf, as an example (this is just an example, because of
643the rust 'orphan rules', only Savefile can actually implement the Savefile-traits for PathBuf. However,
644you can implement the Savefile traits for your own data types in your own crates!)
645
646The first thing we need to do is implement WithSchema. This trait requires us to return an instance
647of Schema. The Schema is used to 'sanity-check' stored data, so that an attempt to deserialize a
648file which was serialized using a different schema will fail predictably.
649
650Schema is an enum, with a few built-in variants. See documentation: [crate::Schema] .
651
652In our case, we choose to handle a MyPathBuf as a string, so we choose Schema::Primitive, with the
653argument SchemaPrimitive::schema_string . If your data is a collection of some sort, Schema::Vector
654may be appropriate.
655
656Note that the implementor of Serialize and Deserialize have total freedom to serialize data
657to/from the binary stream. It is important that the Schema accurately describes the format
658produced by Serialize and expected by Deserialize. Deserialization from a file is always sound,
659even if the Schema is wrong. However, the process may allocate too much memory, and data
660deserialized may be gibberish.
661
662When the Schema is used by the savefile-abi crate, unsoundness can occur if the Schema is
663incorrect. However, the responsibility for ensuring correctness falls on the savefile-abi crate.
664The savefile-library itself produces correct Schema-instances for all types it supports.
665
666````rust
667use savefile::prelude::*;
668pub struct MyPathBuf {
669 path: String,
670}
671impl WithSchema for MyPathBuf {
672 fn schema(_version: u32, context: &mut WithSchemaContext) -> Schema {
673     Schema::Primitive(SchemaPrimitive::schema_string((Default::default())))
674 }
675}
676impl Packed for MyPathBuf {
677}
678impl Serialize for MyPathBuf {
679 fn serialize<'a>(&self, serializer: &mut Serializer<impl std::io::Write>) -> Result<(), SavefileError> {
680     self.path.serialize(serializer)
681 }
682}
683impl Deserialize for MyPathBuf {
684 fn deserialize(deserializer: &mut Deserializer<impl std::io::Read>) -> Result<Self, SavefileError> {
685     Ok(MyPathBuf { path : String::deserialize(deserializer)? } )
686 }
687}
688
689````
690
691
692# Introspection
693
694The Savefile crate also provides an introspection feature, meant for diagnostics. This is implemented
695through the trait [Introspect]. Any type implementing this can be introspected.
696
697The savefile-derive crate supports automatically generating an implementation for most types.
698
699The introspection is purely 'read only'. There is no provision for using the framework to mutate
700data.
701
702Here is an example of using the trait directly:
703
704
705````rust
706use savefile::prelude::*;
707use savefile_derive::Savefile;
708use savefile::Introspect;
709use savefile::IntrospectItem;
710#[derive(Savefile)]
711struct Weight {
712 value: u32,
713 unit: String
714}
715#[derive(Savefile)]
716struct Person {
717 name : String,
718 age: u16,
719 weight: Weight,
720}
721let a_person = Person {
722 name: "Leo".into(),
723 age: 8,
724 weight: Weight { value: 26, unit: "kg".into() }
725};
726assert_eq!(a_person.introspect_len(), 3); //There are three fields
727assert_eq!(a_person.introspect_value(), "Person"); //Value of structs is the struct type, per default
728assert_eq!(a_person.introspect_child(0).unwrap().key(), "name"); //Each child has a name and a value. The value is itself a &dyn Introspect, and can be introspected recursively
729assert_eq!(a_person.introspect_child(0).unwrap().val().introspect_value(), "Leo"); //In this case, the child (name) is a simple string with value "Leo".
730assert_eq!(a_person.introspect_child(1).unwrap().key(), "age");
731assert_eq!(a_person.introspect_child(1).unwrap().val().introspect_value(), "8");
732assert_eq!(a_person.introspect_child(2).unwrap().key(), "weight");
733let weight = a_person.introspect_child(2).unwrap();
734assert_eq!(weight.val().introspect_child(0).unwrap().key(), "value"); //Here the child 'weight' has an introspectable weight obj as value
735assert_eq!(weight.val().introspect_child(0).unwrap().val().introspect_value(), "26");
736assert_eq!(weight.val().introspect_child(1).unwrap().key(), "unit");
737 assert_eq!(weight.val().introspect_child(1).unwrap().val().introspect_value(), "kg");
738
739````
740
741## Introspect Details
742
743By using #\[derive(SavefileIntrospectOnly)] it is possible to have only the Introspect-trait implemented,
744and not the serialization traits. This can be useful for types which aren't possible to serialize,
745but you still wish to have introspection for.
746
747By using the #\[savefile_introspect_key] attribute on a field, it is possible to make the
748generated [crate::Introspect::introspect_value] return the string representation of the field.
749This can be useful, to have the primary key (name) of an object more prominently visible in the
750introspection output.
751
752Example:
753
754````rust
755# use savefile::prelude::*;
756# use savefile_derive::Savefile;
757# use savefile::prelude::*;
758
759#[derive(Savefile)]
760pub struct StructWithName {
761 #[savefile_introspect_key]
762 name: String,
763 value: String
764}
765# fn main(){}
766````
767
768## Higher level introspection functions
769
770There is a helper called [crate::Introspector] which allows to get a structured representation
771of parts of an introspectable object. The Introspector has a 'path' which looks in to the
772introspection tree and shows values for this tree. The advantage of using this compared to
773just using ```format!("{:#?}",mystuff)``` is that for very large data structures, unconditionally
774dumping all data may be unwieldy. The author has a struct which becomes hundreds of megabytes
775when formatted using the Debug-trait in this way.
776
777An example:
778````rust
779
780use savefile_derive::Savefile;
781use savefile::Introspect;
782use savefile::IntrospectItem;
783use savefile::prelude::*;
784#[derive(Savefile)]
785struct Weight {
786 value: u32,
787 unit: String
788}
789#[derive(Savefile)]
790struct Person {
791 name : String,
792 age: u16,
793 weight: Weight,
794}
795
796let a_person = Person {
797 name: "Leo".into(),
798 age: 8,
799 weight: Weight { value: 26, unit: "kg".into() }
800};
801
802let mut introspector = Introspector::new();
803
804let result = introspector.do_introspect(&a_person,
805 IntrospectorNavCommand::SelectNth{select_depth:0, select_index: 2}).unwrap();
806
807println!("{}",result);
808/*
809Output is:
810
811Introspectionresult:
812name = Leo
813age = 8
814eight = Weight
815value = 26
816unit = kg
817
818*/
819// Note, that there is no point in using the Introspection framework just to get
820// a debug output like above, the point is that for larger data structures, the
821// introspection data can be programmatically used and shown in a live updating GUI,
822// or possibly command line interface or similar. The [crate::IntrospectionResult] does
823// implement Display, but this is just for convenience.
824
825
826
827````
828
829## Navigating using the Introspector
830
831The [crate::Introspector] object can be used to navigate inside an object being introspected.
832A GUI-program could allow an operator to use arrow keys to navigate the introspected object.
833
834Every time [crate::Introspector::do_introspect] is called, a [crate::IntrospectorNavCommand] is given
835which can traverse the tree downward or upward. In the example in the previous chapter,
836SelectNth is used to select the 2nd children at the 0th level in the tree.
837
838
839# Troubleshooting
840
841## The compiler complains that it cannot find item 'deserialize' on a type
842
843Maybe you get an error like:
844
845```the function or associated item `deserialize` exists for struct `Vec<T>`, but its trait bounds were not satisfied```
846
847First, check that you've derived 'Savefile' for the type in question. If you've implemented the Savefile traits
848manually, check that you've implemented both ```[crate::prelude::Deserialize]``` and ```[crate::prelude::Packed]```.
849Without Packed, vectors cannot be deserialized, since savefile can't determine if they are safe to serialize
850through simple copying of bytes.
851
852
853*/
854
855/// The prelude contains all definitions thought to be needed by typical users of the library
856pub mod prelude;
857
858#[cfg(feature = "serde_derive")]
859extern crate serde;
860#[cfg(feature = "serde_derive")]
861extern crate serde_derive;
862
863use core::str::Utf8Error;
864#[cfg(feature = "serde_derive")]
865use serde_derive::{Deserialize, Serialize};
866use std::any::TypeId;
867
868#[cfg(feature = "quickcheck")]
869extern crate quickcheck;
870
871extern crate alloc;
872#[cfg(feature = "arrayvec")]
873extern crate arrayvec;
874extern crate byteorder;
875#[cfg(feature = "parking_lot")]
876extern crate parking_lot;
877#[cfg(feature = "smallvec")]
878extern crate smallvec;
879
880#[cfg(feature = "parking_lot")]
881use parking_lot::{Mutex, MutexGuard, RwLock, RwLockReadGuard};
882
883use std::borrow::Cow;
884use std::fs::File;
885use std::io::{BufReader, BufWriter, Read};
886use std::io::{ErrorKind, Write};
887use std::sync::atomic::{
888    AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64, AtomicU8,
889    AtomicUsize, Ordering,
890};
891
892pub use ::byteorder::LittleEndian;
893use std::collections::BinaryHeap;
894use std::collections::VecDeque;
895use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
896use std::hash::Hash;
897#[allow(unused_imports)]
898use std::mem::MaybeUninit;
899
900#[cfg(feature = "indexmap")]
901extern crate indexmap;
902#[cfg(feature = "indexmap")]
903use indexmap::{IndexMap, IndexSet};
904
905#[cfg(feature = "quickcheck")]
906use quickcheck::{Arbitrary, Gen};
907
908#[cfg(feature = "bit-vec")]
909extern crate bit_vec;
910#[cfg(feature = "bzip2")]
911extern crate bzip2;
912
913#[cfg(feature = "bit-set")]
914extern crate bit_set;
915
916#[cfg(feature = "rustc-hash")]
917extern crate rustc_hash;
918
919extern crate memoffset;
920
921#[cfg(feature = "derive")]
922extern crate savefile_derive;
923
924/// The current savefile version.
925///
926/// This versions number is used for serialized schemas.
927/// There is an ambition that savefiles created by earlier versions
928/// will be possible to open using later versions. The other way
929/// around is not supported.
930pub const CURRENT_SAVEFILE_LIB_VERSION: u16 = 2;
931
932/// This object represents an error in deserializing or serializing
933/// an item.
934#[derive(Debug)]
935#[must_use]
936#[non_exhaustive]
937pub enum SavefileError {
938    /// Error given when the schema stored in a file, does not match
939    /// the schema given by the data structures in the code, taking into account
940    /// versions.
941    IncompatibleSchema {
942        /// A short description of the incompatibility
943        message: String,
944    },
945    /// Some sort of IO failure. Permissions, broken media etc ...
946    IOError {
947        /// Cause
948        io_error: std::io::Error,
949    },
950    /// The binary data which is being deserialized, contained an invalid utf8 sequence
951    /// where a String was expected. If this occurs, it is either a bug in savefile,
952    /// a bug in an implementation of Deserialize, Serialize or WithSchema, or
953    /// a corrupt data file.
954    InvalidUtf8 {
955        /// descriptive message
956        msg: String,
957    },
958    /// Unexpected error with regards to memory layout requirements.
959    MemoryAllocationLayoutError,
960    /// An Arrayvec had smaller capacity than the size of the data in the binary file.
961    ArrayvecCapacityError {
962        /// Descriptive message
963        msg: String,
964    },
965    /// The reader returned fewer bytes than expected
966    ShortRead,
967    /// Cryptographic checksum mismatch. Probably due to a corrupt file.
968    CryptographyError,
969    /// A persisted value of isize or usize was greater than the maximum for the machine.
970    /// This can happen if a file saved by a 64-bit machine contains an usize or isize which
971    /// does not fit in a 32 bit word.
972    SizeOverflow,
973    /// The file does not have a supported version number
974    WrongVersion {
975        /// Descriptive message
976        msg: String,
977    },
978    /// The file does not have a supported version number
979    GeneralError {
980        /// Descriptive message
981        msg: String,
982    },
983    /// A poisoned mutex was encountered when traversing the object being saved
984    PoisonedMutex,
985    /// File was compressed, or user asked for compression, but bzip2-library feature was not enabled.
986    CompressionSupportNotCompiledIn,
987    /// Invalid char, i.e, a serialized value expected to be a char was encountered, but it had an invalid value.
988    InvalidChar,
989    /// This occurs for example when using the stable ABI-functionality to call into a library,
990    /// and then it turns out that library uses a future, incompatible, Savefile-library version.
991    IncompatibleSavefileLibraryVersion,
992    /// This occurs if a foreign ABI entry point is missing a method
993    MissingMethod {
994        /// The name of the missing method
995        method_name: String,
996    },
997    /// Savefile ABI only supports at most 63 arguments per function
998    TooManyArguments,
999    /// An ABI callee panicked
1000    CalleePanic {
1001        /// Descriptive message
1002        msg: String,
1003    },
1004    /// Loading an extern library failed (only relevant for savefile-abi)
1005    LoadLibraryFailed {
1006        /// The library being loaded
1007        libname: String,
1008        /// Possible descriptive message
1009        msg: String,
1010    },
1011    /// Loading an extern library failed (only relevant for savefile-abi)
1012    LoadSymbolFailed {
1013        /// The library being loaded
1014        libname: String,
1015        /// The symbol being loaded
1016        symbol: String,
1017        /// Possible descriptive message
1018        msg: String,
1019    },
1020}
1021impl From<Utf8Error> for SavefileError {
1022    fn from(value: Utf8Error) -> Self {
1023        SavefileError::InvalidUtf8 {
1024            msg: format!("{:?}", value),
1025        }
1026    }
1027}
1028impl Display for SavefileError {
1029    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1030        match self {
1031            SavefileError::IncompatibleSchema { message } => {
1032                write!(f, "Incompatible schema: {}", message)
1033            }
1034            SavefileError::IOError { io_error } => {
1035                write!(f, "IO error: {}", io_error)
1036            }
1037            SavefileError::InvalidUtf8 { msg } => {
1038                write!(f, "Invalid UTF-8: {}", msg)
1039            }
1040            SavefileError::MemoryAllocationLayoutError => {
1041                write!(f, "Memory allocation layout error")
1042            }
1043            SavefileError::ArrayvecCapacityError { msg } => {
1044                write!(f, "Arrayvec capacity error: {}", msg)
1045            }
1046            SavefileError::ShortRead => {
1047                write!(f, "Short read")
1048            }
1049            SavefileError::CryptographyError => {
1050                write!(f, "Cryptography error")
1051            }
1052            SavefileError::SizeOverflow => {
1053                write!(f, "Size overflow")
1054            }
1055            SavefileError::WrongVersion { msg } => {
1056                write!(f, "Wrong version: {}", msg)
1057            }
1058            SavefileError::GeneralError { msg } => {
1059                write!(f, "General error: {}", msg)
1060            }
1061            SavefileError::PoisonedMutex => {
1062                write!(f, "Poisoned mutex")
1063            }
1064            SavefileError::CompressionSupportNotCompiledIn => {
1065                write!(f, "Compression support missing - recompile with bzip2 feature enabled.")
1066            }
1067            SavefileError::InvalidChar => {
1068                write!(f, "Invalid char value encountered.")
1069            }
1070            SavefileError::IncompatibleSavefileLibraryVersion => {
1071                write!(f, "Incompatible savefile library version. Perhaps a plugin was loaded that is a future unsupported version?")
1072            }
1073            SavefileError::MissingMethod { method_name } => {
1074                write!(f, "Plugin is missing method {}", method_name)
1075            }
1076            SavefileError::TooManyArguments => {
1077                write!(f, "Function has too many arguments")
1078            }
1079            SavefileError::CalleePanic { msg } => {
1080                write!(f, "Invocation target panicked: {}", msg)
1081            }
1082            SavefileError::LoadLibraryFailed { libname, msg } => {
1083                write!(f, "Failed while loading library {}: {}", libname, msg)
1084            }
1085            SavefileError::LoadSymbolFailed { libname, symbol, msg } => {
1086                write!(
1087                    f,
1088                    "Failed while loading symbol {} from library {}: {}",
1089                    symbol, libname, msg
1090                )
1091            }
1092        }
1093    }
1094}
1095
1096impl std::error::Error for SavefileError {}
1097
1098impl SavefileError {
1099    /// Construct a SavefileError::GeneralError using the given string
1100    pub fn general(something: impl Display) -> SavefileError {
1101        SavefileError::GeneralError {
1102            msg: format!("{}", something),
1103        }
1104    }
1105}
1106
1107/// Object to which serialized data is to be written.
1108///
1109/// This is basically just a wrapped `std::io::Write` object
1110/// and a file protocol version number.
1111/// In versions prior to 0.15, 'Serializer' did not accept a type parameter.
1112/// It now requires a type parameter with the type of writer to operate on.
1113pub struct Serializer<'a, W: Write> {
1114    /// The underlying writer. You should not access this.
1115    pub writer: &'a mut W,
1116    /// The version of the data structures which we are writing to disk.
1117    /// If this is < memory_version, we're serializing into an older format.
1118    /// Serializing into a future format is logically impossible.
1119    pub file_version: u32,
1120}
1121
1122/// Object from which bytes to be deserialized are read.
1123///
1124/// This is basically just a wrapped `std::io::Read` object,
1125/// the version number of the file being read, and the
1126/// current version number of the data structures in memory.
1127pub struct Deserializer<'a, R: Read> {
1128    /// The wrapped reader
1129    pub reader: &'a mut R,
1130    /// The version of the input file
1131    pub file_version: u32,
1132    /// This contains ephemeral state that can be used to implement de-duplication of
1133    /// strings or possibly other situations where it is desired to deserialize DAGs.
1134    pub ephemeral_state: HashMap<TypeId, Box<dyn Any>>,
1135}
1136
1137impl<TR: Read> Deserializer<'_, TR> {
1138    /// Get deserializer state.
1139    ///
1140    /// This function constructs a temporary state object of type R, and returns a mutable
1141    /// reference to it. This object can be used to store data that needs to live for the entire
1142    /// deserialization session. An example is de-duplicating Arc and other reference counted objects.
1143    /// Out of the box, `Arc<str>` has this deduplication done for it.
1144    /// The type T must be set to the type being deserialized, and is used as a key in a hashmap
1145    /// separating the state for different types.
1146    pub fn get_state<T: 'static, R: Default + 'static>(&mut self) -> &mut R {
1147        let type_id = TypeId::of::<T>();
1148        let the_any = self
1149            .ephemeral_state
1150            .entry(type_id)
1151            .or_insert_with(|| Box::new(R::default()));
1152
1153        the_any.downcast_mut().unwrap()
1154    }
1155}
1156
1157/// Marker used to promise that some type fulfills all rules
1158/// for the "Packed"-optimization.
1159#[derive(Default, Debug)]
1160pub struct IsPacked(bool);
1161
1162#[doc(hidden)]
1163#[deprecated(since = "0.17.0", note = "The 'IsReprC' type has been renamed to 'IsPacked'.")]
1164pub type IsReprC = IsPacked;
1165
1166impl std::ops::BitAnd<IsPacked> for IsPacked {
1167    type Output = IsPacked;
1168
1169    fn bitand(self, rhs: Self) -> Self::Output {
1170        IsPacked(self.0 && rhs.0)
1171    }
1172}
1173
1174impl IsPacked {
1175    /// # Safety
1176    /// Must only ever be created and immediately returned from
1177    /// Packed::repr_c_optimization_safe. Any other use, such
1178    /// that the value could conceivably be smuggled to
1179    /// a repr_c_optimization_safe-implementation is forbidden.
1180    ///
1181    /// Also, see description of Packed trait and repr_c_optimization_safe.
1182    pub unsafe fn yes() -> IsPacked {
1183        IsPacked(true)
1184    }
1185    /// No, the type is not compatible with the "Packed"-optimization.
1186    /// It cannot be just blitted.
1187    /// This is always safe, it just misses out on some optimizations.
1188    pub fn no() -> IsPacked {
1189        IsPacked(false)
1190    }
1191
1192    /// If this returns false, "Packed"-Optimization is not allowed.
1193    #[inline(always)]
1194    pub fn is_false(self) -> bool {
1195        !self.0
1196    }
1197
1198    /// If this returns true, "Packed"-Optimization is allowed. Beware.
1199    #[inline(always)]
1200    pub fn is_yes(self) -> bool {
1201        self.0
1202    }
1203}
1204
1205/// This trait describes whether a type is such that it can just be blitted.
1206/// See method repr_c_optimization_safe.
1207/// Note! The name Packed is a little misleading. A better name would be
1208/// 'packed'
1209#[cfg_attr(
1210    feature = "rust1_78",
1211    diagnostic::on_unimplemented(
1212        message = "`{Self}` cannot be serialized or deserialized by Savefile, since it doesn't implement trait `savefile::Packed`",
1213        label = "This cannot be serialized or deserialized",
1214        note = "You can implement it by adding `#[derive(Savefile)]` before the declaration of `{Self}`",
1215        note = "Or you can manually implement the `savefile::Packed` trait."
1216    )
1217)]
1218pub trait Packed {
1219    /// This method returns true if the optimization is allowed
1220    /// for the protocol version given as an argument.
1221    /// This may return true if and only if the given protocol version
1222    /// has a serialized format identical to the memory layout of the given protocol version.
1223    /// Note, the only memory layout existing is that of the most recent version, so
1224    /// Packed-optimization only works when disk-format is identical to memory version.
1225    ///
1226    /// This can return true for types which have an in-memory layout that is packed
1227    /// and therefore identical to the layout that savefile will use on disk.
1228    /// This means that types for which this trait is implemented can be serialized
1229    /// very quickly by just writing their raw bits to disc.
1230    ///
1231    /// Rules to allow returning true:
1232    ///
1233    /// * The type must "be Copy" (i.e, implement the `Copy`-trait)
1234    /// * The type must not contain any padding (if there is padding, backward compatibility will fail, since in fallback mode regular savefile-deserialize will be used, and it will not use padding)
1235    /// * The type must have a strictly deterministic memory layout (no field order randomization). This typically means repr(C)
1236    /// * All the constituent types of the type must also implement `Packed` (correctly).
1237    ///
1238    /// Constructing an instance of 'IsPacked' with value 'true' is not safe. See
1239    /// documentation of 'IsPacked'. The idea is that the Packed-trait itself
1240    /// can still be safe to implement, it just won't be possible to get hold of an
1241    /// instance of IsPacked(true). That is, a safe implementation of `Packed` can't return
1242    /// IsPacked(true), if everything else follows safety rules. To make it impossible to just
1243    /// 'steal' such a value from some other thing implementing 'Packed',
1244    /// this method is marked unsafe (however, it can be left unimplemented,
1245    /// making it still possible to safely implement Packed).
1246    ///
1247    /// # Safety
1248    /// The returned value must not be used, except by the Savefile-framework.
1249    /// It must *not* be forwarded anywhere else.
1250    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
1251        IsPacked::no()
1252    }
1253}
1254
1255/// This just exists to make sure that no one can actually implement the ReprC-trait placeholder.
1256/// If you somehow end up here, what you really want is to find instances of ReprC and change them
1257/// to Packed.
1258#[doc(hidden)]
1259#[deprecated(since = "0.17.0", note = "The 'ReprC' trait has been renamed to 'Packed'.")]
1260pub struct DeliberatelyUnimplementable {
1261    #[allow(dead_code)]
1262    private: (),
1263}
1264
1265#[deprecated(since = "0.17.0", note = "The 'ReprC' trait has been renamed to 'Packed'.")]
1266#[doc(hidden)]
1267#[cfg_attr(
1268    feature = "rust1_78",
1269    diagnostic::on_unimplemented(
1270        message = "ReprC has been deprecated and must not be used. Use trait `savefile::Packed` instead!",
1271        label = "ReprC was erroneously required here",
1272        note = "Please change any `ReprC` bounds into `Packed` bounds.",
1273    )
1274)]
1275pub trait ReprC {
1276    #[deprecated(since = "0.17.0", note = "The 'ReprC' trait has been renamed to 'Packed'.")]
1277    #[doc(hidden)]
1278    #[allow(non_snake_case)]
1279    #[allow(deprecated)]
1280    fn this_is_a_placeholder__if_you_see_this_it_is_likely_that_you_have_code_that_refers_to_ReprC_trait__this_trait_has_been_renamed_to__Packed(
1281    ) -> DeliberatelyUnimplementable;
1282    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
1283        IsPacked::no()
1284    }
1285}
1286
1287impl From<std::io::Error> for SavefileError {
1288    fn from(s: std::io::Error) -> SavefileError {
1289        SavefileError::IOError { io_error: s }
1290    }
1291}
1292
1293impl<T> From<std::sync::PoisonError<T>> for SavefileError {
1294    fn from(_: std::sync::PoisonError<T>) -> SavefileError {
1295        SavefileError::PoisonedMutex
1296    }
1297}
1298
1299impl From<std::string::FromUtf8Error> for SavefileError {
1300    fn from(s: std::string::FromUtf8Error) -> SavefileError {
1301        SavefileError::InvalidUtf8 { msg: s.to_string() }
1302    }
1303}
1304#[cfg(feature = "arrayvec")]
1305impl<T> From<arrayvec::CapacityError<T>> for SavefileError {
1306    fn from(s: arrayvec::CapacityError<T>) -> SavefileError {
1307        SavefileError::ArrayvecCapacityError { msg: s.to_string() }
1308    }
1309}
1310
1311impl WithSchema for PathBuf {
1312    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
1313        Schema::Primitive(SchemaPrimitive::schema_string(VecOrStringLayout::Unknown))
1314    }
1315}
1316impl Serialize for PathBuf {
1317    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
1318        let as_string: String = self.to_string_lossy().to_string();
1319        as_string.serialize(serializer)
1320    }
1321}
1322impl Packed for PathBuf {}
1323impl Deserialize for PathBuf {
1324    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
1325        Ok(PathBuf::from(String::deserialize(deserializer)?))
1326    }
1327}
1328impl Introspect for PathBuf {
1329    fn introspect_value(&self) -> String {
1330        self.to_string_lossy().to_string()
1331    }
1332
1333    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_>>> {
1334        None
1335    }
1336}
1337
1338impl<'a, T: 'a + WithSchema + ToOwned + ?Sized> WithSchema for Cow<'a, T> {
1339    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
1340        T::schema(version, context)
1341    }
1342}
1343impl<'a, T: 'a + ToOwned + ?Sized> Packed for Cow<'a, T> {}
1344
1345impl<'a, T: 'a + Serialize + ToOwned + ?Sized> Serialize for Cow<'a, T> {
1346    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
1347        (**self).serialize(serializer)
1348    }
1349}
1350impl<'a, T: 'a + WithSchema + ToOwned + ?Sized> Deserialize for Cow<'a, T>
1351where
1352    T::Owned: Deserialize,
1353{
1354    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Cow<'a, T>, SavefileError> {
1355        Ok(Cow::Owned(<T as ToOwned>::Owned::deserialize(deserializer)?))
1356    }
1357}
1358impl<'a, T: 'a + Introspect + ToOwned + ?Sized> Introspect for Cow<'a, T> {
1359    fn introspect_value(&self) -> String {
1360        (**self).introspect_value()
1361    }
1362
1363    fn introspect_child<'b>(&'b self, index: usize) -> Option<Box<dyn IntrospectItem<'b> + 'b>> {
1364        (**self).introspect_child(index)
1365    }
1366
1367    fn introspect_len(&self) -> usize {
1368        (**self).introspect_len()
1369    }
1370}
1371
1372impl WithSchema for std::io::Error {
1373    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
1374        Schema::StdIoError
1375    }
1376}
1377impl Packed for std::io::Error {}
1378
1379impl Serialize for std::io::Error {
1380    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
1381        let kind = match self.kind() {
1382            ErrorKind::NotFound => 1,
1383            ErrorKind::PermissionDenied => 2,
1384            ErrorKind::ConnectionRefused => 3,
1385            ErrorKind::ConnectionReset => 4,
1386            ErrorKind::ConnectionAborted => 7,
1387            ErrorKind::NotConnected => 8,
1388            ErrorKind::AddrInUse => 9,
1389            ErrorKind::AddrNotAvailable => 10,
1390            ErrorKind::BrokenPipe => 12,
1391            ErrorKind::AlreadyExists => 13,
1392            ErrorKind::WouldBlock => 14,
1393            ErrorKind::InvalidInput => 21,
1394            ErrorKind::InvalidData => 22,
1395            ErrorKind::TimedOut => 23,
1396            ErrorKind::WriteZero => 24,
1397            ErrorKind::Interrupted => 36,
1398            ErrorKind::Unsupported => 37,
1399            ErrorKind::UnexpectedEof => 38,
1400            ErrorKind::OutOfMemory => 39,
1401            ErrorKind::Other => 40,
1402            _ => 42,
1403        };
1404        serializer.write_u16(kind as u16)?;
1405        serializer.write_string(&self.to_string())?;
1406        Ok(())
1407    }
1408}
1409impl Deserialize for std::io::Error {
1410    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
1411        let kind = deserializer.read_u16()?;
1412        let kind = match kind {
1413            1 => ErrorKind::NotFound,
1414            2 => ErrorKind::PermissionDenied,
1415            3 => ErrorKind::ConnectionRefused,
1416            4 => ErrorKind::ConnectionReset,
1417            7 => ErrorKind::ConnectionAborted,
1418            8 => ErrorKind::NotConnected,
1419            9 => ErrorKind::AddrInUse,
1420            10 => ErrorKind::AddrNotAvailable,
1421            12 => ErrorKind::BrokenPipe,
1422            13 => ErrorKind::AlreadyExists,
1423            14 => ErrorKind::WouldBlock,
1424            21 => ErrorKind::InvalidInput,
1425            22 => ErrorKind::InvalidData,
1426            23 => ErrorKind::TimedOut,
1427            24 => ErrorKind::WriteZero,
1428            36 => ErrorKind::Interrupted,
1429            37 => ErrorKind::Unsupported,
1430            38 => ErrorKind::UnexpectedEof,
1431            39 => ErrorKind::OutOfMemory,
1432            40 => ErrorKind::Other,
1433            _ => ErrorKind::Other,
1434        };
1435
1436        let string = String::deserialize(deserializer)?;
1437        Ok(std::io::Error::new(kind, string))
1438    }
1439}
1440
1441#[cfg(feature = "ring")]
1442mod crypto {
1443    use ring::aead;
1444    use ring::aead::{BoundKey, Nonce, NonceSequence, OpeningKey, SealingKey, UnboundKey, AES_256_GCM};
1445    use ring::error::Unspecified;
1446    use std::fs::File;
1447    use std::io::{Error, ErrorKind, Read, Write};
1448    use std::path::Path;
1449
1450    extern crate rand;
1451
1452    use crate::{Deserialize, Deserializer, SavefileError, Serialize, Serializer, WithSchema};
1453    use byteorder::WriteBytesExt;
1454    use byteorder::{LittleEndian, ReadBytesExt};
1455    use rand::rngs::OsRng;
1456    use rand::RngCore;
1457
1458    extern crate ring;
1459
1460    #[derive(Debug)]
1461    struct RandomNonceSequence {
1462        data1: u64,
1463        data2: u32,
1464    }
1465
1466    impl RandomNonceSequence {
1467        pub fn new() -> RandomNonceSequence {
1468            RandomNonceSequence {
1469                data1: OsRng.next_u64(),
1470                data2: OsRng.next_u32(),
1471            }
1472        }
1473        pub fn serialize(&self, writer: &mut dyn Write) -> Result<(), SavefileError> {
1474            writer.write_u64::<LittleEndian>(self.data1)?;
1475            writer.write_u32::<LittleEndian>(self.data2)?;
1476            Ok(())
1477        }
1478        pub fn deserialize(reader: &mut dyn Read) -> Result<RandomNonceSequence, SavefileError> {
1479            Ok(RandomNonceSequence {
1480                data1: reader.read_u64::<LittleEndian>()?,
1481                data2: reader.read_u32::<LittleEndian>()?,
1482            })
1483        }
1484    }
1485
1486    impl NonceSequence for RandomNonceSequence {
1487        fn advance(&mut self) -> Result<Nonce, Unspecified> {
1488            self.data2 = self.data2.wrapping_add(1);
1489            if self.data2 == 0 {
1490                self.data1 = self.data1.wrapping_add(1);
1491            }
1492            let mut bytes = [0u8; 12];
1493            let bytes1: [u8; 8] = self.data1.to_le_bytes();
1494            let bytes2: [u8; 4] = self.data2.to_le_bytes();
1495            for i in 0..8 {
1496                bytes[i] = bytes1[i];
1497            }
1498            for i in 0..4 {
1499                bytes[i + 8] = bytes2[i];
1500            }
1501
1502            Ok(Nonce::assume_unique_for_key(bytes))
1503        }
1504    }
1505
1506    /// A cryptographic stream wrapper.
1507    /// Wraps a plain dyn Write, and itself implements Write, encrypting
1508    /// all data written.
1509    pub struct CryptoWriter<'a> {
1510        writer: &'a mut dyn Write,
1511        buf: Vec<u8>,
1512        sealkey: SealingKey<RandomNonceSequence>,
1513        failed: bool,
1514    }
1515
1516    /// A cryptographic stream wrapper.
1517    /// Wraps a plain dyn Read, and itself implements Read, decrypting
1518    /// and verifying all data read.
1519    pub struct CryptoReader<'a> {
1520        reader: &'a mut dyn Read,
1521        buf: Vec<u8>,
1522        offset: usize,
1523        openingkey: OpeningKey<RandomNonceSequence>,
1524    }
1525
1526    impl<'a> CryptoReader<'a> {
1527        /// Create a new CryptoReader, wrapping the given Read . Decrypts using the given
1528        /// 32 byte cryptographic key.
1529        /// Crypto is 256 bit AES GCM
1530        pub fn new(reader: &'a mut dyn Read, key_bytes: [u8; 32]) -> Result<CryptoReader<'a>, SavefileError> {
1531            let unboundkey = UnboundKey::new(&AES_256_GCM, &key_bytes).unwrap();
1532
1533            let nonce_sequence = RandomNonceSequence::deserialize(reader)?;
1534            let openingkey = OpeningKey::new(unboundkey, nonce_sequence);
1535
1536            Ok(CryptoReader {
1537                reader,
1538                offset: 0,
1539                buf: Vec::new(),
1540                openingkey,
1541            })
1542        }
1543    }
1544
1545    const CRYPTO_BUFSIZE: usize = 100_000;
1546
1547    impl Drop for CryptoWriter<'_> {
1548        fn drop(&mut self) {
1549            self.flush().expect("The implicit flush in the Drop of CryptoWriter failed. This causes this panic. If you want to be able to handle this, make sure to call flush() manually. If a manual flush has failed, Drop won't panic.");
1550        }
1551    }
1552
1553    impl<'a> CryptoWriter<'a> {
1554        /// Create a new CryptoWriter, wrapping the given Write . Encrypts using the given
1555        /// 32 byte cryptographic key.
1556        /// Crypto is 256 bit AES GCM
1557        pub fn new(writer: &'a mut dyn Write, key_bytes: [u8; 32]) -> Result<CryptoWriter<'a>, SavefileError> {
1558            let unboundkey = UnboundKey::new(&AES_256_GCM, &key_bytes).unwrap();
1559            let nonce_sequence = RandomNonceSequence::new();
1560            nonce_sequence.serialize(writer)?;
1561            let sealkey = SealingKey::new(unboundkey, nonce_sequence);
1562            Ok(CryptoWriter {
1563                writer,
1564                buf: Vec::new(),
1565                sealkey,
1566                failed: false,
1567            })
1568        }
1569        /// Data is encrypted in chunks. Calling this unconditionally finalizes a chunk, actually emitting
1570        /// data to the underlying dyn Write. When later reading data, an entire chunk must be read
1571        /// from file before any plaintext is produced.
1572        pub fn flush_final(mut self) -> Result<(), SavefileError> {
1573            if self.failed {
1574                panic!("Call to failed CryptoWriter");
1575            }
1576            self.flush()?;
1577            Ok(())
1578        }
1579    }
1580
1581    impl Read for CryptoReader<'_> {
1582        fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
1583            loop {
1584                if buf.len() <= self.buf.len() - self.offset {
1585                    buf.clone_from_slice(&self.buf[self.offset..self.offset + buf.len()]);
1586                    self.offset += buf.len();
1587                    return Ok(buf.len());
1588                }
1589
1590                {
1591                    let oldlen = self.buf.len();
1592                    let newlen = self.buf.len() - self.offset;
1593                    self.buf.copy_within(self.offset..oldlen, 0);
1594                    self.buf.resize(newlen, 0);
1595                    self.offset = 0;
1596                }
1597                let mut sizebuf = [0; 8];
1598                let mut sizebuf_bytes_read = 0;
1599                loop {
1600                    match self.reader.read(&mut sizebuf[sizebuf_bytes_read..]) {
1601                        Ok(gotsize) => {
1602                            if gotsize == 0 {
1603                                if sizebuf_bytes_read == 0 {
1604                                    let cur_content_size = self.buf.len() - self.offset;
1605                                    buf[0..cur_content_size]
1606                                        .clone_from_slice(&self.buf[self.offset..self.offset + cur_content_size]);
1607                                    self.offset += cur_content_size;
1608                                    return Ok(cur_content_size);
1609                                } else {
1610                                    return Err(Error::new(ErrorKind::UnexpectedEof, "Unexpected EOF"));
1611                                }
1612                            } else {
1613                                sizebuf_bytes_read += gotsize;
1614                                assert!(sizebuf_bytes_read <= 8);
1615                            }
1616                        }
1617                        Err(err) => return Err(err),
1618                    }
1619                    if sizebuf_bytes_read == 8 {
1620                        break;
1621                    }
1622                }
1623                use byteorder::ByteOrder;
1624                let curlen = byteorder::LittleEndian::read_u64(&sizebuf) as usize;
1625
1626                if curlen > CRYPTO_BUFSIZE + 16 {
1627                    return Err(Error::new(ErrorKind::Other, "Cryptography error"));
1628                }
1629                let orglen = self.buf.len();
1630                self.buf.resize(orglen + curlen, 0);
1631
1632                self.reader.read_exact(&mut self.buf[orglen..orglen + curlen])?;
1633
1634                match self
1635                    .openingkey
1636                    .open_in_place(aead::Aad::empty(), &mut self.buf[orglen..])
1637                {
1638                    Ok(_) => {}
1639                    Err(_) => {
1640                        return Err(Error::new(ErrorKind::Other, "Cryptography error"));
1641                    }
1642                }
1643                self.buf.resize(self.buf.len() - 16, 0);
1644            }
1645        }
1646    }
1647
1648    impl Write for CryptoWriter<'_> {
1649        fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
1650            if self.failed {
1651                panic!("Call to failed CryptoWriter");
1652            }
1653            self.buf.extend(buf);
1654            if self.buf.len() > CRYPTO_BUFSIZE {
1655                self.flush()?;
1656            }
1657            Ok(buf.len())
1658        }
1659
1660        /// Writes any non-written buffered bytes to the underlying stream.
1661        /// If this fails, there is no recovery. The buffered data will have been
1662        /// lost.
1663        fn flush(&mut self) -> Result<(), Error> {
1664            self.failed = true;
1665            let mut offset = 0;
1666
1667            let mut tempbuf = Vec::new();
1668            if self.buf.len() > CRYPTO_BUFSIZE {
1669                tempbuf = Vec::<u8>::with_capacity(CRYPTO_BUFSIZE + 16);
1670            }
1671
1672            while self.buf.len() > offset {
1673                let curbuf;
1674                if offset == 0 && self.buf.len() <= CRYPTO_BUFSIZE {
1675                    curbuf = &mut self.buf;
1676                } else {
1677                    let chunksize = (self.buf.len() - offset).min(CRYPTO_BUFSIZE);
1678                    tempbuf.resize(chunksize, 0u8);
1679                    tempbuf.clone_from_slice(&self.buf[offset..offset + chunksize]);
1680                    curbuf = &mut tempbuf;
1681                }
1682                let expected_final_len = curbuf.len() as u64 + 16;
1683                debug_assert!(expected_final_len <= CRYPTO_BUFSIZE as u64 + 16);
1684
1685                self.writer.write_u64::<LittleEndian>(expected_final_len)?; //16 for the tag
1686                match self.sealkey.seal_in_place_append_tag(aead::Aad::empty(), curbuf) {
1687                    Ok(_) => {}
1688                    Err(_) => {
1689                        return Err(Error::new(ErrorKind::Other, "Cryptography error"));
1690                    }
1691                }
1692                debug_assert!(curbuf.len() == expected_final_len as usize, "The size of the TAG generated by the AES 256 GCM in ring seems to have changed! This is very unexpected. File a bug on the savefile-crate");
1693
1694                self.writer.write_all(&curbuf[..])?;
1695                self.writer.flush()?;
1696                offset += curbuf.len() - 16;
1697                curbuf.resize(curbuf.len() - 16, 0);
1698            }
1699            self.buf.clear();
1700            self.failed = false;
1701            Ok(())
1702        }
1703    }
1704    /// Like [crate::save_file], except encrypts the data with AES256, using the SHA256 hash
1705    /// of the password as key.
1706    pub fn save_encrypted_file<T: WithSchema + Serialize, P: AsRef<Path>>(
1707        filepath: P,
1708        version: u32,
1709        data: &T,
1710        password: &str,
1711    ) -> Result<(), SavefileError> {
1712        use ring::digest;
1713        let actual = digest::digest(&digest::SHA256, password.as_bytes());
1714        let mut key = [0u8; 32];
1715        let password_hash = actual.as_ref();
1716        assert_eq!(password_hash.len(), key.len(), "A SHA256 sum must be 32 bytes");
1717        key.clone_from_slice(password_hash);
1718
1719        let mut f = File::create(filepath)?;
1720        let mut writer = CryptoWriter::new(&mut f, key)?;
1721
1722        Serializer::<CryptoWriter>::save::<T>(&mut writer, version, data, true)?;
1723        writer.flush()?;
1724        Ok(())
1725    }
1726
1727    /// Like [crate::load_file], except it expects the file to be an encrypted file previously stored using
1728    /// [crate::save_encrypted_file].
1729    pub fn load_encrypted_file<T: WithSchema + Deserialize, P: AsRef<Path>>(
1730        filepath: P,
1731        version: u32,
1732        password: &str,
1733    ) -> Result<T, SavefileError> {
1734        use ring::digest;
1735        let actual = digest::digest(&digest::SHA256, password.as_bytes());
1736        let mut key = [0u8; 32];
1737        let password_hash = actual.as_ref();
1738        assert_eq!(password_hash.len(), key.len(), "A SHA256 sum must be 32 bytes");
1739        key.clone_from_slice(password_hash);
1740
1741        let mut f = File::open(filepath)?;
1742        let mut reader = CryptoReader::new(&mut f, key).unwrap();
1743        Deserializer::<CryptoReader>::load::<T>(&mut reader, version)
1744    }
1745}
1746#[cfg(feature = "ring")]
1747pub use crypto::{load_encrypted_file, save_encrypted_file, CryptoReader, CryptoWriter};
1748
1749impl<'a, W: Write + 'a> Serializer<'a, W> {
1750    /// Writes a binary bool to the output
1751    #[inline(always)]
1752    pub fn write_bool(&mut self, v: bool) -> Result<(), SavefileError> {
1753        Ok(self.writer.write_u8(if v { 1 } else { 0 })?)
1754    }
1755    /// Writes a binary u8 to the output
1756    #[inline(always)]
1757    pub fn write_u8(&mut self, v: u8) -> Result<(), SavefileError> {
1758        Ok(self.writer.write_all(&[v])?)
1759    }
1760    /// Writes a binary i8 to the output
1761    #[inline(always)]
1762    pub fn write_i8(&mut self, v: i8) -> Result<(), SavefileError> {
1763        Ok(self.writer.write_i8(v)?)
1764    }
1765
1766    /// Writes a binary little endian u16 to the output
1767    #[inline(always)]
1768    pub fn write_u16(&mut self, v: u16) -> Result<(), SavefileError> {
1769        Ok(self.writer.write_u16::<LittleEndian>(v)?)
1770    }
1771    /// Writes a binary little endian i16 to the output
1772    #[inline(always)]
1773    pub fn write_i16(&mut self, v: i16) -> Result<(), SavefileError> {
1774        Ok(self.writer.write_i16::<LittleEndian>(v)?)
1775    }
1776
1777    /// Writes a binary little endian u32 to the output
1778    #[inline(always)]
1779    pub fn write_u32(&mut self, v: u32) -> Result<(), SavefileError> {
1780        Ok(self.writer.write_u32::<LittleEndian>(v)?)
1781    }
1782    /// Writes a binary little endian i32 to the output
1783    #[inline(always)]
1784    pub fn write_i32(&mut self, v: i32) -> Result<(), SavefileError> {
1785        Ok(self.writer.write_i32::<LittleEndian>(v)?)
1786    }
1787
1788    /// Writes a binary little endian f32 to the output
1789    #[inline(always)]
1790    pub fn write_f32(&mut self, v: f32) -> Result<(), SavefileError> {
1791        Ok(self.writer.write_f32::<LittleEndian>(v)?)
1792    }
1793    /// Writes a binary little endian f64 to the output
1794    #[inline(always)]
1795    pub fn write_f64(&mut self, v: f64) -> Result<(), SavefileError> {
1796        Ok(self.writer.write_f64::<LittleEndian>(v)?)
1797    }
1798
1799    /// Writes a binary little endian u64 to the output
1800    #[inline(always)]
1801    pub fn write_u64(&mut self, v: u64) -> Result<(), SavefileError> {
1802        Ok(self.writer.write_u64::<LittleEndian>(v)?)
1803    }
1804
1805    /// Serialize the bytes of the pointer itself
1806    /// # Safety
1807    /// This method does not actually have any safety invariants.
1808    /// However, any realistic use case will involve a subsequent read_raw_ptr,
1809    /// and for that to have any chance of being sound, this call must have used
1810    /// a pointer to a valid T, or a null ptr.
1811    #[inline(always)]
1812    pub unsafe fn write_raw_ptr<T: ?Sized>(&mut self, data: *const T) -> Result<(), SavefileError> {
1813        let temp = &data as *const *const T;
1814        let temp_data = temp as *const u8;
1815        let buf = slice::from_raw_parts(temp_data, std::mem::size_of::<*const T>());
1816        self.write_bytes(buf)
1817    }
1818
1819    /// Write a ptr + size
1820    /// # Safety
1821    /// `data` must point at `len` valid bytes.
1822    pub unsafe fn write_raw_ptr_size<T>(&mut self, data: *const T, len: usize) -> Result<(), SavefileError> {
1823        self.write_raw_ptr(data)?;
1824        self.write_usize(len)?;
1825        Ok(())
1826    }
1827
1828    /// Writes a binary little endian u64 to the output
1829    #[inline(always)]
1830    pub fn write_ptr(&mut self, v: *const ()) -> Result<(), SavefileError> {
1831        let slice_to_write = unsafe {
1832            std::slice::from_raw_parts(&v as *const *const () as *const u8, std::mem::size_of::<*const ()>())
1833        };
1834        Ok(self.writer.write_all(slice_to_write)?)
1835    }
1836    /// Writes a binary little endian i64 to the output
1837    #[inline(always)]
1838    pub fn write_i64(&mut self, v: i64) -> Result<(), SavefileError> {
1839        Ok(self.writer.write_i64::<LittleEndian>(v)?)
1840    }
1841    /// Writes a binary little endian u128 to the output
1842    #[inline(always)]
1843    pub fn write_u128(&mut self, v: u128) -> Result<(), SavefileError> {
1844        Ok(self.writer.write_u128::<LittleEndian>(v)?)
1845    }
1846    /// Writes a binary little endian i128 to the output
1847    #[inline(always)]
1848    pub fn write_i128(&mut self, v: i128) -> Result<(), SavefileError> {
1849        Ok(self.writer.write_i128::<LittleEndian>(v)?)
1850    }
1851    /// Writes a binary little endian usize as u64 to the output
1852    #[inline(always)]
1853    pub fn write_usize(&mut self, v: usize) -> Result<(), SavefileError> {
1854        Ok(self.writer.write_u64::<LittleEndian>(v as u64)?)
1855    }
1856    /// Writes a binary little endian isize as i64 to the output
1857    #[inline(always)]
1858    pub fn write_isize(&mut self, v: isize) -> Result<(), SavefileError> {
1859        Ok(self.writer.write_i64::<LittleEndian>(v as i64)?)
1860    }
1861    /// Writes a binary u8 array to the output
1862    #[inline(always)]
1863    pub fn write_buf(&mut self, v: &[u8]) -> Result<(), SavefileError> {
1864        Ok(self.writer.write_all(v)?)
1865    }
1866    /// Writes as a string as 64 bit length + utf8 data
1867    #[inline(always)]
1868    pub fn write_string(&mut self, v: &str) -> Result<(), SavefileError> {
1869        let asb = v.as_bytes();
1870        self.write_usize(asb.len())?;
1871        Ok(self.writer.write_all(asb)?)
1872    }
1873    /// Writes a binary u8 array to the output. Synonym of write_buf.
1874    #[inline(always)]
1875    pub fn write_bytes(&mut self, v: &[u8]) -> Result<(), SavefileError> {
1876        Ok(self.writer.write_all(v)?)
1877    }
1878
1879    /// Writes an interval of memory to the output
1880    /// #SAFETY:
1881    /// All the memory between the start of t1 and up to the end of t2 must
1882    /// be contiguous, without padding and safe to transmute to a u8-slice([u8]).
1883    /// The memory must all be within the object pointed to by full.
1884    /// The 'full' object is only needed to satisfy miri, otherwise
1885    /// we violate the rules when we create one continuous thing from parts.
1886    #[inline(always)]
1887    #[doc(hidden)]
1888    pub unsafe fn raw_write_region<T, T1: Packed, T2: Packed>(
1889        &mut self,
1890        full: &T,
1891        t1: &T1,
1892        t2: &T2,
1893        version: u32,
1894    ) -> Result<(), SavefileError> {
1895        assert!(T1::repr_c_optimization_safe(version).is_yes());
1896        assert!(T2::repr_c_optimization_safe(version).is_yes());
1897
1898        let base = full as *const T as *const u8;
1899        let totlen = std::mem::size_of::<T>();
1900        let p1 = (t1 as *const T1 as *const u8) as usize;
1901        let p2 = (t2 as *const T2 as *const u8) as usize;
1902        let start = p1 - (base as usize);
1903        let end = (p2 - (base as usize)) + std::mem::size_of::<T2>();
1904        let full_slice = std::slice::from_raw_parts(base, totlen);
1905        Ok(self.writer.write_all(&full_slice[start..end])?)
1906    }
1907    /// Creata a new serializer.
1908    /// Don't use this function directly, use the [crate::save] function instead.
1909    pub fn save<T: WithSchema + Serialize>(
1910        writer: &mut W,
1911        version: u32,
1912        data: &T,
1913        with_compression: bool,
1914    ) -> Result<(), SavefileError> {
1915        Ok(Self::save_impl(
1916            writer,
1917            version,
1918            data,
1919            Some(T::schema(version, &mut WithSchemaContext::new())),
1920            with_compression,
1921            None,
1922        )?)
1923    }
1924    /// Creata a new serializer.
1925    /// Don't use this function directly, use the [crate::save_noschema] function instead.
1926    pub fn save_noschema<T: Serialize>(writer: &mut W, version: u32, data: &T) -> Result<(), SavefileError> {
1927        Ok(Self::save_impl(writer, version, data, None, false, None)?)
1928    }
1929
1930    #[doc(hidden)]
1931    pub fn save_noschema_internal<T: Serialize>(
1932        writer: &mut W,
1933        version: u32,
1934        data: &T,
1935        lib_version_override: u16,
1936    ) -> Result<(), SavefileError> {
1937        Ok(Self::save_impl(
1938            writer,
1939            version,
1940            data,
1941            None,
1942            false,
1943            Some(lib_version_override),
1944        )?)
1945    }
1946    /// Serialize without any header. Using this means that bare_deserialize must be used to
1947    /// deserialize. No metadata is sent, not even version.
1948    pub fn bare_serialize<T: Serialize>(writer: &mut W, file_version: u32, data: &T) -> Result<(), SavefileError> {
1949        let mut serializer = Serializer { writer, file_version };
1950        data.serialize(&mut serializer)?;
1951        writer.flush()?;
1952        Ok(())
1953    }
1954
1955    #[inline(always)]
1956    fn save_impl<T: Serialize>(
1957        writer: &mut W,
1958        version: u32,
1959        data: &T,
1960        with_schema: Option<Schema>,
1961        with_compression: bool,
1962        lib_version_override: Option<u16>,
1963    ) -> Result<(), SavefileError> {
1964        let header = "savefile\0".to_string().into_bytes();
1965
1966        writer.write_all(&header)?; //9
1967
1968        writer.write_u16::<LittleEndian>(
1969            lib_version_override.unwrap_or(CURRENT_SAVEFILE_LIB_VERSION), /*savefile format version*/
1970        )?;
1971        writer.write_u32::<LittleEndian>(version)?;
1972        // 9 + 2 + 4 = 15
1973        {
1974            if with_compression {
1975                writer.write_u8(1)?; //15 + 1 = 16
1976
1977                #[cfg(feature = "bzip2")]
1978                {
1979                    let mut compressed_writer = bzip2::write::BzEncoder::new(writer, Compression::best());
1980                    if let Some(schema) = with_schema {
1981                        let mut schema_serializer = Serializer::<bzip2::write::BzEncoder<W>>::new_raw(
1982                            &mut compressed_writer,
1983                            lib_version_override.unwrap_or(CURRENT_SAVEFILE_LIB_VERSION) as u32,
1984                        );
1985                        schema.serialize(&mut schema_serializer)?;
1986                    }
1987
1988                    let mut serializer = Serializer {
1989                        writer: &mut compressed_writer,
1990                        file_version: version,
1991                    }; //Savefile always serializes most recent version. Only savefile-abi ever writes old formats.
1992                    data.serialize(&mut serializer)?;
1993                    compressed_writer.flush()?;
1994                    return Ok(());
1995                }
1996                #[cfg(not(feature = "bzip2"))]
1997                {
1998                    return Err(SavefileError::CompressionSupportNotCompiledIn);
1999                }
2000            } else {
2001                writer.write_u8(0)?;
2002                if let Some(schema) = with_schema {
2003                    let mut schema_serializer = Serializer::<W>::new_raw(
2004                        writer,
2005                        lib_version_override.unwrap_or(CURRENT_SAVEFILE_LIB_VERSION) as u32,
2006                    );
2007                    schema.serialize(&mut schema_serializer)?;
2008                }
2009
2010                let mut serializer = Serializer {
2011                    writer,
2012                    file_version: version,
2013                };
2014                data.serialize(&mut serializer)?;
2015                writer.flush()?;
2016                Ok(())
2017            }
2018        }
2019    }
2020
2021    /// Create a Serializer.
2022    /// Don't use this method directly, use the [crate::save] function
2023    /// instead.
2024    pub fn new_raw(writer: &mut impl Write, file_version: u32) -> Serializer<'_, impl Write> {
2025        Serializer { writer, file_version }
2026    }
2027}
2028
2029impl<TR: Read> Deserializer<'_, TR> {
2030    /// Reads a u8 and return true if equal to 1
2031    pub fn read_bool(&mut self) -> Result<bool, SavefileError> {
2032        Ok(self.reader.read_u8()? == 1)
2033    }
2034    /// Reads an u8
2035    pub fn read_u8(&mut self) -> Result<u8, SavefileError> {
2036        let mut buf = [0u8];
2037        self.reader.read_exact(&mut buf)?;
2038        Ok(buf[0])
2039    }
2040    /// Reads a little endian u16
2041    pub fn read_u16(&mut self) -> Result<u16, SavefileError> {
2042        Ok(self.reader.read_u16::<LittleEndian>()?)
2043    }
2044    /// Reads a little endian u32
2045    pub fn read_u32(&mut self) -> Result<u32, SavefileError> {
2046        Ok(self.reader.read_u32::<LittleEndian>()?)
2047    }
2048    /// Reads a little endian u64
2049    pub fn read_u64(&mut self) -> Result<u64, SavefileError> {
2050        Ok(self.reader.read_u64::<LittleEndian>()?)
2051    }
2052
2053    /// Reads the raw bit pattern of a pointer
2054    /// # Safety
2055    /// The stream must contain a valid pointer to T.
2056    pub unsafe fn read_raw_ptr<T: ?Sized>(&mut self) -> Result<*const T, SavefileError> {
2057        let mut temp = MaybeUninit::<*const T>::zeroed();
2058
2059        let temp_data = &mut temp as *mut MaybeUninit<*const T> as *mut u8;
2060        let temp_size = std::mem::size_of::<*const T>();
2061        let buf = unsafe { slice::from_raw_parts_mut(temp_data, temp_size) };
2062
2063        self.read_bytes_to_buf(buf)?;
2064
2065        Ok(unsafe { temp.assume_init() })
2066    }
2067    /// Reads the raw bit pattern of a pointer
2068    /// # Safety
2069    /// The stream must contain a valid pointer to T.
2070    pub unsafe fn read_raw_ptr_mut<T: ?Sized>(&mut self) -> Result<*mut T, SavefileError> {
2071        let mut temp = MaybeUninit::<*mut T>::zeroed();
2072
2073        let temp_data = &mut temp as *mut MaybeUninit<*mut T> as *mut u8;
2074        let temp_size = std::mem::size_of::<*mut T>();
2075        let buf = unsafe { slice::from_raw_parts_mut(temp_data, temp_size) };
2076
2077        self.read_bytes_to_buf(buf)?;
2078
2079        Ok(unsafe { temp.assume_init() })
2080    }
2081    /// Reads a pointer
2082    pub fn read_ptr(&mut self) -> Result<*const (), SavefileError> {
2083        let mut ptr: MaybeUninit<*const ()> = MaybeUninit::zeroed();
2084        let data = ptr.as_mut_ptr();
2085        let target = unsafe { slice::from_raw_parts_mut(data as *mut u8, std::mem::size_of::<*const ()>()) };
2086        self.reader.read_exact(target)?;
2087        Ok(unsafe { ptr.assume_init() })
2088    }
2089    /// Reads a little endian u128
2090    pub fn read_u128(&mut self) -> Result<u128, SavefileError> {
2091        Ok(self.reader.read_u128::<LittleEndian>()?)
2092    }
2093    /// Reads an i8
2094    pub fn read_i8(&mut self) -> Result<i8, SavefileError> {
2095        Ok(self.reader.read_i8()?)
2096    }
2097    /// Reads a little endian i16
2098    pub fn read_i16(&mut self) -> Result<i16, SavefileError> {
2099        Ok(self.reader.read_i16::<LittleEndian>()?)
2100    }
2101    /// Reads a little endian i32
2102    pub fn read_i32(&mut self) -> Result<i32, SavefileError> {
2103        Ok(self.reader.read_i32::<LittleEndian>()?)
2104    }
2105    /// Reads a little endian i64
2106    pub fn read_i64(&mut self) -> Result<i64, SavefileError> {
2107        Ok(self.reader.read_i64::<LittleEndian>()?)
2108    }
2109    /// Reads a little endian i128
2110    pub fn read_i128(&mut self) -> Result<i128, SavefileError> {
2111        Ok(self.reader.read_i128::<LittleEndian>()?)
2112    }
2113    /// Reads a little endian f32
2114    pub fn read_f32(&mut self) -> Result<f32, SavefileError> {
2115        Ok(self.reader.read_f32::<LittleEndian>()?)
2116    }
2117    /// Reads a little endian f64
2118    pub fn read_f64(&mut self) -> Result<f64, SavefileError> {
2119        Ok(self.reader.read_f64::<LittleEndian>()?)
2120    }
2121    /// Reads an i64 into an isize. For 32 bit architectures, the function fails on overflow.
2122    pub fn read_isize(&mut self) -> Result<isize, SavefileError> {
2123        if let Ok(val) = TryFrom::try_from(self.reader.read_i64::<LittleEndian>()?) {
2124            Ok(val)
2125        } else {
2126            Err(SavefileError::SizeOverflow)
2127        }
2128    }
2129    /// Reads an u64 into an usize. For 32 bit architectures, the function fails on overflow.
2130    pub fn read_usize(&mut self) -> Result<usize, SavefileError> {
2131        if let Ok(val) = TryFrom::try_from(self.reader.read_u64::<LittleEndian>()?) {
2132            Ok(val)
2133        } else {
2134            Err(SavefileError::SizeOverflow)
2135        }
2136    }
2137    /// Reads a 64 bit length followed by an utf8 encoded string. Fails if data is not valid utf8
2138    pub fn read_string(&mut self) -> Result<String, SavefileError> {
2139        let l = self.read_usize()?;
2140        #[cfg(feature = "size_sanity_checks")]
2141        {
2142            if l > 1_000_000 {
2143                return Err(SavefileError::GeneralError {
2144                    msg: format!("String too large: {}", l),
2145                });
2146            }
2147        }
2148        let mut v = vec![0; l];
2149        self.reader.read_exact(&mut v)?;
2150        Ok(String::from_utf8(v)?)
2151    }
2152
2153    /// Reads 'len' raw u8 bytes as a `Vec<u8>`
2154    pub fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, SavefileError> {
2155        let mut v = vec![0; len];
2156        self.reader.read_exact(&mut v)?;
2157        Ok(v)
2158    }
2159    /// Reads raw u8 bytes into the given buffer. The buffer size must be
2160    /// equal to the number of bytes desired to be read.
2161    pub fn read_bytes_to_buf(&mut self, buf: &mut [u8]) -> Result<(), SavefileError> {
2162        self.reader.read_exact(buf)?;
2163        Ok(())
2164    }
2165
2166    /// Deserialize an object of type T from the given reader.
2167    /// Don't use this method directly, use the [crate::load] function
2168    /// instead.
2169    pub fn load<T: WithSchema + Deserialize>(reader: &mut TR, version: u32) -> Result<T, SavefileError> {
2170        Deserializer::<_>::load_impl::<T>(
2171            reader,
2172            version,
2173            Some(|version| T::schema(version, &mut WithSchemaContext::new())),
2174        )
2175    }
2176
2177    /// Deserialize an object of type T from the given reader.
2178    /// Don't use this method directly, use the [crate::load_noschema] function
2179    /// instead.
2180    pub fn load_noschema<T: Deserialize>(reader: &mut TR, version: u32) -> Result<T, SavefileError> {
2181        let dummy: Option<fn(u32) -> Schema> = None;
2182        Deserializer::<TR>::load_impl::<T>(reader, version, dummy)
2183    }
2184
2185    /// Deserialize data which was serialized using 'bare_serialize'
2186    pub fn bare_deserialize<T: Deserialize>(reader: &mut TR, file_version: u32) -> Result<T, SavefileError> {
2187        let mut deserializer = Deserializer {
2188            reader,
2189            file_version,
2190            ephemeral_state: HashMap::new(),
2191        };
2192        Ok(T::deserialize(&mut deserializer)?)
2193    }
2194
2195    #[inline(always)]
2196    fn load_impl<T: Deserialize>(
2197        reader: &mut TR,
2198        version: u32,
2199        expected_schema: Option<impl FnOnce(u32) -> Schema>,
2200    ) -> Result<T, SavefileError> {
2201        let mut head: [u8; 9] = [0u8; 9];
2202        reader.read_exact(&mut head)?;
2203
2204        if head[..] != ("savefile\0".to_string().into_bytes())[..] {
2205            return Err(SavefileError::GeneralError {
2206                msg: "File is not in new savefile-format.".into(),
2207            });
2208        }
2209
2210        let savefile_lib_version = reader.read_u16::<LittleEndian>()?;
2211        if savefile_lib_version > CURRENT_SAVEFILE_LIB_VERSION {
2212            return Err(SavefileError::GeneralError {
2213                msg: "This file has been created by a future, incompatible version of the savefile crate.".into(),
2214            });
2215        }
2216        let file_ver = reader.read_u32::<LittleEndian>()?;
2217
2218        if file_ver > version {
2219            return Err(SavefileError::WrongVersion {
2220                msg: format!(
2221                    "File has later version ({}) than structs in memory ({}).",
2222                    file_ver, version
2223                ),
2224            });
2225        }
2226        let with_compression = reader.read_u8()? != 0;
2227
2228        if with_compression {
2229            #[cfg(feature = "bzip2")]
2230            {
2231                let mut compressed_reader = bzip2::read::BzDecoder::new(reader);
2232                if let Some(memory_schema) = expected_schema {
2233                    let mut schema_deserializer = new_schema_deserializer(&mut compressed_reader, savefile_lib_version);
2234                    let memory_schema = memory_schema(file_ver);
2235                    let file_schema = Schema::deserialize(&mut schema_deserializer)?;
2236
2237                    if let Some(err) = diff_schema(&memory_schema, &file_schema, ".".to_string(), false) {
2238                        return Err(SavefileError::IncompatibleSchema {
2239                            message: format!(
2240                                "Saved schema differs from in-memory schema for version {}. Error: {}",
2241                                file_ver, err
2242                            ),
2243                        });
2244                    }
2245                }
2246                let mut deserializer = Deserializer {
2247                    reader: &mut compressed_reader,
2248                    file_version: file_ver,
2249                    ephemeral_state: HashMap::new(),
2250                };
2251                Ok(T::deserialize(&mut deserializer)?)
2252            }
2253            #[cfg(not(feature = "bzip2"))]
2254            {
2255                return Err(SavefileError::CompressionSupportNotCompiledIn);
2256            }
2257        } else {
2258            if let Some(memory_schema) = expected_schema {
2259                let mut schema_deserializer = new_schema_deserializer(reader, savefile_lib_version);
2260                let memory_schema = memory_schema(file_ver);
2261                let file_schema = Schema::deserialize(&mut schema_deserializer)?;
2262
2263                if let Some(err) = diff_schema(&memory_schema, &file_schema, ".".to_string(), false) {
2264                    return Err(SavefileError::IncompatibleSchema {
2265                        message: format!(
2266                            "Saved schema differs from in-memory schema for version {}. Error: {}",
2267                            file_ver, err
2268                        ),
2269                    });
2270                }
2271            }
2272            let mut deserializer = Deserializer {
2273                reader,
2274                file_version: file_ver,
2275                ephemeral_state: HashMap::new(),
2276            };
2277            Ok(T::deserialize(&mut deserializer)?)
2278        }
2279    }
2280}
2281
2282/// Create a Deserializer.
2283/// Don't use this method directly, use the [crate::load] function
2284/// instead.
2285pub fn new_schema_deserializer(reader: &mut impl Read, file_schema_version: u16) -> Deserializer<'_, impl Read> {
2286    Deserializer {
2287        reader,
2288        file_version: file_schema_version as u32,
2289        ephemeral_state: HashMap::new(),
2290    }
2291}
2292
2293/// Deserialize an instance of type T from the given `reader` .
2294///
2295/// The current type of T in memory must be equal to `version`.
2296/// The deserializer will use the actual protocol version in the
2297/// file to do the deserialization.
2298pub fn load<T: WithSchema + Deserialize>(reader: &mut impl Read, version: u32) -> Result<T, SavefileError> {
2299    Deserializer::<_>::load::<T>(reader, version)
2300}
2301
2302/// Deserialize an instance of type T from the given u8 slice .
2303///
2304/// The current type of T in memory must be equal to `version`.
2305/// The deserializer will use the actual protocol version in the
2306/// file to do the deserialization.
2307pub fn load_from_mem<T: WithSchema + Deserialize>(input: &[u8], version: u32) -> Result<T, SavefileError> {
2308    let mut input = input;
2309    Deserializer::load::<T>(&mut input, version)
2310}
2311
2312/// Write the given `data` to the `writer`.
2313///
2314/// The current version of data must be `version`.
2315pub fn save<T: WithSchema + Serialize>(writer: &mut impl Write, version: u32, data: &T) -> Result<(), SavefileError> {
2316    Serializer::save::<T>(writer, version, data, false)
2317}
2318
2319/// Write the given `data` to the `writer`. Compresses data using 'bzip2' compression format.
2320///
2321/// The current version of data must be `version`.
2322/// The resultant data can be loaded using the regular load-function (it autodetects if compressions was
2323/// active or not).
2324/// Note, this function will fail if the bzip2-feature is not enabled.
2325pub fn save_compressed<T: WithSchema + Serialize>(
2326    writer: &mut impl Write,
2327    version: u32,
2328    data: &T,
2329) -> Result<(), SavefileError> {
2330    Serializer::save::<T>(writer, version, data, true)
2331}
2332
2333/// Write the given `data` to the file. Compresses data using 'bzip2' compression format.
2334///
2335/// The current version of data must be `version`.
2336/// The resultant data can be loaded using the regular load_file-function (it autodetects if compressions was
2337/// active or not).
2338/// Note, this function will fail if the bzip2-feature is not enabled.
2339pub fn save_file_compressed<T: WithSchema + Serialize, P: AsRef<Path>>(
2340    path: P,
2341    version: u32,
2342    data: &T,
2343) -> Result<(), SavefileError> {
2344    let mut f = BufWriter::new(File::create(path)?);
2345    Serializer::save::<T>(&mut f, version, data, true)
2346}
2347
2348/// Serialize the given data and return as a `Vec<u8>`
2349/// The current version of data must be `version`.
2350pub fn save_to_mem<T: WithSchema + Serialize>(version: u32, data: &T) -> Result<Vec<u8>, SavefileError> {
2351    let mut retval = Vec::new();
2352    Serializer::save::<T>(&mut retval, version, data, false)?;
2353    Ok(retval)
2354}
2355
2356/// Like [crate::load] , but used to open files saved without schema,
2357/// by one of the _noschema versions of the save functions.
2358pub fn load_noschema<T: Deserialize>(reader: &mut impl Read, version: u32) -> Result<T, SavefileError> {
2359    Deserializer::<_>::load_noschema::<T>(reader, version)
2360}
2361
2362/// Write the given `data` to the `writer`, without a schema.
2363///
2364/// The current version of data must be `version`.
2365/// Do this write without writing any schema to disk.
2366/// As long as all the serializers and deserializers
2367/// are correctly written, the schema is not necessary.
2368/// Omitting the schema saves some space in the saved file,
2369/// but means that any mistake in implementation of the
2370/// Serialize or Deserialize traits will cause hard-to-troubleshoot
2371/// data corruption instead of a nice error message.
2372pub fn save_noschema<T: Serialize>(writer: &mut impl Write, version: u32, data: &T) -> Result<(), SavefileError> {
2373    Serializer::save_noschema::<T>(writer, version, data)
2374}
2375
2376/// Like [crate::load] , except it deserializes from the given file in the filesystem.
2377/// This is a pure convenience function.
2378pub fn load_file<T: WithSchema + Deserialize, P: AsRef<Path>>(filepath: P, version: u32) -> Result<T, SavefileError> {
2379    let mut f = BufReader::new(File::open(filepath)?);
2380    Deserializer::load::<T>(&mut f, version)
2381}
2382
2383/// Like [crate::save] , except it opens a file on the filesystem and writes
2384/// the data to it. This is a pure convenience function.
2385pub fn save_file<T: WithSchema + Serialize, P: AsRef<Path>>(
2386    filepath: P,
2387    version: u32,
2388    data: &T,
2389) -> Result<(), SavefileError> {
2390    let mut f = BufWriter::new(File::create(filepath)?);
2391    Serializer::save::<T>(&mut f, version, data, false)
2392}
2393
2394/// Like [crate::load_noschema] , except it deserializes from the given file in the filesystem.
2395/// This is a pure convenience function.
2396pub fn load_file_noschema<T: Deserialize, P: AsRef<Path>>(filepath: P, version: u32) -> Result<T, SavefileError> {
2397    let mut f = BufReader::new(File::open(filepath)?);
2398    Deserializer::load_noschema::<T>(&mut f, version)
2399}
2400
2401/// Like [crate::save_noschema] , except it opens a file on the filesystem and writes
2402/// the data to it.
2403///
2404/// This is a pure convenience function.
2405pub fn save_file_noschema<T: Serialize, P: AsRef<Path>>(
2406    filepath: P,
2407    version: u32,
2408    data: &T,
2409) -> Result<(), SavefileError> {
2410    let mut f = BufWriter::new(File::create(filepath)?);
2411    Serializer::save_noschema::<T>(&mut f, version, data)
2412}
2413
2414/// Context object used to keep track of recursion.
2415///
2416/// Datastructures which cannot contain recursion do not need to concern themselves with
2417/// this. Recursive data structures in rust require the use of Box, Vec, Arc or similar.
2418/// The most common of these datatypes from std are supported by savefile, and will guard
2419/// against recursion in a well-defined way.
2420/// As a user of Savefile, you only need to use this if you are implementing Savefile for
2421/// container or smart-pointer type.
2422pub struct WithSchemaContext {
2423    seen_types: HashMap<TypeId, usize /*depth*/>,
2424}
2425
2426impl WithSchemaContext {
2427    /// Create a new empty WithSchemaContext.
2428    /// This is useful for calling ::schema at the top-level.
2429    pub fn new() -> WithSchemaContext {
2430        let seen_types = HashMap::new();
2431        WithSchemaContext { seen_types }
2432    }
2433}
2434
2435impl WithSchemaContext {
2436    /// Use this when returning the schema of a type that can be part of a recursion.
2437    /// For example, given a hypothetical user-implemented type MyBox, do
2438    ///
2439    /// ```rust
2440    /// use savefile::{Schema, WithSchema, WithSchemaContext};
2441    /// #[repr(transparent)]
2442    /// struct MyBox<T> {
2443    ///    content: *const T
2444    /// }
2445    /// impl<T:WithSchema + 'static> WithSchema for MyBox<T> {
2446    ///     fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
2447    ///         context.possible_recursion::<MyBox<T>>(|context| Schema::Boxed(Box::new(T::schema(version, context))))
2448    ///     }
2449    /// }
2450    /// ```
2451    ///
2452    /// If recursion is detected (traversing to exactly `MyBox<T>` twice, in the above example), the method
2453    /// 'possible_recursion' will return Schema::Recursion, stopping the Schema instance from becoming infinitely big.
2454    ///
2455    pub fn possible_recursion<T: 'static>(&mut self, cb: impl FnOnce(&mut WithSchemaContext) -> Schema) -> Schema {
2456        let typeid = TypeId::of::<T>();
2457        let prevlen = self.seen_types.len();
2458        match self.seen_types.entry(typeid) {
2459            Entry::Occupied(occ) => {
2460                let present_value_depth = *occ.get();
2461                return Schema::Recursion(prevlen - present_value_depth);
2462            }
2463            Entry::Vacant(vac) => {
2464                vac.insert(prevlen);
2465            }
2466        }
2467        let ret = (cb)(self);
2468        self.seen_types.remove(&typeid);
2469        ret
2470    }
2471}
2472
2473/// This trait must be implemented by all data structures you wish to be able to save.
2474///
2475/// It must encode the schema for the datastructure when saved using the given version number.
2476/// When files are saved, the schema is encoded into the file.
2477/// when loading, the schema is inspected to make sure that the load will safely succeed.
2478/// This is only for increased safety, the file format does not in fact use the schema for any other
2479/// purpose, the design is schema-less at the core, the schema is just an added layer of safety (which
2480/// can be disabled).
2481#[cfg_attr(
2482    feature = "rust1_78",
2483    diagnostic::on_unimplemented(
2484        message = "`{Self}` does not have a defined schema for savefile, since it doesn't implement the trait `savefile::WithSchema`",
2485        label = "This cannot be serialized or deserialized with a schema",
2486        note = "You can implement it by adding `#[derive(Savefile)]` before the declaration of `{Self}`",
2487        note = "Or you can manually implement the `savefile::WithSchema` trait.",
2488        note = "You can also use one of the `*_noschema` functions to save/load without a schema."
2489    )
2490)]
2491pub trait WithSchema {
2492    /// Returns a representation of the schema used by this Serialize implementation for the given version.
2493    /// The WithSchemaContext can be used to guard against recursive data structures.
2494    /// See documentation of WithSchemaContext.
2495    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema;
2496}
2497
2498/// Create a new WithSchemaContext, and then call 'schema' on type T.
2499/// This is a useful convenience method.
2500pub fn get_schema<T: WithSchema + 'static>(version: u32) -> Schema {
2501    T::schema(version, &mut WithSchemaContext::new())
2502}
2503
2504/// Get the schema for a type Result<OK, ERR>, where OK and ERR
2505/// have the schemas given by the parameters.
2506pub fn get_result_schema(ok: Schema, err: Schema) -> Schema {
2507    Schema::Enum(SchemaEnum {
2508        dbg_name: "Result".to_string(),
2509        size: None,
2510        alignment: None,
2511        variants: vec![
2512            Variant {
2513                name: "Ok".to_string(),
2514                discriminant: 0,
2515                fields: vec![Field {
2516                    name: "ok".to_string(),
2517                    value: Box::new(ok),
2518                    offset: None,
2519                }],
2520            },
2521            Variant {
2522                name: "Err".to_string(),
2523                discriminant: 0,
2524                fields: vec![Field {
2525                    name: "err".to_string(),
2526                    value: Box::new(err),
2527                    offset: None,
2528                }],
2529            },
2530        ],
2531        discriminant_size: 1,
2532        has_explicit_repr: false,
2533    })
2534}
2535
2536/// This trait must be implemented for all data structures you wish to be
2537/// able to serialize.
2538///
2539/// To actually serialize data: create a [Serializer],
2540/// then call serialize on your data to save, giving the Serializer
2541/// as an argument.
2542///
2543/// The most convenient way to implement this is to use
2544/// `use savefile-derive::Savefile;`
2545///
2546/// and the use #\[derive(Serialize)]
2547#[cfg_attr(
2548    feature = "rust1_78",
2549    diagnostic::on_unimplemented(
2550        message = "`{Self}` cannot be serialized by Savefile, since it doesn't implement the trait `savefile::Serialize`",
2551        label = "This cannot be serialized",
2552        note = "You can implement it by adding `#[derive(Savefile)]` before the declaration of `{Self}`",
2553        note = "Or you can manually implement the `savefile::Serialize` trait."
2554    )
2555)]
2556pub trait Serialize: WithSchema {
2557    /// Serialize self into the given serializer.
2558    ///
2559    /// In versions prior to 0.15, 'Serializer' did not accept a type parameter.
2560    /// It now requires a type parameter with the type of writer expected.
2561    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError>; //TODO: Do error handling
2562}
2563
2564/// A child of an object implementing Introspect.
2565///
2566/// Is a key-value pair. The only reason this is not
2567/// simply (String, &dyn Introspect) is that Mutex wouldn't be introspectable in that case.
2568/// Mutex needs something like `(String, MutexGuard<T>)`. By having this a trait,
2569/// different types can have whatever reference holder needed (MutexGuard, RefMut etc).
2570#[cfg_attr(
2571    feature = "rust1_78",
2572    diagnostic::on_unimplemented(
2573        message = "`{Self}` cannot be an introspected value used by Savefile, since it doesn't implement the trait `savefile::IntrospectItem`",
2574        label = "This cannot be the type of an introspected field value",
2575        note = "You can possibly implement IntrospectItem manually for the type `{Self}`, or try to use `String` instead of `{Self}`."
2576    )
2577)]
2578pub trait IntrospectItem<'a> {
2579    /// Should return a descriptive string for the given child. For structures,
2580    /// this would be the field name, for instance.
2581    fn key(&self) -> &str;
2582    /// The introspectable value of the child.
2583    fn val(&self) -> &dyn Introspect;
2584}
2585
2586/// This is an zero-sized introspectable object with no value and no children.
2587/// It is used for situations where you wish to have a key but no value.
2588struct NullIntrospectable {}
2589static THE_NULL_INTROSPECTABLE: NullIntrospectable = NullIntrospectable {};
2590
2591impl Introspect for NullIntrospectable {
2592    fn introspect_value(&self) -> String {
2593        String::new()
2594    }
2595
2596    fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
2597        None
2598    }
2599    fn introspect_len(&self) -> usize {
2600        0
2601    }
2602}
2603
2604impl IntrospectItem<'_> for str {
2605    fn key(&self) -> &str {
2606        self
2607    }
2608
2609    fn val(&self) -> &dyn Introspect {
2610        &THE_NULL_INTROSPECTABLE
2611    }
2612}
2613
2614impl IntrospectItem<'_> for String {
2615    fn key(&self) -> &str {
2616        self
2617    }
2618
2619    fn val(&self) -> &dyn Introspect {
2620        &THE_NULL_INTROSPECTABLE
2621    }
2622}
2623
2624/// Max number of introspect children.
2625///
2626/// As a sort of guard against infinite loops, the default 'len'-implementation only
2627/// ever iterates this many times. This is so that broken 'introspect_child'-implementations
2628/// won't cause introspect_len to iterate forever.
2629pub const MAX_CHILDREN: usize = 10000;
2630
2631/// Gives the ability to look into an object, inspecting any children (fields).
2632#[cfg_attr(
2633    feature = "rust1_78",
2634    diagnostic::on_unimplemented(
2635        message = "`{Self}` cannot be introspected by Savefile, since it doesn't implement trait `savefile::Introspect`",
2636        label = "This cannot be introspected",
2637        note = "If you get this message after having used the #[savefile_ignore] attribute on a field, consider adding #[savefile_introspect_ignore].",
2638        note = "You can implement it by adding `#[derive(Savefile)]` or `#[derive(SavefileIntrospectOnly)]` before the declaration of `{Self}`",
2639        note = "Or you can manually implement the `savefile::Introspect` trait."
2640    )
2641)]
2642pub trait Introspect {
2643    /// Returns the value of the object, excluding children, as a string.
2644    /// Exactly what the value returned here is depends on the type.
2645    /// For some types, like a plain array, there isn't much of a value,
2646    /// the entire information of object resides in the children.
2647    /// For other cases, like a department in an organisation, it might
2648    /// make sense to have the value be the name, and have all the other properties
2649    /// as children.
2650    fn introspect_value(&self) -> String;
2651
2652    /// Returns an the name and &dyn Introspect for the child with the given index,
2653    /// or if no child with that index exists, None.
2654    /// All the children should be indexed consecutively starting at 0 with no gaps,
2655    /// all though there isn't really anything stopping the user of the trait to have
2656    /// any arbitrary index strategy, consecutive numbering 0, 1, 2, ... etc is strongly
2657    /// encouraged.
2658    fn introspect_child<'a>(&'a self, index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>>;
2659
2660    /// Returns the total number of children.
2661    /// The default implementation calculates this by simply calling introspect_child with
2662    /// higher and higher indexes until it returns None.
2663    /// It gives up if the count reaches 10000. If your type can be bigger
2664    /// and you want to be able to introspect it, override this method.
2665    fn introspect_len(&self) -> usize {
2666        for child_index in 0..MAX_CHILDREN {
2667            if self.introspect_child(child_index).is_none() {
2668                return child_index;
2669            }
2670        }
2671        return MAX_CHILDREN;
2672    }
2673}
2674
2675/// This trait must be implemented for all data structures you wish to
2676/// be able to deserialize.
2677///
2678/// The most convenient way to implement this is to use
2679/// `use savefile-derive::Savefile`
2680///
2681/// and the use #\[derive(Deserialize)]
2682#[cfg_attr(
2683    feature = "rust1_78",
2684    diagnostic::on_unimplemented(
2685        message = "`{Self}` cannot be deserialized by Savefile, since it doesn't implement the trait `savefile::Deserialize`",
2686        label = "This cannot be deserialized",
2687        note = "You can implement it by adding `#[derive(Savefile)]` before the declaration of `{Self}`",
2688        note = "Or you can manually implement the `savefile::Deserialize` trait."
2689    )
2690)]
2691pub trait Deserialize: WithSchema + Sized {
2692    /// Deserialize and return an instance of Self from the given deserializer.
2693    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError>; //TODO: Do error handling
2694}
2695
2696/// A field is serialized according to its value.
2697/// The name is just for diagnostics.
2698#[derive(Debug, PartialEq, Clone)]
2699#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
2700pub struct Field {
2701    /// Field name
2702    pub name: String,
2703    /// Field type
2704    pub value: Box<Schema>,
2705    /// The field offset within the struct, if known.
2706    /// This is used to determine layout compatibility between different shared libraries,
2707    /// when using the savefile-abi crate. A value of None means offset is not known.
2708    /// For fields in enums, the offset is the offset from the start of memory of the enum.
2709    /// For a repr(C,?)-enum, this will be the offset from the start of the discriminant.
2710    /// For repr(rust)-enums, the discriminant may not be at the start of the memory layout.
2711    /// Note - if this is !=None, then it is important that the value at the given offset
2712    /// is actually an instance of the type given by the schema in 'value'. Otherwise,
2713    /// layout compatibility calculations may fail, with catastrophic consequences.
2714    offset: Option<usize>,
2715}
2716
2717impl Field {
2718    /// Create a new instance of field, with the given name and type
2719    pub fn new(name: String, value: Box<Schema>) -> Field {
2720        Field {
2721            name,
2722            value,
2723            offset: None,
2724        }
2725    }
2726    /// Create a new instance of field, with the given name and type.
2727    /// The offset is the offset of the field within its struct.
2728    ///
2729    /// # Safety
2730    /// The offset *must* be the correct offset of the field within its struct.
2731    pub unsafe fn unsafe_new(name: String, value: Box<Schema>, offset: Option<usize>) -> Field {
2732        Field { name, value, offset }
2733    }
2734    /// Determine if the two fields are laid out identically in memory, in their parent objects.
2735    pub fn layout_compatible(&self, other: &Field) -> bool {
2736        let (Some(offset_a), Some(offset_b)) = (self.offset, other.offset) else {
2737            return false;
2738        };
2739        if offset_a != offset_b {
2740            return false;
2741        }
2742        self.value.layout_compatible(&other.value)
2743    }
2744}
2745
2746/// An array is serialized by serializing its items one by one,
2747/// without any padding.
2748/// The dbg_name is just for diagnostics.
2749#[derive(Debug, PartialEq, Clone)]
2750#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
2751pub struct SchemaArray {
2752    /// Type of array elements
2753    pub item_type: Box<Schema>,
2754    /// Length of array
2755    pub count: usize,
2756}
2757
2758impl SchemaArray {
2759    fn layout_compatible(&self, other: &SchemaArray) -> bool {
2760        if self.count != other.count {
2761            return false;
2762        }
2763        self.item_type.layout_compatible(&other.item_type)
2764    }
2765    fn serialized_size(&self) -> Option<usize> {
2766        self.item_type.serialized_size().map(|x| x * self.count)
2767    }
2768}
2769
2770/// Schema for a struct.
2771///
2772/// A struct is serialized by serializing its fields one by one,
2773/// without any padding.
2774/// The dbg_name is just for diagnostics.
2775/// The memory format is given by size, alignment and the various
2776/// field offsets. If any field lacks an offset, the memory format
2777/// is unspecified.
2778#[derive(Debug, PartialEq, Clone)]
2779#[repr(C)]
2780#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
2781pub struct SchemaStruct {
2782    /// Diagnostic value
2783    pub dbg_name: String,
2784    /// If None, the memory layout of the struct is unspecified.
2785    /// Otherwise, the size of the struct in memory (`std::mem::size_of::<TheStruct>()`).
2786    size: Option<usize>,
2787    /// If None, the memory layout of the struct is unspecified.
2788    /// Otherwise, the alignment of the struct (`std::mem::align_of::<TheStruct>()`).
2789    alignment: Option<usize>,
2790    /// Fields of struct
2791    pub fields: Vec<Field>,
2792}
2793fn maybe_add(a: Option<usize>, b: Option<usize>) -> Option<usize> {
2794    if let Some(a) = a {
2795        if let Some(b) = b {
2796            return Some(a + b);
2797        }
2798    }
2799    None
2800}
2801impl SchemaStruct {
2802    /// * dbg_name: The name of the struct
2803    /// * fields: The fields of the struct
2804    pub fn new(dbg_name: String, fields: Vec<Field>) -> SchemaStruct {
2805        SchemaStruct {
2806            dbg_name,
2807            fields,
2808            size: None,
2809            alignment: None,
2810        }
2811    }
2812    /// * dbg_name: The name of the struct
2813    /// * fields: The fields of the struct
2814    /// * size: If None, the memory layout of the struct is unspecified.
2815    ///   Otherwise, the size of the struct in memory (`std::mem::size_of::<TheStruct>()`).
2816    /// * alignment: If None, the memory layout of the struct is unspecified.
2817    ///   Otherwise, the alignment of the struct (`std::mem::align_of::<TheStruct>()`).
2818    pub fn new_unsafe(
2819        dbg_name: String,
2820        fields: Vec<Field>,
2821        size: Option<usize>,
2822        alignment: Option<usize>,
2823    ) -> SchemaStruct {
2824        SchemaStruct {
2825            dbg_name,
2826            fields,
2827            size,
2828            alignment,
2829        }
2830    }
2831
2832    fn layout_compatible(&self, other: &SchemaStruct) -> bool {
2833        if self.fields.len() != other.fields.len() {
2834            return false;
2835        }
2836        if self.alignment.is_none() || self.size.is_none() {
2837            return false;
2838        }
2839        if self.alignment != other.alignment || self.size != other.size {
2840            return false;
2841        }
2842        for (a, b) in self.fields.iter().zip(other.fields.iter()) {
2843            if !a.layout_compatible(b) {
2844                return false;
2845            }
2846        }
2847        true
2848    }
2849    fn serialized_size(&self) -> Option<usize> {
2850        self.fields
2851            .iter()
2852            .fold(Some(0usize), |prev, x| maybe_add(prev, x.value.serialized_size()))
2853    }
2854}
2855
2856/// An enum variant is serialized as its fields, one by one,
2857/// without any padding.
2858#[derive(Debug, PartialEq, Clone)]
2859#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
2860pub struct Variant {
2861    /// Name of variant
2862    pub name: String,
2863    /// Discriminant in binary file-format
2864    pub discriminant: u8,
2865    /// Fields of variant
2866    pub fields: Vec<Field>,
2867}
2868impl Variant {
2869    fn layout_compatible(&self, other: &Variant) -> bool {
2870        if self.discriminant != other.discriminant {
2871            return false;
2872        }
2873        if self.fields.len() != other.fields.len() {
2874            return false;
2875        }
2876        for (a, b) in self.fields.iter().zip(other.fields.iter()) {
2877            if !a.layout_compatible(b) {
2878                return false;
2879            }
2880        }
2881        true
2882    }
2883    fn serialized_size(&self) -> Option<usize> {
2884        self.fields
2885            .iter()
2886            .fold(Some(0usize), |prev, x| maybe_add(prev, x.value.serialized_size()))
2887    }
2888}
2889
2890/// Schema for an enum.
2891///
2892/// An enum is serialized as its u8 variant discriminant
2893/// followed by all the field for that variant.
2894/// The name of each variant, as well as its order in
2895/// the enum (the discriminant), is significant.
2896/// The memory format is given by 'has_explicit_repr',
2897/// 'discriminant_size', 'size', 'alignment' and the vairous variants.
2898///
2899/// Note: If 'has_explicit_repr' is false,
2900/// the memory format is unspecified.
2901#[derive(Debug, PartialEq, Clone)]
2902#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
2903pub struct SchemaEnum {
2904    /// Diagnostic name
2905    pub dbg_name: String,
2906    /// Variants of enum
2907    pub variants: Vec<Variant>,
2908    /// If this is a repr(uX)-enum, then the size of the discriminant, in bytes.
2909    /// Valid values are 1, 2 or 4.
2910    /// Otherwise, this is the number of bytes needed to represent the discriminant.
2911    /// In either case, this is the size of the enum in the disk-format.
2912    pub discriminant_size: u8,
2913    /// True if this enum type has a repr(uX) attribute, and thus a predictable
2914    /// memory layout.
2915    has_explicit_repr: bool,
2916    /// The size of the enum (`std::mem::size_of::<TheEnum>()`), if known
2917    size: Option<usize>,
2918    /// The alignment of the enum (`std::mem::align_of::<TheEnum>()`)
2919    alignment: Option<usize>,
2920}
2921
2922fn maybe_max(a: Option<usize>, b: Option<usize>) -> Option<usize> {
2923    if let Some(a) = a {
2924        if let Some(b) = b {
2925            return Some(a.max(b));
2926        }
2927    }
2928    None
2929}
2930impl SchemaEnum {
2931    /// Create a new SchemaEnum instance.
2932    /// Arguments:
2933    ///
2934    /// * dbg_name - Name of the enum type.
2935    /// * discriminant_size:
2936    ///   If this is a repr(uX)-enum, then the size of the discriminant, in bytes.
2937    ///   Valid values are 1, 2 or 4.
2938    ///   Otherwise, this is the number of bytes needed to represent the discriminant.
2939    ///   In either case, this is the size of the enum in the disk-format.
2940    /// * variants - The variants of the enum
2941    ///
2942    pub fn new(dbg_name: String, discriminant_size: u8, variants: Vec<Variant>) -> SchemaEnum {
2943        SchemaEnum {
2944            dbg_name,
2945            variants,
2946            discriminant_size,
2947            has_explicit_repr: false,
2948            size: None,
2949            alignment: None,
2950        }
2951    }
2952    /// Create a new SchemaEnum instance.
2953    /// Arguments:
2954    ///
2955    /// * dbg_name - Name of the enum type.
2956    /// * variants - The variants of the enum
2957    /// * discriminant_size:
2958    ///   If this is a repr(uX)-enum, then the size of the discriminant, in bytes.
2959    ///   Valid values are 1, 2 or 4.
2960    ///   Otherwise, this is the number of bytes needed to represent the discriminant.
2961    ///   In either case, this is the size of the enum in the disk-format.
2962    /// * has_explicit_repr: True if this enum type has a repr(uX) attribute, and thus a predictable
2963    ///   memory layout.
2964    /// * size: The size of the enum (`std::mem::size_of::<TheEnum>()`), if known
2965    /// * alignment: The alignment of the enum (`std::mem::align_of::<TheEnum>()`)
2966    ///
2967    /// # Safety
2968    /// The argument 'has_explicit_repr' must only be true if the enum in fact has a #[repr(uX)] attribute.
2969    /// The size and alignment must be correct for the type.
2970    pub fn new_unsafe(
2971        dbg_name: String,
2972        variants: Vec<Variant>,
2973        discriminant_size: u8,
2974        has_explicit_repr: bool,
2975        size: Option<usize>,
2976        alignment: Option<usize>,
2977    ) -> SchemaEnum {
2978        SchemaEnum {
2979            dbg_name,
2980            variants,
2981            discriminant_size,
2982            has_explicit_repr,
2983            size,
2984            alignment,
2985        }
2986    }
2987    fn layout_compatible(&self, other: &SchemaEnum) -> bool {
2988        if self.has_explicit_repr == false || other.has_explicit_repr == false {
2989            return false;
2990        }
2991        if self.alignment.is_none() || self.size.is_none() {
2992            return false;
2993        }
2994        if self.alignment != other.alignment || self.size != other.size {
2995            return false;
2996        }
2997        if self.discriminant_size != other.discriminant_size {
2998            return false;
2999        }
3000        if self.variants.len() != other.variants.len() {
3001            return false;
3002        }
3003        for (a, b) in self.variants.iter().zip(other.variants.iter()) {
3004            if !a.layout_compatible(b) {
3005                return false;
3006            }
3007        }
3008        true
3009    }
3010    fn serialized_size(&self) -> Option<usize> {
3011        let discr_size = 1usize; //Discriminant is always 1 byte
3012        self.variants
3013            .iter()
3014            .fold(Some(discr_size), |prev, x| maybe_max(prev, x.serialized_size()))
3015    }
3016}
3017
3018/// Schema of a primitive type.
3019///
3020/// A primitive is serialized as the little endian
3021/// representation of its type, except for string,
3022/// which is serialized as an usize length followed
3023/// by the string in utf8.
3024/// These always have a specified memory format, except
3025/// for String, which can in theory be unspecified.
3026#[allow(non_camel_case_types)]
3027#[derive(Copy, Clone, Debug, PartialEq)]
3028#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
3029pub enum SchemaPrimitive {
3030    /// i8
3031    schema_i8,
3032    /// u8
3033    schema_u8,
3034    /// i16
3035    schema_i16,
3036    /// u16
3037    schema_u16,
3038    /// i32
3039    schema_i32,
3040    /// u32
3041    schema_u32,
3042    /// i64
3043    schema_i64,
3044    /// u64
3045    schema_u64,
3046    /// string
3047    schema_string(VecOrStringLayout),
3048    /// f32
3049    schema_f32,
3050    /// f64
3051    schema_f64,
3052    /// bool
3053    schema_bool,
3054    /// canary
3055    schema_canary1,
3056    /// u128
3057    schema_u128,
3058    /// i128
3059    schema_i128,
3060    /// char
3061    schema_char,
3062}
3063impl SchemaPrimitive {
3064    fn layout_compatible(&self, other: &SchemaPrimitive) -> bool {
3065        if let (SchemaPrimitive::schema_string(layout1), SchemaPrimitive::schema_string(layout2)) = (self, other) {
3066            if *layout1 == VecOrStringLayout::Unknown || *layout2 == VecOrStringLayout::Unknown {
3067                return false;
3068            }
3069        }
3070        self == other
3071    }
3072    fn name(&self) -> &'static str {
3073        match *self {
3074            SchemaPrimitive::schema_i8 => "i8",
3075            SchemaPrimitive::schema_u8 => "u8",
3076            SchemaPrimitive::schema_i16 => "i16",
3077            SchemaPrimitive::schema_u16 => "u16",
3078            SchemaPrimitive::schema_i32 => "i32",
3079            SchemaPrimitive::schema_u32 => "u32",
3080            SchemaPrimitive::schema_i64 => "i64",
3081            SchemaPrimitive::schema_u64 => "u64",
3082            SchemaPrimitive::schema_string(_) => "String",
3083            SchemaPrimitive::schema_f32 => "f32",
3084            SchemaPrimitive::schema_f64 => "f64",
3085            SchemaPrimitive::schema_bool => "bool",
3086            SchemaPrimitive::schema_canary1 => "u32",
3087            SchemaPrimitive::schema_u128 => "u128",
3088            SchemaPrimitive::schema_i128 => "i128",
3089            SchemaPrimitive::schema_char => "char",
3090        }
3091    }
3092
3093    fn serialized_size(&self) -> Option<usize> {
3094        match *self {
3095            SchemaPrimitive::schema_i8 | SchemaPrimitive::schema_u8 => Some(1),
3096            SchemaPrimitive::schema_i16 | SchemaPrimitive::schema_u16 => Some(2),
3097            SchemaPrimitive::schema_i32 | SchemaPrimitive::schema_u32 => Some(4),
3098            SchemaPrimitive::schema_i64 | SchemaPrimitive::schema_u64 => Some(8),
3099            SchemaPrimitive::schema_string(_) => None,
3100            SchemaPrimitive::schema_f32 => Some(4),
3101            SchemaPrimitive::schema_f64 => Some(8),
3102            SchemaPrimitive::schema_bool => Some(1),
3103            SchemaPrimitive::schema_canary1 => Some(4),
3104            SchemaPrimitive::schema_i128 | SchemaPrimitive::schema_u128 => Some(16),
3105            SchemaPrimitive::schema_char => Some(4),
3106        }
3107    }
3108}
3109
3110fn diff_primitive(a: SchemaPrimitive, b: SchemaPrimitive, path: &str) -> Option<String> {
3111    if a != b {
3112        if let (SchemaPrimitive::schema_string(_), SchemaPrimitive::schema_string(_)) = (&a, &b) {
3113            return None; //Strings have the same schema, even if they're not memory-layout compatible
3114        }
3115        return Some(format!(
3116            "At location [{}]: Application protocol has datatype {}, but disk format has {}",
3117            path,
3118            a.name(),
3119            b.name()
3120        ));
3121    }
3122    None
3123}
3124
3125/// The actual layout in memory of a Vec-like datastructure.
3126/// If this is 'Unknown', the memory format is unspecified.
3127/// Otherwise, it is as given by the variant.
3128#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
3129#[repr(u8)]
3130#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
3131pub enum VecOrStringLayout {
3132    #[default]
3133    /// Nothing is known. We must assume that the memory layout could be anything
3134    Unknown,
3135    /// Data pointer, plus capacity and length usize
3136    DataCapacityLength,
3137    /// Data pointer, plus length and capacity usize
3138    DataLengthCapacity,
3139    /// One of the possible vec layouts, capacity-data-length
3140    CapacityDataLength,
3141    /// One of the possible vec layouts, length-data-capacity
3142    LengthDataCapacity,
3143    /// One of the possible vec layouts, capacity-length-data
3144    CapacityLengthData,
3145    /// One of the possible vec layouts, length-capacity-data
3146    LengthCapacityData,
3147    /// Length, then data
3148    LengthData,
3149    /// Data, then length
3150    DataLength,
3151}
3152
3153impl Packed for AbiMethodArgument {}
3154
3155/// The definition of an argument to a method
3156#[derive(Debug, PartialEq, Clone)]
3157#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
3158pub struct AbiMethodArgument {
3159    /// The schema (type) of the argument. This contains
3160    /// primarily the on-disk serialized format, but also
3161    /// contains information that can allow savefile-abi to determine
3162    /// if memory layouts are the same.
3163    pub schema: Schema,
3164}
3165
3166impl Deserialize for AbiMethodArgument {
3167    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
3168        Ok(AbiMethodArgument {
3169            schema: <_ as Deserialize>::deserialize(deserializer)?,
3170        })
3171    }
3172}
3173
3174impl WithSchema for AbiMethodArgument {
3175    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
3176        Schema::Undefined
3177    }
3178}
3179
3180impl Serialize for AbiMethodArgument {
3181    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
3182        self.schema.serialize(serializer)?;
3183        Ok(())
3184    }
3185}
3186
3187/// The type of the 'self'-parameter
3188#[non_exhaustive]
3189#[derive(PartialEq, Debug, Clone, Copy)]
3190#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
3191#[repr(u8)]
3192pub enum ReceiverType {
3193    /// &self
3194    Shared, // &self
3195    /// &mut self
3196    Mut, // &mut self
3197    /// self: Pin<&mut Self>
3198    PinMut, // self: Pin<&mut Self>
3199}
3200
3201/// Return value and argument types for a method
3202#[derive(Debug, PartialEq, Clone)]
3203#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
3204pub struct AbiMethodInfo {
3205    /// The return value type of the method
3206    pub return_value: Schema,
3207    /// What type is the 'self'-parameter of this method?
3208    pub receiver: ReceiverType,
3209    /// The arguments of the method.
3210    pub arguments: Vec<AbiMethodArgument>,
3211    /// True if this method was found to have been modified by async_trait,
3212    /// converting it to return a boxed future.
3213    pub async_trait_heuristic: bool,
3214}
3215
3216impl Packed for AbiMethodInfo {}
3217impl WithSchema for AbiMethodInfo {
3218    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
3219        Schema::Undefined
3220    }
3221}
3222
3223impl Serialize for AbiMethodInfo {
3224    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
3225        self.return_value.serialize(serializer)?;
3226        if serializer.file_version >= 2 {
3227            serializer.write_u8(match self.receiver {
3228                ReceiverType::Shared => 100,
3229                ReceiverType::Mut => 101,
3230                ReceiverType::PinMut => 102,
3231            })?;
3232            serializer.write_bool(self.async_trait_heuristic)?;
3233        }
3234        self.arguments.serialize(serializer)?;
3235        Ok(())
3236    }
3237}
3238impl Deserialize for AbiMethodInfo {
3239    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
3240        let return_value = <_ as Deserialize>::deserialize(deserializer)?;
3241        let async_trait_heuristic;
3242        let receiver;
3243        if deserializer.file_version >= 2 {
3244            receiver = match deserializer.read_u8()? {
3245                100 => ReceiverType::Shared,
3246                101 => ReceiverType::Mut,
3247                102 => ReceiverType::PinMut,
3248                x => return Err(SavefileError::WrongVersion {
3249                    msg: format!("Version 0.17.x (or earlier) of the savefile-library detected. It is not compatible with the current version. Please upgrade to version >0.18. Unexpected value: {}", x),
3250                }),
3251            };
3252            async_trait_heuristic = deserializer.read_bool()?;
3253        } else {
3254            receiver = ReceiverType::Shared;
3255            async_trait_heuristic = false;
3256        };
3257        Ok(AbiMethodInfo {
3258            return_value,
3259            receiver,
3260            arguments: <_ as Deserialize>::deserialize(deserializer)?,
3261            async_trait_heuristic,
3262        })
3263    }
3264}
3265
3266/// A method exposed through savefile-abi.
3267/// Contains a name, and a signature.
3268#[derive(Debug, PartialEq, Clone)]
3269#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
3270pub struct AbiMethod {
3271    /// The name of the method
3272    pub name: String,
3273    /// The function signature
3274    pub info: AbiMethodInfo,
3275}
3276impl Packed for AbiMethod {}
3277impl WithSchema for AbiMethod {
3278    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
3279        Schema::Undefined
3280    }
3281}
3282impl Serialize for AbiMethod {
3283    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
3284        self.name.serialize(serializer)?;
3285        self.info.serialize(serializer)?;
3286        Ok(())
3287    }
3288}
3289impl Deserialize for AbiMethod {
3290    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
3291        Ok(AbiMethod {
3292            name: <_ as Deserialize>::deserialize(deserializer)?,
3293            info: <_ as Deserialize>::deserialize(deserializer)?,
3294        })
3295    }
3296}
3297
3298/// Defines a dyn trait, basically
3299#[derive(Default, Debug, PartialEq, Clone)]
3300#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
3301pub struct AbiTraitDefinition {
3302    /// The name of the trait
3303    pub name: String,
3304    /// The set of methods available on the trait
3305    pub methods: Vec<AbiMethod>,
3306    /// True if this object is 'Sync'
3307    pub sync: bool,
3308    /// True if this object is 'Send'
3309    pub send: bool,
3310}
3311impl Packed for AbiTraitDefinition {}
3312impl WithSchema for AbiTraitDefinition {
3313    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
3314        Schema::Undefined
3315    }
3316}
3317impl Serialize for AbiTraitDefinition {
3318    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
3319        let mut effective_name = self.name.clone();
3320        if self.sync {
3321            effective_name += "+Sync";
3322        }
3323        if self.send {
3324            effective_name += "+Send";
3325        }
3326        effective_name.serialize(serializer)?;
3327        self.methods.serialize(serializer)?;
3328        Ok(())
3329    }
3330}
3331impl Deserialize for AbiTraitDefinition {
3332    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
3333        let name: String = <_ as Deserialize>::deserialize(deserializer)?;
3334
3335        let actual_name = name.split('+').next().unwrap();
3336        let mut sync = false;
3337        let mut send = false;
3338        for segment in name.split('+').skip(1) {
3339            match segment {
3340                "Sync" => sync = true,
3341                "Send" => send = true,
3342                _ => panic!("Unexpected trait name encountered: {}", name),
3343            }
3344        }
3345
3346        let t = AbiTraitDefinition {
3347            name: actual_name.to_string(),
3348            methods: <_ as Deserialize>::deserialize(deserializer)?,
3349            sync,
3350            send,
3351        };
3352        Ok(t)
3353    }
3354}
3355
3356impl AbiTraitDefinition {
3357    /// Verify that the 'self' trait definition is compatible with the 'old' definition.
3358    /// Note, this routine ignores methods which only exist in 'self'.
3359    /// The motivation is that older clients won't call them. Of course, a newer client
3360    /// might call such a method, but this will be detected at runtime, and will panic.
3361    /// However, it is hard to do very much better than this.
3362    ///
3363    /// This routine will flag an error if a method that used to exist, no longer does.
3364    /// Note that the _existence_ of methods is not itself versioned with a version number.
3365    ///
3366    /// The version number is only for the data types of the arguments.
3367    ///
3368    /// old is the callee, self is the caller
3369    fn verify_compatible_with_old_impl(
3370        &self,
3371        old_version: u32,
3372        old: &AbiTraitDefinition,
3373        is_return_position: bool,
3374    ) -> Result<(), String> {
3375        if is_return_position {
3376            if !old.sync && self.sync {
3377                return Err(format!("Trait {} was not Sync in version {}, but the Sync-bound has since been added. This is not a backward-compatible change.",
3378                                   self.name, old_version,
3379                ));
3380            }
3381            if !old.send && self.send {
3382                return Err(format!("Trait {} was not Send in version {}, but the Send-bound has since been added. This is not a backward-compatible change.",
3383                                   self.name, old_version,
3384                ));
3385            }
3386        } else {
3387            if old.sync && !self.sync {
3388                return Err(format!("Trait {} was Sync in version {}, but the Sync-bound has since been removed. This is not a backward-compatible change.",
3389                                   self.name, old_version,
3390                ));
3391            }
3392            if old.send && !self.send {
3393                return Err(format!("Trait {} was Send in version {}, but the Send-bound has since been removed. This is not a backward-compatible change.",
3394                                   self.name, old_version,
3395                ));
3396            }
3397        }
3398
3399        for old_method in old.methods.iter() {
3400            let Some(new_method) = self.methods.iter().find(|x| x.name == old_method.name) else {
3401                return Err(format!("In trait {}, the method {} existed in version {}, but has been removed. This is not a backward-compatible change.",
3402                                   self.name, old_method.name, old_version,
3403                ));
3404            };
3405            if new_method.info.async_trait_heuristic != old_method.info.async_trait_heuristic {
3406                if old_method.info.async_trait_heuristic {
3407                    return Err(format!("In trait {}, the method {} was previously async, using #[async_trait], but it does no longer. This is not a backward-compatible change.",
3408                                       self.name, old_method.name
3409                    ));
3410                } else {
3411                    return Err(format!("In trait {}, the method {} is now async, using #[async_trait], but it previously did not. This is not a backward-compatible change.",
3412                                       self.name, old_method.name
3413                    ));
3414                }
3415            }
3416            if new_method.info.arguments.len() != old_method.info.arguments.len() {
3417                return Err(format!("In trait {}, method {}, the number of arguments has changed from {} in version {} to {}. This is not a backward-compatible change.",
3418                                   self.name, old_method.name, old_method.info.arguments.len(), old_version, new_method.info.arguments.len()
3419                ));
3420            }
3421            if let Some(diff) = diff_schema(
3422                &new_method.info.return_value,
3423                &old_method.info.return_value,
3424                "".into(),
3425                is_return_position,
3426            ) {
3427                return Err(format!("In trait {}, method {}, the return value type has changed from version {}: {}. This is not a backward-compatible change.",
3428                                   self.name, old_method.name, old_version, diff
3429                ));
3430            }
3431            for (arg_index, (new_arg, old_arg)) in new_method
3432                .info
3433                .arguments
3434                .iter()
3435                .zip(old_method.info.arguments.iter())
3436                .enumerate()
3437            {
3438                if let Some(diff) = diff_schema(&new_arg.schema, &old_arg.schema, "".into(), is_return_position) {
3439                    return Err(format!("In trait {}, method {}, argument {}, the type has changed from version {}: {}. This is not a backward-compatible change.",
3440                                       self.name, old_method.name, arg_index , old_version, diff
3441                    ));
3442                }
3443            }
3444        }
3445
3446        Ok(())
3447    }
3448
3449    /// Verify that 'self' represents a newer version of a trait, that is backward compatible
3450    /// with 'old'. 'old_version' is the version number of the old version being inspected.
3451    /// To guarantee compatibility, all versions must be checked
3452    ///
3453    /// old is the callee, self is the caller
3454    pub fn verify_backward_compatible(
3455        &self,
3456        old_version: u32,
3457        old: &AbiTraitDefinition,
3458        is_return_position: bool,
3459    ) -> Result<(), SavefileError> {
3460        self.verify_compatible_with_old_impl(old_version, old, is_return_position)
3461            .map_err(|x| SavefileError::IncompatibleSchema { message: x })
3462    }
3463}
3464
3465/// The schema represents the save file format
3466/// of your data structure.
3467///
3468/// It is a tree,
3469/// consisting of various types of nodes in the savefile
3470/// format. Custom Serialize-implementations cannot add new types to
3471/// this tree, but must reuse these existing ones.
3472/// See the various enum variants for more information.
3473///
3474/// Note, the Schema actually carries two different pieces of information
3475///  * The disk format
3476///  * The memory format. The latter is only used by SavefileAbi.
3477///
3478/// Note, schema instances may choose to not specify any memory format. If so,
3479/// SavefileAbi will have to resort to serialization.
3480///
3481/// Exactly how the memory format is specified varies for the variants.
3482/// Check the variant documentation.
3483#[derive(Debug, PartialEq, Clone)]
3484#[repr(C, u32)]
3485#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
3486#[non_exhaustive]
3487pub enum Schema {
3488    /// Represents a struct. Custom implementations of Serialize are encouraged to use this format.
3489    Struct(SchemaStruct),
3490    /// Represents an enum.
3491    Enum(SchemaEnum),
3492    /// Represents a primitive: Any of the various integer types (u8, i8, u16, i16 etc...), or String
3493    Primitive(SchemaPrimitive),
3494    /// A Vector of arbitrary nodes, all of the given type.
3495    /// This has a specified memory format unless the VecOrStringLayout value is 'Unknown'.
3496    Vector(Box<Schema>, VecOrStringLayout /*standard savefile memory layout*/),
3497    /// An array of N arbitrary nodes, all of the given type
3498    /// This has a specified memory format unless the VecOrStringLayout value is 'Unknown'.
3499    Array(SchemaArray),
3500    /// An Option variable instance of the given type.
3501    /// This has a specified memory format (a pointer to instance of 'Schema')
3502    SchemaOption(Box<Schema>),
3503    /// Basically a dummy value, the Schema nodes themselves report this schema if queried.
3504    /// This never has a specified memory format.
3505    Undefined,
3506    /// A zero-sized type. I.e, there is no data to serialize or deserialize.
3507    /// This always has a specified memory format.
3508    ZeroSize,
3509    /// A user-defined, custom type. The string can be anything. The schema
3510    /// only matches if the string is identical. Use with caution. Consider
3511    /// if your type is aptly represented as a Struct or Enum instead.
3512    /// This never has a specified memory format.
3513    Custom(String),
3514    /// The savefile format of a `Box<T>` is identical to that of `T`.
3515    /// But SavefileAbi still needs to represent `Box<T>` separate from `T`, since
3516    /// their memory layout isn't the same.
3517    Boxed(Box<Schema>),
3518    /// Savefile does not support deserializing unsized slices.
3519    /// But SavefileAbi supports these as parameters.
3520    /// Savefile schema still needs to be able to represent them.
3521    Slice(Box<Schema>),
3522    /// Savefile does not support deserializing &str, nor the unsized str.
3523    /// But SavefileAbi supports &str as parameters. It does not support str.
3524    /// Savefile schema still needs to be able to represent Str.
3525    Str,
3526    /// Savefile does not support deserializing references.
3527    /// If it would, the savefile format of `&T` would be identical to that of `T`.
3528    /// But SavefileAbi still needs to represent &T separate from T, since
3529    /// their memory layout isn't the same.
3530    Reference(Box<Schema>),
3531    /// Traits cannot be serialized, but they can be exchanged using savefile-abi
3532    /// Their memory layout is considered to depend on all method signatures,
3533    /// and the layouts of all argument types and all return types.
3534    Trait(bool /* mut self*/, AbiTraitDefinition),
3535    /// This is just a trait. But it exists as a separate schema variant,
3536    /// since SavefileAbi automatically generates wrappers for standard Fn*-types,
3537    /// and these should not be mixed up with regular trait definitions, even if they
3538    /// would be identical
3539    /// Traits cannot be serialized, but they can be exchanged using savefile-abi
3540    /// Their memory layout is considered to depend on all method signatures,
3541    /// and the layouts of all argument types and all return types.
3542    FnClosure(bool /*mut self*/, AbiTraitDefinition),
3543    /// The datastructure is recursive, and the datatype now continues from
3544    /// the element that is 'depth' layers higher in the schema tree.
3545    /// Note, the 'depth' only counts possible recursion points, i.e, objects
3546    /// such as 'Box', 'Vec' etc. This works, since the schema will only ever match
3547    /// if it is identical in memory and file, and because of this, counting
3548    /// only the recursion points is non-ambiguous.
3549    Recursion(usize /*depth*/),
3550    /// std::io::Error
3551    StdIoError,
3552    /// Savefile-abi boxed Future
3553    Future(
3554        AbiTraitDefinition,
3555        /*send*/ bool,
3556        /*sync*/ bool,
3557        /*unpin*/ bool,
3558    ),
3559    /// UninitSlice from 'bytes' crate
3560    UninitSlice,
3561}
3562/// Introspect is not implemented for Schema, though it could be
3563impl Introspect for Schema {
3564    fn introspect_value(&self) -> String {
3565        "Schema".to_string()
3566    }
3567
3568    fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
3569        None
3570    }
3571}
3572
3573impl Schema {
3574    /// Get a short description of the major type of this schema.
3575    /// 'struct', 'enum' etc.
3576    pub fn top_level_description(&self) -> String {
3577        match self {
3578            Schema::Struct(_) => "struct".into(),
3579            Schema::Enum(_) => "enum".into(),
3580            Schema::Primitive(_) => "primitive".into(),
3581            Schema::Vector(_, _) => "vector".into(),
3582            Schema::Array(_) => "array".into(),
3583            Schema::SchemaOption(_) => "option".into(),
3584            Schema::Undefined => "undefined".into(),
3585            Schema::ZeroSize => "zerosize".into(),
3586            Schema::Custom(_) => "custom".into(),
3587            Schema::Boxed(_) => "box".into(),
3588            Schema::FnClosure(_, _) => "fntrait".into(),
3589            Schema::Slice(_) => "slice".into(),
3590            Schema::Str => "str".into(),
3591            Schema::Reference(_) => "reference".into(),
3592            Schema::Trait(_, _) => "trait".into(),
3593            Schema::Recursion(depth) => {
3594                format!("<recursion {}>", depth)
3595            }
3596            Schema::StdIoError => "stdioerror".into(),
3597            Schema::Future(_, _, _, _) => "future".into(),
3598            Schema::UninitSlice => {"UninitSlice".into()}
3599        }
3600    }
3601    /// Determine if the two fields are laid out identically in memory, in their parent objects.
3602    pub fn layout_compatible(&self, b_native: &Schema) -> bool {
3603        match (self, b_native) {
3604            (Schema::Struct(a), Schema::Struct(b)) => a.layout_compatible(b),
3605            (Schema::Enum(a), Schema::Enum(b)) => a.layout_compatible(b),
3606            (Schema::Primitive(a), Schema::Primitive(b)) => a.layout_compatible(b),
3607            (Schema::Vector(a, a_standard_layout), Schema::Vector(b, b_standard_layout)) => {
3608                a.layout_compatible(b)
3609                    && *a_standard_layout != VecOrStringLayout::Unknown
3610                    && *b_standard_layout != VecOrStringLayout::Unknown
3611                    && *a_standard_layout == *b_standard_layout
3612            }
3613            (Schema::Array(a), Schema::Array(b)) => a.layout_compatible(b),
3614            (Schema::SchemaOption(_), Schema::SchemaOption(_)) => {
3615                false // Layout of enums in memory is undefined, and also hard to determine at runtime
3616            }
3617            (Schema::ZeroSize, Schema::ZeroSize) => true,
3618            (Schema::Custom(_), Schema::Custom(_)) => {
3619                false // Be conservative here
3620            }
3621            (Schema::FnClosure(_a1, _a2), Schema::FnClosure(_b1, _b2)) => {
3622                // Closures as arguments are handled differently.
3623                // Closures are not supported in any other position
3624                false
3625            }
3626            (Schema::Boxed(a), Schema::Boxed(b)) => {
3627                // The memory layout of boxes is guaranteed in practice (just a pointer)
3628                // Trait pointers (which are fat) could conceivably differ, but we don't
3629                // actually rely on memory layout compatibility for them, and this expression
3630                // will also return false (since Schema::Trait 'layout_compatible' always returns false).
3631                a.layout_compatible(b)
3632            }
3633            (Schema::Reference(a), Schema::Reference(b)) => a.layout_compatible(b),
3634            (Schema::Slice(a), Schema::Slice(b)) => a.layout_compatible(b),
3635            _ => false,
3636        }
3637    }
3638    /// Create a 1-element tuple
3639    pub fn new_tuple1<T1: WithSchema>(version: u32, context: &mut WithSchemaContext) -> Schema {
3640        let schema = Box::new(T1::schema(version, context));
3641        Schema::Struct(SchemaStruct {
3642            dbg_name: "1-Tuple".to_string(),
3643            size: Some(std::mem::size_of::<(T1,)>()),
3644            alignment: Some(std::mem::align_of::<(T1,)>()),
3645            fields: vec![Field {
3646                name: "0".to_string(),
3647                value: schema,
3648                offset: Some(offset_of_tuple!((T1,), 0)),
3649            }],
3650        })
3651    }
3652
3653    /// Create a 2-element tuple
3654    pub fn new_tuple2<T1: WithSchema, T2: WithSchema>(version: u32, context: &mut WithSchemaContext) -> Schema {
3655        Schema::Struct(SchemaStruct {
3656            dbg_name: "2-Tuple".to_string(),
3657            size: Some(std::mem::size_of::<(T1, T2)>()),
3658            alignment: Some(std::mem::align_of::<(T1, T2)>()),
3659            fields: vec![
3660                Field {
3661                    name: "0".to_string(),
3662                    value: Box::new(T1::schema(version, context)),
3663                    offset: Some(offset_of_tuple!((T1, T2), 0)),
3664                },
3665                Field {
3666                    name: "1".to_string(),
3667                    value: Box::new(T2::schema(version, context)),
3668                    offset: Some(offset_of_tuple!((T1, T2), 1)),
3669                },
3670            ],
3671        })
3672    }
3673    /// Create a 3-element tuple
3674    pub fn new_tuple3<T1: WithSchema, T2: WithSchema, T3: WithSchema>(
3675        version: u32,
3676        context: &mut WithSchemaContext,
3677    ) -> Schema {
3678        Schema::Struct(SchemaStruct {
3679            dbg_name: "3-Tuple".to_string(),
3680            size: Some(std::mem::size_of::<(T1, T2, T3)>()),
3681            alignment: Some(std::mem::align_of::<(T1, T2, T3)>()),
3682            fields: vec![
3683                Field {
3684                    name: "0".to_string(),
3685                    value: Box::new(T1::schema(version, context)),
3686                    offset: Some(offset_of_tuple!((T1, T2, T3), 0)),
3687                },
3688                Field {
3689                    name: "1".to_string(),
3690                    value: Box::new(T2::schema(version, context)),
3691                    offset: Some(offset_of_tuple!((T1, T2, T3), 1)),
3692                },
3693                Field {
3694                    name: "2".to_string(),
3695                    value: Box::new(T3::schema(version, context)),
3696                    offset: Some(offset_of_tuple!((T1, T2, T3), 2)),
3697                },
3698            ],
3699        })
3700    }
3701    /// Create a 4-element tuple
3702    pub fn new_tuple4<T1: WithSchema, T2: WithSchema, T3: WithSchema, T4: WithSchema>(
3703        version: u32,
3704        context: &mut WithSchemaContext,
3705    ) -> Schema {
3706        Schema::Struct(SchemaStruct {
3707            dbg_name: "4-Tuple".to_string(),
3708            size: Some(std::mem::size_of::<(T1, T2, T3, T4)>()),
3709            alignment: Some(std::mem::align_of::<(T1, T2, T3, T4)>()),
3710            fields: vec![
3711                Field {
3712                    name: "0".to_string(),
3713                    value: Box::new(T1::schema(version, context)),
3714                    offset: Some(offset_of_tuple!((T1, T2, T3, T4), 0)),
3715                },
3716                Field {
3717                    name: "1".to_string(),
3718                    value: Box::new(T2::schema(version, context)),
3719                    offset: Some(offset_of_tuple!((T1, T2, T3, T4), 1)),
3720                },
3721                Field {
3722                    name: "2".to_string(),
3723                    value: Box::new(T3::schema(version, context)),
3724                    offset: Some(offset_of_tuple!((T1, T2, T3, T4), 2)),
3725                },
3726                Field {
3727                    name: "3".to_string(),
3728                    value: Box::new(T4::schema(version, context)),
3729                    offset: Some(offset_of_tuple!((T1, T2, T3, T4), 3)),
3730                },
3731            ],
3732        })
3733    }
3734    /// Size
3735    pub fn serialized_size(&self) -> Option<usize> {
3736        match self {
3737            Schema::Struct(ref schema_struct) => schema_struct.serialized_size(),
3738            Schema::Enum(ref schema_enum) => schema_enum.serialized_size(),
3739            Schema::Primitive(ref schema_primitive) => schema_primitive.serialized_size(),
3740            Schema::Vector(ref _vector, _) => None,
3741            Schema::Array(ref array) => array.serialized_size(),
3742            Schema::SchemaOption(ref _content) => None,
3743            Schema::Undefined => None,
3744            Schema::ZeroSize => Some(0),
3745            Schema::Custom(_) => None,
3746            Schema::Boxed(inner) => inner.serialized_size(),
3747            Schema::FnClosure(_, _) => None,
3748            Schema::Slice(_) => None,
3749            Schema::Str => None,
3750            Schema::Reference(_) => None,
3751            Schema::Trait(_, _) => None,
3752            Schema::Recursion(_) => None,
3753            Schema::StdIoError => None,
3754            Schema::Future(_, _, _, _) => None,
3755            Schema::UninitSlice => None,
3756        }
3757    }
3758}
3759
3760fn diff_vector(a: &Schema, b: &Schema, path: String) -> Option<String> {
3761    diff_schema(a, b, path + "/*", false)
3762}
3763
3764fn diff_array(a: &SchemaArray, b: &SchemaArray, path: String) -> Option<String> {
3765    if a.count != b.count {
3766        return Some(format!(
3767            "At location [{}]: In memory array has length {}, but disk format length {}.",
3768            path, a.count, b.count
3769        ));
3770    }
3771
3772    diff_schema(&a.item_type, &b.item_type, format!("{}/[{}]", path, a.count), false)
3773}
3774
3775fn diff_option(a: &Schema, b: &Schema, path: String) -> Option<String> {
3776    diff_schema(a, b, path + "/?", false)
3777}
3778
3779fn diff_enum(a: &SchemaEnum, b: &SchemaEnum, path: String) -> Option<String> {
3780    let path = (path + &b.dbg_name).to_string();
3781    if a.variants.len() != b.variants.len() {
3782        return Some(format!(
3783            "At location [{}]: In memory enum has {} variants, but disk format has {} variants.",
3784            path,
3785            a.variants.len(),
3786            b.variants.len()
3787        ));
3788    }
3789    if a.discriminant_size != b.discriminant_size {
3790        return Some(format!(
3791            "At location [{}]: In memory enum has a representation with {} bytes for the discriminant, but disk format has {}.",
3792            path,
3793            a.discriminant_size,
3794            b.discriminant_size
3795        ));
3796    }
3797    for i in 0..a.variants.len() {
3798        if a.variants[i].name != b.variants[i].name {
3799            return Some(format!(
3800                "At location [{}]: Enum variant #{} in memory is called {}, but in disk format it is called {}",
3801                &path, i, a.variants[i].name, b.variants[i].name
3802            ));
3803        }
3804        if a.variants[i].discriminant != b.variants[i].discriminant {
3805            return Some(format!(
3806                "At location [{}]: Enum variant #{} in memory has discriminant {}, but in disk format it has {}",
3807                &path, i, a.variants[i].discriminant, b.variants[i].discriminant
3808            ));
3809        }
3810        let r = diff_fields(
3811            &a.variants[i].fields,
3812            &b.variants[i].fields,
3813            &(path.to_string() + "/" + &b.variants[i].name).to_string(),
3814            "enum",
3815            "",
3816            "",
3817        );
3818        if let Some(err) = r {
3819            return Some(err);
3820        }
3821    }
3822    None
3823}
3824fn diff_struct(a: &SchemaStruct, b: &SchemaStruct, path: String) -> Option<String> {
3825    diff_fields(
3826        &a.fields,
3827        &b.fields,
3828        &(path + "/" + &b.dbg_name).to_string(),
3829        "struct",
3830        &(" (struct ".to_string() + &a.dbg_name + ")"),
3831        &(" (struct ".to_string() + &b.dbg_name + ")"),
3832    )
3833}
3834fn diff_fields(
3835    a: &[Field],
3836    b: &[Field],
3837    path: &str,
3838    structuretype: &str,
3839    extra_a: &str,
3840    extra_b: &str,
3841) -> Option<String> {
3842    if a.len() != b.len() {
3843        return Some(format!(
3844            "At location [{}]: In memory {}{} has {} fields, disk format{} has {} fields.",
3845            path,
3846            structuretype,
3847            extra_a,
3848            a.len(),
3849            extra_b,
3850            b.len()
3851        ));
3852    }
3853    for i in 0..a.len() {
3854        let r = diff_schema(
3855            &a[i].value,
3856            &b[i].value,
3857            (path.to_string() + "/" + &b[i].name).to_string(),
3858            false,
3859        );
3860        if let Some(err) = r {
3861            return Some(err);
3862        }
3863    }
3864    None
3865}
3866/// Return a (kind of) human-readable description of the difference
3867/// between the two schemas.
3868///
3869/// The schema 'a' is assumed to be the current
3870/// schema (used in memory).
3871/// Returns None if both schemas are equivalent
3872/// This does not care about memory layout, only serializability.
3873///
3874/// is_return_pos should be true if the schema we're diffing is for a return value in
3875/// savefile abi, otherwise false.
3876///
3877/// for ABI calls:
3878/// a is the caller
3879/// b is the callee
3880pub fn diff_schema(a: &Schema, b: &Schema, path: String, is_return_pos: bool) -> Option<String> {
3881    let (atype, btype) = match (a, b) {
3882        (Schema::Struct(a), Schema::Struct(b)) => return diff_struct(a, b, path),
3883        (Schema::Enum(a), Schema::Enum(b)) => return diff_enum(a, b, path),
3884        (Schema::Primitive(a1), Schema::Primitive(b1)) => return diff_primitive(*a1, *b1, &path),
3885        (Schema::Vector(a1, _a2), Schema::Vector(b1, _b2)) => return diff_vector(a1, b1, path),
3886        (Schema::SchemaOption(a), Schema::SchemaOption(b)) => {
3887            return diff_option(a, b, path);
3888        }
3889        (Schema::Undefined, Schema::Undefined) => {
3890            return Some(format!("At location [{}]: Undefined schema encountered.", path))
3891        }
3892        (Schema::ZeroSize, Schema::ZeroSize) => {
3893            return None;
3894        }
3895        (Schema::Array(a), Schema::Array(b)) => return diff_array(a, b, path),
3896        (Schema::Custom(a), Schema::Custom(b)) => {
3897            if a != b {
3898                return Some(format!(
3899                    "At location [{}]: Application protocol has datatype Custom({}), but foreign format has Custom({})",
3900                    path, a, b
3901                ));
3902            }
3903            return None;
3904        }
3905        (Schema::Str, Schema::Str) => {
3906            return None;
3907        }
3908        (Schema::StdIoError, Schema::StdIoError) => {
3909            return None;
3910        }
3911        (Schema::Boxed(a), Schema::Boxed(b)) => {
3912            return diff_schema(a, b, path, is_return_pos);
3913        }
3914        (Schema::Reference(a), Schema::Reference(b)) => {
3915            return diff_schema(a, b, path, is_return_pos);
3916        }
3917        (Schema::Slice(a), Schema::Slice(b)) => {
3918            return diff_schema(a, b, path, is_return_pos);
3919        }
3920        (Schema::Trait(amut, a), Schema::Trait(bmut, b)) | (Schema::FnClosure(amut, a), Schema::FnClosure(bmut, b)) => {
3921            if amut != bmut {
3922                if *amut {
3923                    return Some(format!(
3924                        "At location [{}]: Application protocol uses FnMut, but foreign format has Fn.",
3925                        path
3926                    ));
3927                }
3928                if *bmut {
3929                    return Some(format!(
3930                        "At location [{}]: Application protocol uses Fn, but foreign format uses FnMut.",
3931                        path
3932                    ));
3933                }
3934            }
3935            return diff_abi_def(a, b, path, is_return_pos);
3936        }
3937        (Schema::Recursion(adepth), Schema::Recursion(bdepth)) => {
3938            if adepth == bdepth {
3939                return None; //Ok
3940            } else {
3941                return Some(format!(
3942                    "At location [{}]: Application protocol uses recursion up {} levels, but foreign format uses {}.",
3943                    path, adepth, bdepth
3944                ));
3945            }
3946        }
3947        (Schema::Future(a, a_send, a_sync, a_unpin), Schema::Future(b, b_send, b_sync, b_unpin)) => {
3948            if !is_return_pos {
3949                panic!("Futures are only supported in return position");
3950            }
3951            for (a, b, bound) in [
3952                (*a_send, *b_send, "Send"),
3953                (*a_sync, *b_sync, "Sync"),
3954                (*a_unpin, *b_unpin, "Unpin"),
3955            ] {
3956                if a && !b {
3957                    return Some(format!(
3958                        "At location [{}]: Caller expects a future with an {}-bound, but implementation provides one without. This is an incompatible difference.",
3959                        path, bound
3960                    ));
3961                }
3962            }
3963            return diff_abi_def(a, b, path, is_return_pos);
3964        }
3965        (Schema::UninitSlice, Schema::UninitSlice) => {
3966            return None; //Ok
3967        }
3968        (a, b) => (a.top_level_description(), b.top_level_description()),
3969    };
3970
3971    Some(format!(
3972        "At location [{}]: In memory schema: {}, file schema: {}",
3973        path, atype, btype
3974    ))
3975}
3976
3977fn diff_abi_def(a: &AbiTraitDefinition, b: &AbiTraitDefinition, path: String, is_return_pos: bool) -> Option<String> {
3978    for amet in a.methods.iter() {
3979        if let Some(bmet) = b.methods.iter().find(|x| x.name == amet.name) {
3980            if amet.info.arguments.len() != bmet.info.arguments.len() {
3981                return Some(format!(
3982                    "At location [{}]: Application protocol method {} has {} args, but foreign version has {}.",
3983                    path,
3984                    amet.name,
3985                    amet.info.arguments.len(),
3986                    bmet.info.arguments.len()
3987                ));
3988            }
3989            for (arg_index, (a_arg, b_arg)) in amet.info.arguments.iter().zip(bmet.info.arguments.iter()).enumerate() {
3990                if let Some(diff) = diff_schema(
3991                    &a_arg.schema,
3992                    &b_arg.schema,
3993                    format!("{}(arg #{})", amet.name, arg_index),
3994                    is_return_pos,
3995                ) {
3996                    return Some(diff);
3997                }
3998            }
3999        }
4000    }
4001    return None;
4002}
4003
4004impl WithSchema for Field {
4005    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4006        Schema::Undefined
4007    }
4008}
4009
4010impl Serialize for Field {
4011    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4012        serializer.write_string(&self.name)?;
4013        self.value.serialize(serializer)?;
4014        self.offset.serialize(serializer)?;
4015        Ok(())
4016    }
4017}
4018impl Packed for Field {}
4019impl Deserialize for Field {
4020    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
4021        Ok(Field {
4022            name: deserializer.read_string()?,
4023            value: Box::new(Schema::deserialize(deserializer)?),
4024            offset: if deserializer.file_version > 0 {
4025                Option::deserialize(deserializer)?
4026            } else {
4027                None
4028            },
4029        })
4030    }
4031}
4032impl WithSchema for Variant {
4033    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4034        Schema::Undefined
4035    }
4036}
4037impl Serialize for Variant {
4038    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4039        serializer.write_string(&self.name)?;
4040        serializer.write_u8(self.discriminant)?;
4041        serializer.write_usize(self.fields.len())?;
4042        for field in &self.fields {
4043            field.serialize(serializer)?;
4044        }
4045        Ok(())
4046    }
4047}
4048
4049impl Packed for Variant {}
4050impl Deserialize for Variant {
4051    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
4052        Ok(Variant {
4053            name: deserializer.read_string()?,
4054            discriminant: deserializer.read_u8()?,
4055            fields: {
4056                let l = deserializer.read_usize()?;
4057                let mut ret = Vec::new();
4058                for _ in 0..l {
4059                    ret.push(Field {
4060                        name: deserializer.read_string()?,
4061                        value: Box::new(Schema::deserialize(deserializer)?),
4062                        offset: if deserializer.file_version > 0 {
4063                            Option::deserialize(deserializer)?
4064                        } else {
4065                            None
4066                        },
4067                    });
4068                }
4069                ret
4070            },
4071        })
4072    }
4073}
4074impl Serialize for SchemaArray {
4075    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4076        serializer.write_usize(self.count)?;
4077        self.item_type.serialize(serializer)?;
4078        Ok(())
4079    }
4080}
4081impl Packed for SchemaArray {}
4082impl Deserialize for SchemaArray {
4083    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
4084        let count = deserializer.read_usize()?;
4085        let item_type = Box::new(Schema::deserialize(deserializer)?);
4086        Ok(SchemaArray { count, item_type })
4087    }
4088}
4089impl WithSchema for SchemaArray {
4090    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4091        Schema::Undefined
4092    }
4093}
4094
4095impl WithSchema for SchemaStruct {
4096    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4097        Schema::Undefined
4098    }
4099}
4100impl Serialize for SchemaStruct {
4101    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4102        serializer.write_string(&self.dbg_name)?;
4103        serializer.write_usize(self.fields.len())?;
4104        self.size.serialize(serializer)?;
4105        self.alignment.serialize(serializer)?;
4106        for field in &self.fields {
4107            field.serialize(serializer)?;
4108        }
4109        Ok(())
4110    }
4111}
4112impl Packed for SchemaStruct {}
4113impl Deserialize for SchemaStruct {
4114    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
4115        let dbg_name = deserializer.read_string()?;
4116        let l = deserializer.read_usize()?;
4117        Ok(SchemaStruct {
4118            dbg_name,
4119            size: if deserializer.file_version > 0 {
4120                <_ as Deserialize>::deserialize(deserializer)?
4121            } else {
4122                None
4123            },
4124            alignment: if deserializer.file_version > 0 {
4125                <_ as Deserialize>::deserialize(deserializer)?
4126            } else {
4127                None
4128            },
4129            fields: {
4130                let mut ret = Vec::new();
4131                for _ in 0..l {
4132                    ret.push(Field::deserialize(deserializer)?)
4133                }
4134                ret
4135            },
4136        })
4137    }
4138}
4139
4140impl WithSchema for SchemaPrimitive {
4141    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4142        Schema::Undefined
4143    }
4144}
4145impl Serialize for SchemaPrimitive {
4146    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4147        let discr = match *self {
4148            SchemaPrimitive::schema_i8 => 1,
4149            SchemaPrimitive::schema_u8 => 2,
4150            SchemaPrimitive::schema_i16 => 3,
4151            SchemaPrimitive::schema_u16 => 4,
4152            SchemaPrimitive::schema_i32 => 5,
4153            SchemaPrimitive::schema_u32 => 6,
4154            SchemaPrimitive::schema_i64 => 7,
4155            SchemaPrimitive::schema_u64 => 8,
4156            SchemaPrimitive::schema_f32 => 10,
4157            SchemaPrimitive::schema_f64 => 11,
4158            SchemaPrimitive::schema_bool => 12,
4159            SchemaPrimitive::schema_canary1 => 13,
4160            SchemaPrimitive::schema_i128 => 14,
4161            SchemaPrimitive::schema_u128 => 15,
4162            SchemaPrimitive::schema_char => 16,
4163            SchemaPrimitive::schema_string(layout) => {
4164                serializer.write_u8(9)?;
4165                if serializer.file_version > 0 {
4166                    serializer.write_u8(layout as u8)?;
4167                }
4168                return Ok(());
4169            }
4170        };
4171        serializer.write_u8(discr)
4172    }
4173}
4174impl WithSchema for VecOrStringLayout {
4175    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4176        Schema::Undefined
4177    }
4178}
4179impl Deserialize for VecOrStringLayout {
4180    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
4181        Ok(match deserializer.read_u8()? {
4182            1 => VecOrStringLayout::DataCapacityLength,
4183            2 => VecOrStringLayout::DataLengthCapacity,
4184            3 => VecOrStringLayout::CapacityDataLength,
4185            4 => VecOrStringLayout::LengthDataCapacity,
4186            5 => VecOrStringLayout::CapacityLengthData,
4187            6 => VecOrStringLayout::LengthCapacityData,
4188            7 => VecOrStringLayout::LengthData,
4189            8 => VecOrStringLayout::DataLength,
4190            _ => VecOrStringLayout::Unknown,
4191        })
4192    }
4193}
4194impl Packed for SchemaPrimitive {}
4195impl Deserialize for SchemaPrimitive {
4196    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
4197        let var = match deserializer.read_u8()? {
4198            1 => SchemaPrimitive::schema_i8,
4199            2 => SchemaPrimitive::schema_u8,
4200            3 => SchemaPrimitive::schema_i16,
4201            4 => SchemaPrimitive::schema_u16,
4202            5 => SchemaPrimitive::schema_i32,
4203            6 => SchemaPrimitive::schema_u32,
4204            7 => SchemaPrimitive::schema_i64,
4205            8 => SchemaPrimitive::schema_u64,
4206            9 => SchemaPrimitive::schema_string({
4207                if deserializer.file_version > 0 {
4208                    VecOrStringLayout::deserialize(deserializer)?
4209                } else {
4210                    VecOrStringLayout::Unknown
4211                }
4212            }),
4213            10 => SchemaPrimitive::schema_f32,
4214            11 => SchemaPrimitive::schema_f64,
4215            12 => SchemaPrimitive::schema_bool,
4216            13 => SchemaPrimitive::schema_canary1,
4217            14 => SchemaPrimitive::schema_i128,
4218            15 => SchemaPrimitive::schema_u128,
4219            16 => SchemaPrimitive::schema_char,
4220            c => {
4221                return Err(SavefileError::GeneralError {
4222                    msg: format!(
4223                        "Corrupt schema, type {} encountered. Perhaps data is from future version?",
4224                        c
4225                    ),
4226                })
4227            }
4228        };
4229        Ok(var)
4230    }
4231}
4232
4233impl WithSchema for SchemaEnum {
4234    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4235        Schema::Undefined
4236    }
4237}
4238
4239impl Serialize for SchemaEnum {
4240    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4241        serializer.write_string(&self.dbg_name)?;
4242        serializer.write_usize(self.variants.len())?;
4243        for var in &self.variants {
4244            var.serialize(serializer)?;
4245        }
4246        self.discriminant_size.serialize(serializer)?;
4247        self.has_explicit_repr.serialize(serializer)?;
4248        self.size.serialize(serializer)?;
4249        self.alignment.serialize(serializer)?;
4250        Ok(())
4251    }
4252}
4253impl Packed for SchemaEnum {}
4254impl Deserialize for SchemaEnum {
4255    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
4256        let dbg_name = deserializer.read_string()?;
4257        let l = deserializer.read_usize()?;
4258        let mut ret = Vec::new();
4259        for _ in 0..l {
4260            ret.push(Variant::deserialize(deserializer)?);
4261        }
4262        let (discriminant_size, has_explicit_repr, size, alignment) = if deserializer.file_version > 0 {
4263            (
4264                u8::deserialize(deserializer)?,
4265                bool::deserialize(deserializer)?,
4266                Option::<usize>::deserialize(deserializer)?,
4267                Option::<usize>::deserialize(deserializer)?,
4268            )
4269        } else {
4270            (1, false, None, None)
4271        };
4272        Ok(SchemaEnum {
4273            dbg_name,
4274            variants: ret,
4275            discriminant_size,
4276            has_explicit_repr,
4277            size,
4278            alignment,
4279        })
4280    }
4281}
4282
4283#[cfg(feature = "quickcheck")]
4284impl Arbitrary for VecOrStringLayout {
4285    fn arbitrary(g: &mut Gen) -> Self {
4286        let x = u8::arbitrary(g);
4287        match x % 9 {
4288            0 => VecOrStringLayout::Unknown,
4289            1 => VecOrStringLayout::DataCapacityLength,
4290            2 => VecOrStringLayout::DataLengthCapacity,
4291            3 => VecOrStringLayout::CapacityDataLength,
4292            4 => VecOrStringLayout::LengthDataCapacity,
4293            5 => VecOrStringLayout::CapacityLengthData,
4294            6 => VecOrStringLayout::LengthCapacityData,
4295            7 => VecOrStringLayout::LengthData,
4296            8 => VecOrStringLayout::DataLength,
4297            _ => unreachable!(),
4298        }
4299    }
4300}
4301
4302#[cfg(feature = "quickcheck")]
4303impl Arbitrary for SchemaPrimitive {
4304    fn arbitrary(g: &mut Gen) -> Self {
4305        let x = u8::arbitrary(g);
4306        match x % 16 {
4307            0 => SchemaPrimitive::schema_i8,
4308            1 => SchemaPrimitive::schema_u8,
4309            2 => SchemaPrimitive::schema_i16,
4310            3 => SchemaPrimitive::schema_u16,
4311            4 => SchemaPrimitive::schema_i32,
4312            5 => SchemaPrimitive::schema_u32,
4313            6 => SchemaPrimitive::schema_i64,
4314            7 => SchemaPrimitive::schema_u64,
4315            8 => SchemaPrimitive::schema_string(VecOrStringLayout::arbitrary(g)),
4316            9 => SchemaPrimitive::schema_f32,
4317            10 => SchemaPrimitive::schema_f64,
4318            11 => SchemaPrimitive::schema_bool,
4319            12 => SchemaPrimitive::schema_canary1,
4320            13 => SchemaPrimitive::schema_u128,
4321            14 => SchemaPrimitive::schema_i128,
4322            15 => SchemaPrimitive::schema_char,
4323            _ => unreachable!(),
4324        }
4325    }
4326}
4327
4328#[cfg(feature = "quickcheck")]
4329impl Arbitrary for Field {
4330    fn arbitrary(g: &mut Gen) -> Self {
4331        Field {
4332            name: g.choose(&["", "test"]).unwrap().to_string(),
4333            value: <_ as Arbitrary>::arbitrary(g),
4334            offset: <_ as Arbitrary>::arbitrary(g),
4335        }
4336    }
4337}
4338
4339#[cfg(feature = "quickcheck")]
4340impl Arbitrary for Variant {
4341    fn arbitrary(g: &mut Gen) -> Self {
4342        Variant {
4343            name: g.choose(&["", "test"]).unwrap().to_string(),
4344            discriminant: <_ as Arbitrary>::arbitrary(g),
4345            fields: <_ as Arbitrary>::arbitrary(g),
4346        }
4347    }
4348}
4349
4350#[cfg(feature = "quickcheck")]
4351impl Arbitrary for SchemaEnum {
4352    fn arbitrary(g: &mut Gen) -> Self {
4353        SchemaEnum {
4354            dbg_name: g.choose(&["", "test"]).unwrap().to_string(),
4355            variants: (0..*g.choose(&[0usize, 1, 2, 3]).unwrap())
4356                .map(|_| <_ as Arbitrary>::arbitrary(g))
4357                .collect(),
4358            discriminant_size: *g.choose(&[1, 2, 4]).unwrap(),
4359            has_explicit_repr: *g.choose(&[false, true]).unwrap(),
4360            size: <_ as Arbitrary>::arbitrary(g),
4361            alignment: <_ as Arbitrary>::arbitrary(g),
4362        }
4363    }
4364}
4365
4366#[cfg(feature = "quickcheck")]
4367impl Arbitrary for SchemaStruct {
4368    fn arbitrary(g: &mut Gen) -> Self {
4369        SchemaStruct {
4370            fields: (0..*g.choose(&[0usize, 1, 2, 3]).unwrap())
4371                .map(|_| <_ as Arbitrary>::arbitrary(g))
4372                .collect(),
4373            dbg_name: <_ as Arbitrary>::arbitrary(g),
4374            size: <_ as Arbitrary>::arbitrary(g),
4375            alignment: <_ as Arbitrary>::arbitrary(g),
4376        }
4377    }
4378}
4379#[cfg(feature = "quickcheck")]
4380impl Arbitrary for SchemaArray {
4381    fn arbitrary(g: &mut Gen) -> Self {
4382        SchemaArray {
4383            item_type: <_ as Arbitrary>::arbitrary(g),
4384            count: <_ as Arbitrary>::arbitrary(g),
4385        }
4386    }
4387}
4388#[cfg(feature = "quickcheck")]
4389static QUICKCHECKBOUND: AtomicU8 = AtomicU8::new(0);
4390#[cfg(feature = "quickcheck")]
4391impl Arbitrary for Schema {
4392    fn arbitrary(g: &mut Gen) -> Self {
4393        let val = QUICKCHECKBOUND.fetch_add(1, Ordering::Relaxed);
4394        if val > 1 {
4395            QUICKCHECKBOUND.fetch_sub(1, Ordering::Relaxed);
4396            return Schema::ZeroSize;
4397        }
4398        let arg = g.choose(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap_or(&8);
4399        let temp = match arg {
4400            0 => Schema::Struct(<_ as Arbitrary>::arbitrary(g)),
4401            1 => Schema::Enum(<_ as Arbitrary>::arbitrary(g)),
4402            2 => Schema::Primitive(<_ as Arbitrary>::arbitrary(g)),
4403            3 => Schema::Vector(<_ as Arbitrary>::arbitrary(g), VecOrStringLayout::arbitrary(g)),
4404            4 => Schema::Array(SchemaArray::arbitrary(g)),
4405            5 => Schema::SchemaOption(<_ as Arbitrary>::arbitrary(g)),
4406            //Don't generate 'Undefined', since some of our tests assume not
4407            6 => Schema::ZeroSize,
4408            7 => Schema::Custom(g.choose(&["", "test"]).unwrap().to_string()),
4409            _ => Schema::ZeroSize,
4410        };
4411        _ = QUICKCHECKBOUND.fetch_sub(1, Ordering::Relaxed);
4412        temp
4413    }
4414}
4415
4416impl WithSchema for Schema {
4417    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4418        Schema::Undefined
4419    }
4420}
4421impl Serialize for Schema {
4422    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4423        match self {
4424            Schema::Struct(schema_struct) => {
4425                serializer.write_u8(1)?;
4426                schema_struct.serialize(serializer)
4427            }
4428            Schema::Enum(schema_enum) => {
4429                serializer.write_u8(2)?;
4430                schema_enum.serialize(serializer)
4431            }
4432            Schema::Primitive(schema_prim) => {
4433                serializer.write_u8(3)?;
4434                schema_prim.serialize(serializer)?;
4435                Ok(())
4436            }
4437            Schema::Vector(schema_vector, is_standard_layout) => {
4438                serializer.write_u8(4)?;
4439                schema_vector.serialize(serializer)?;
4440                if serializer.file_version > 0 {
4441                    serializer.write_u8(*is_standard_layout as u8)?;
4442                }
4443                Ok(())
4444            }
4445            Schema::Undefined => serializer.write_u8(5),
4446            Schema::ZeroSize => serializer.write_u8(6),
4447            Schema::SchemaOption(content) => {
4448                serializer.write_u8(7)?;
4449                content.serialize(serializer)
4450            }
4451            Schema::Array(array) => {
4452                serializer.write_u8(8)?;
4453                array.serialize(serializer)
4454            }
4455            Schema::Custom(custom) => {
4456                serializer.write_u8(9)?;
4457                custom.serialize(serializer)
4458            }
4459            Schema::Boxed(name) => {
4460                serializer.write_u8(10)?;
4461                name.serialize(serializer)
4462            }
4463            Schema::FnClosure(a, b) => {
4464                serializer.write_u8(11)?;
4465                a.serialize(serializer)?;
4466                b.serialize(serializer)?;
4467                Ok(())
4468            }
4469            Schema::Slice(inner) => {
4470                serializer.write_u8(12)?;
4471                inner.serialize(serializer)?;
4472                Ok(())
4473            }
4474            Schema::Str => {
4475                serializer.write_u8(13)?;
4476                Ok(())
4477            }
4478            Schema::Reference(inner) => {
4479                serializer.write_u8(14)?;
4480                inner.serialize(serializer)?;
4481                Ok(())
4482            }
4483            Schema::Trait(a, b) => {
4484                serializer.write_u8(15)?;
4485                serializer.write_bool(*a)?;
4486                b.serialize(serializer)?;
4487                Ok(())
4488            }
4489            Schema::Recursion(depth) => {
4490                serializer.write_u8(16)?;
4491                serializer.write_usize(*depth)?;
4492                Ok(())
4493            }
4494            Schema::StdIoError => {
4495                serializer.write_u8(17)?;
4496                Ok(())
4497            }
4498            Schema::Future(o, send, sync, unpin) => {
4499                serializer.write_u8(18)?;
4500                serializer
4501                    .write_u8(if *send { 1 } else { 0 } | if *sync { 2 } else { 0 } | if *unpin { 4 } else { 0 })?;
4502                o.serialize(serializer)?;
4503                Ok(())
4504            }
4505            Schema::UninitSlice => {
4506                serializer.write_u8(19)?;
4507                Ok(())
4508            }
4509        }
4510    }
4511}
4512
4513impl Packed for Schema {}
4514impl Deserialize for Schema {
4515    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
4516        let x = deserializer.read_u8()?;
4517        let schema = match x {
4518            1 => Schema::Struct(SchemaStruct::deserialize(deserializer)?),
4519            2 => Schema::Enum(SchemaEnum::deserialize(deserializer)?),
4520            3 => Schema::Primitive(SchemaPrimitive::deserialize(deserializer)?),
4521            4 => Schema::Vector(
4522                Box::new(Schema::deserialize(deserializer)?),
4523                if deserializer.file_version > 0 {
4524                    VecOrStringLayout::deserialize(deserializer)?
4525                } else {
4526                    VecOrStringLayout::Unknown
4527                },
4528            ),
4529            5 => Schema::Undefined,
4530            6 => Schema::ZeroSize,
4531            7 => Schema::SchemaOption(Box::new(Schema::deserialize(deserializer)?)),
4532            8 => Schema::Array(SchemaArray::deserialize(deserializer)?),
4533            9 => Schema::Custom(String::deserialize(deserializer)?),
4534            10 => Schema::Boxed(<_ as Deserialize>::deserialize(deserializer)?),
4535            11 => Schema::FnClosure(
4536                <_ as Deserialize>::deserialize(deserializer)?,
4537                <_ as Deserialize>::deserialize(deserializer)?,
4538            ),
4539            12 => Schema::Slice(Box::new(<_ as Deserialize>::deserialize(deserializer)?)),
4540            13 => Schema::Str,
4541            14 => Schema::Reference(Box::new(<_ as Deserialize>::deserialize(deserializer)?)),
4542            15 => Schema::Trait(
4543                <_ as Deserialize>::deserialize(deserializer)?,
4544                <_ as Deserialize>::deserialize(deserializer)?,
4545            ),
4546            16 => Schema::Recursion(<_ as Deserialize>::deserialize(deserializer)?),
4547            17 => Schema::StdIoError,
4548            18 => {
4549                let mask = deserializer.read_u8()?;
4550                let send = (mask & 1) != 0;
4551                let sync = (mask & 2) != 0;
4552                let unpin = (mask & 4) != 0;
4553                Schema::Future(<_ as Deserialize>::deserialize(deserializer)?, send, sync, unpin)
4554            }
4555            19 => {
4556                Schema::UninitSlice
4557            }
4558            c => {
4559                return Err(SavefileError::GeneralError {
4560                    msg: format!("Corrupt, or future schema, schema variant {} encountered", c),
4561                })
4562            }
4563        };
4564
4565        Ok(schema)
4566    }
4567}
4568impl WithSchema for str {
4569    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4570        Schema::Primitive(SchemaPrimitive::schema_string(VecOrStringLayout::Unknown))
4571    }
4572}
4573
4574impl WithSchema for String {
4575    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
4576        Schema::Primitive(SchemaPrimitive::schema_string(calculate_string_memory_layout()))
4577    }
4578}
4579impl Introspect for str {
4580    fn introspect_value(&self) -> String {
4581        self.to_string()
4582    }
4583
4584    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_>>> {
4585        None
4586    }
4587}
4588impl Introspect for String {
4589    fn introspect_value(&self) -> String {
4590        self.to_string()
4591    }
4592
4593    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_>>> {
4594        None
4595    }
4596}
4597impl Serialize for String {
4598    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4599        serializer.write_string(self)
4600    }
4601}
4602impl Serialize for str {
4603    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4604        serializer.write_string(self)
4605    }
4606}
4607
4608impl Packed for String {}
4609
4610impl Packed for str {}
4611
4612impl Deserialize for String {
4613    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<String, SavefileError> {
4614        deserializer.read_string()
4615    }
4616}
4617
4618/// Type of single child of introspector for Mutex
4619#[cfg(feature = "parking_lot")]
4620pub struct IntrospectItemMutex<'a, T> {
4621    g: MutexGuard<'a, T>,
4622}
4623
4624#[cfg(feature = "parking_lot")]
4625impl<'a, T: Introspect> IntrospectItem<'a> for IntrospectItemMutex<'a, T> {
4626    fn key(&self) -> &str {
4627        "0"
4628    }
4629
4630    fn val(&self) -> &dyn Introspect {
4631        self.g.deref()
4632    }
4633}
4634
4635#[cfg(feature = "parking_lot")]
4636impl<T: Introspect> Introspect for Mutex<T> {
4637    fn introspect_value(&self) -> String {
4638        format!("Mutex<{}>", std::any::type_name::<T>())
4639    }
4640
4641    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4642        if index == 0 {
4643            Some(Box::new(IntrospectItemMutex { g: self.lock() }))
4644        } else {
4645            None
4646        }
4647    }
4648}
4649
4650/// Type of single child of introspector for std::sync::Mutex
4651pub struct IntrospectItemStdMutex<'a, T> {
4652    g: std::sync::MutexGuard<'a, T>,
4653}
4654
4655impl<'a, T: Introspect> IntrospectItem<'a> for IntrospectItemStdMutex<'a, T> {
4656    fn key(&self) -> &str {
4657        "0"
4658    }
4659
4660    fn val(&self) -> &dyn Introspect {
4661        self.g.deref()
4662    }
4663}
4664
4665impl<T: Introspect> Introspect for std::sync::Mutex<T> {
4666    fn introspect_value(&self) -> String {
4667        format!("Mutex<{}>", std::any::type_name::<T>())
4668    }
4669
4670    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4671        match self.lock() {
4672            Ok(item) => {
4673                if index == 0 {
4674                    Some(Box::new(IntrospectItemStdMutex { g: item }))
4675                } else {
4676                    None
4677                }
4678            }
4679            Err(_) => None,
4680        }
4681    }
4682}
4683
4684impl<T: WithSchema> WithSchema for std::sync::Mutex<T> {
4685    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
4686        T::schema(version, context)
4687    }
4688}
4689impl<T> Packed for std::sync::Mutex<T> {}
4690impl<T: Serialize> Serialize for std::sync::Mutex<T> {
4691    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4692        let data = self.lock()?;
4693        data.serialize(serializer)
4694    }
4695}
4696
4697impl<T: Deserialize> Deserialize for std::sync::Mutex<T> {
4698    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<std::sync::Mutex<T>, SavefileError> {
4699        Ok(std::sync::Mutex::new(T::deserialize(deserializer)?))
4700    }
4701}
4702
4703#[cfg(feature = "parking_lot")]
4704impl<T: WithSchema> WithSchema for Mutex<T> {
4705    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
4706        T::schema(version, context)
4707    }
4708}
4709
4710#[cfg(feature = "parking_lot")]
4711impl<T> Packed for Mutex<T> {}
4712
4713#[cfg(feature = "parking_lot")]
4714impl<T: Serialize> Serialize for Mutex<T> {
4715    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4716        let data = self.lock();
4717        data.serialize(serializer)
4718    }
4719}
4720
4721#[cfg(feature = "parking_lot")]
4722impl<T: Deserialize> Deserialize for Mutex<T> {
4723    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Mutex<T>, SavefileError> {
4724        Ok(Mutex::new(T::deserialize(deserializer)?))
4725    }
4726}
4727
4728/// Type of single child of introspector for RwLock
4729#[cfg(feature = "parking_lot")]
4730pub struct IntrospectItemRwLock<'a, T> {
4731    g: RwLockReadGuard<'a, T>,
4732}
4733
4734#[cfg(feature = "parking_lot")]
4735impl<'a, T: Introspect> IntrospectItem<'a> for IntrospectItemRwLock<'a, T> {
4736    fn key(&self) -> &str {
4737        "0"
4738    }
4739
4740    fn val(&self) -> &dyn Introspect {
4741        self.g.deref()
4742    }
4743}
4744
4745impl<T: Introspect> Introspect for std::cell::Ref<'_, T> {
4746    fn introspect_value(&self) -> String {
4747        let sub_value = (**self).introspect_value();
4748        format!("Ref({})", sub_value)
4749    }
4750    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4751        (**self).introspect_child(index)
4752    }
4753    fn introspect_len(&self) -> usize {
4754        (**self).introspect_len()
4755    }
4756}
4757
4758impl<'a, T: Introspect> IntrospectItem<'a> for std::cell::Ref<'a, T> {
4759    fn key(&self) -> &str {
4760        "ref"
4761    }
4762    /// The introspectable value of the child.
4763    fn val(&self) -> &dyn Introspect {
4764        self
4765    }
4766}
4767
4768impl<T: Introspect> Introspect for RefCell<T> {
4769    fn introspect_value(&self) -> String {
4770        let sub_value = self.borrow().introspect_value();
4771        format!("RefCell({})", sub_value)
4772    }
4773
4774    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4775        // Introspect not supported
4776        if index != 0 {
4777            return None;
4778        }
4779        let rf = self.borrow();
4780        Some(Box::new(rf))
4781    }
4782
4783    fn introspect_len(&self) -> usize {
4784        // Introspect not supported
4785        1
4786    }
4787}
4788
4789impl<T: Introspect> Introspect for Rc<T> {
4790    fn introspect_value(&self) -> String {
4791        format!("Rc({})", self.deref().introspect_value())
4792    }
4793
4794    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4795        self.deref().introspect_child(index)
4796    }
4797
4798    fn introspect_len(&self) -> usize {
4799        self.deref().introspect_len()
4800    }
4801}
4802
4803impl<T: Introspect> Introspect for Arc<T> {
4804    fn introspect_value(&self) -> String {
4805        format!("Arc({})", self.deref().introspect_value())
4806    }
4807
4808    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4809        self.deref().introspect_child(index)
4810    }
4811
4812    fn introspect_len(&self) -> usize {
4813        self.deref().introspect_len()
4814    }
4815}
4816#[cfg(feature = "parking_lot")]
4817impl<T: Introspect> Introspect for RwLock<T> {
4818    fn introspect_value(&self) -> String {
4819        format!("RwLock<{}>", std::any::type_name::<T>())
4820    }
4821    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4822        if index == 0 {
4823            Some(Box::new(IntrospectItemRwLock { g: self.read() }))
4824        } else {
4825            None
4826        }
4827    }
4828
4829    fn introspect_len(&self) -> usize {
4830        1
4831    }
4832}
4833
4834#[cfg(feature = "parking_lot")]
4835impl<T: WithSchema> WithSchema for RwLock<T> {
4836    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
4837        T::schema(version, context)
4838    }
4839}
4840
4841#[cfg(feature = "parking_lot")]
4842impl<T> Packed for RwLock<T> {}
4843
4844#[cfg(feature = "parking_lot")]
4845impl<T: Serialize> Serialize for RwLock<T> {
4846    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
4847        let data = self.read();
4848        data.serialize(serializer)
4849    }
4850}
4851
4852#[cfg(feature = "parking_lot")]
4853impl<T: Deserialize> Deserialize for RwLock<T> {
4854    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<RwLock<T>, SavefileError> {
4855        Ok(RwLock::new(T::deserialize(deserializer)?))
4856    }
4857}
4858
4859/// Standard child for Introspect trait. Simply owned key string and reference to dyn Introspect
4860pub struct IntrospectItemSimple<'a> {
4861    key: String,
4862    val: &'a dyn Introspect,
4863}
4864
4865impl<'a> IntrospectItem<'a> for IntrospectItemSimple<'a> {
4866    fn key(&self) -> &str {
4867        &self.key
4868    }
4869
4870    fn val(&self) -> &dyn Introspect {
4871        self.val
4872    }
4873}
4874
4875/// Create a default IntrospectItem with the given key and Introspect.
4876pub fn introspect_item<'a>(key: String, val: &'a dyn Introspect) -> Box<dyn IntrospectItem<'a> + 'a> {
4877    Box::new(IntrospectItemSimple { key, val })
4878}
4879
4880#[cfg(not(feature = "nightly"))]
4881impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for HashMap<K, V, S> {
4882    fn introspect_value(&self) -> String {
4883        format!("HashMap<{},{}>", std::any::type_name::<K>(), std::any::type_name::<V>())
4884    }
4885
4886    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4887        let bucket = index / 2;
4888        let off = index % 2;
4889        if let Some((key, val)) = self.iter().nth(bucket) {
4890            if off == 0 {
4891                Some(introspect_item(format!("Key #{}", index), key))
4892            } else {
4893                Some(introspect_item(format!("Value #{}", index), val))
4894            }
4895        } else {
4896            None
4897        }
4898    }
4899    fn introspect_len(&self) -> usize {
4900        self.len()
4901    }
4902}
4903
4904#[cfg(feature = "nightly")]
4905impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for HashMap<K, V, S> {
4906    default fn introspect_value(&self) -> String {
4907        format!("HashMap<{},{}>", std::any::type_name::<K>(), std::any::type_name::<V>())
4908    }
4909
4910    default fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4911        let bucket = index / 2;
4912        let off = index % 2;
4913        if let Some((key, val)) = self.iter().nth(bucket) {
4914            if off == 0 {
4915                Some(introspect_item(format!("Key #{}", index), key))
4916            } else {
4917                Some(introspect_item(format!("Value #{}", index), val))
4918            }
4919        } else {
4920            None
4921        }
4922    }
4923    default fn introspect_len(&self) -> usize {
4924        self.len()
4925    }
4926}
4927
4928#[cfg(feature = "nightly")]
4929impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for HashMap<K, V, S>
4930where
4931    K: ToString,
4932{
4933    fn introspect_value(&self) -> String {
4934        format!("HashMap<{},{}>", std::any::type_name::<K>(), std::any::type_name::<V>())
4935    }
4936
4937    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4938        if let Some((key, val)) = self.iter().nth(index) {
4939            Some(introspect_item(key.to_string(), val))
4940        } else {
4941            None
4942        }
4943    }
4944    fn introspect_len(&self) -> usize {
4945        self.len()
4946    }
4947}
4948
4949impl<K: Introspect + Eq + Hash, S: ::std::hash::BuildHasher> Introspect for HashSet<K, S> {
4950    fn introspect_value(&self) -> String {
4951        format!("HashSet<{}>", std::any::type_name::<K>())
4952    }
4953
4954    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4955        if let Some(key) = self.iter().nth(index) {
4956            Some(introspect_item(format!("#{}", index), key))
4957        } else {
4958            None
4959        }
4960    }
4961    fn introspect_len(&self) -> usize {
4962        self.len()
4963    }
4964}
4965
4966impl<K: Introspect> Introspect for BTreeSet<K> {
4967    fn introspect_value(&self) -> String {
4968        format!("BTreeSet<{}>", std::any::type_name::<K>())
4969    }
4970
4971    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4972        if let Some(key) = self.iter().nth(index) {
4973            Some(introspect_item(format!("#{}", index), key))
4974        } else {
4975            None
4976        }
4977    }
4978    fn introspect_len(&self) -> usize {
4979        self.len()
4980    }
4981}
4982
4983impl<K: Introspect, V: Introspect> Introspect for BTreeMap<K, V> {
4984    fn introspect_value(&self) -> String {
4985        format!(
4986            "BTreeMap<{},{}>",
4987            std::any::type_name::<K>(),
4988            std::any::type_name::<V>()
4989        )
4990    }
4991
4992    // This has very bad performance. But with the model behind Savefile Introspect it
4993    // is presently hard to do much better
4994    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
4995        let bucket = index / 2;
4996        let off = index % 2;
4997        if let Some((key, val)) = self.iter().nth(bucket) {
4998            if off == 0 {
4999                Some(introspect_item(format!("Key #{}", index), key))
5000            } else {
5001                Some(introspect_item(format!("Value #{}", index), val))
5002            }
5003        } else {
5004            None
5005        }
5006    }
5007    fn introspect_len(&self) -> usize {
5008        self.len()
5009    }
5010}
5011impl<K: WithSchema + 'static, V: WithSchema + 'static> WithSchema for BTreeMap<K, V> {
5012    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5013        Schema::Vector(
5014            Box::new(Schema::Struct(SchemaStruct {
5015                dbg_name: "KeyValuePair".to_string(),
5016                size: None,
5017                alignment: None,
5018                fields: vec![
5019                    Field {
5020                        name: "key".to_string(),
5021                        value: Box::new(context.possible_recursion::<K>(|context| K::schema(version, context))),
5022                        offset: None,
5023                    },
5024                    Field {
5025                        name: "value".to_string(),
5026                        value: Box::new(context.possible_recursion::<V>(|context| V::schema(version, context))),
5027                        offset: None,
5028                    },
5029                ],
5030            })),
5031            VecOrStringLayout::Unknown,
5032        )
5033    }
5034}
5035impl<K, V> Packed for BTreeMap<K, V> {}
5036impl<K: Serialize + 'static, V: Serialize + 'static> Serialize for BTreeMap<K, V> {
5037    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5038        self.len().serialize(serializer)?;
5039        for (k, v) in self {
5040            k.serialize(serializer)?;
5041            v.serialize(serializer)?;
5042        }
5043        Ok(())
5044    }
5045}
5046impl<K: Deserialize + Ord + 'static, V: Deserialize + 'static> Deserialize for BTreeMap<K, V> {
5047    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5048        let mut ret = BTreeMap::new();
5049        let count = <usize as Deserialize>::deserialize(deserializer)?;
5050        for _ in 0..count {
5051            ret.insert(
5052                <_ as Deserialize>::deserialize(deserializer)?,
5053                <_ as Deserialize>::deserialize(deserializer)?,
5054            );
5055        }
5056        Ok(ret)
5057    }
5058}
5059
5060impl<K> Packed for BTreeSet<K> {}
5061impl<K: WithSchema + 'static> WithSchema for BTreeSet<K> {
5062    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5063        Schema::Vector(
5064            Box::new(context.possible_recursion::<K>(|context| K::schema(version, context))),
5065            VecOrStringLayout::Unknown,
5066        )
5067    }
5068}
5069impl<K: Serialize + 'static> Serialize for BTreeSet<K> {
5070    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5071        serializer.write_usize(self.len())?;
5072        for item in self {
5073            item.serialize(serializer)?;
5074        }
5075        Ok(())
5076    }
5077}
5078impl<K: Deserialize + 'static + Ord> Deserialize for BTreeSet<K> {
5079    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5080        let cnt = deserializer.read_usize()?;
5081        let mut ret = BTreeSet::new();
5082        for _ in 0..cnt {
5083            ret.insert(<_ as Deserialize>::deserialize(deserializer)?);
5084        }
5085        Ok(ret)
5086    }
5087}
5088
5089impl<K, S: ::std::hash::BuildHasher> Packed for HashSet<K, S> {}
5090impl<K: WithSchema + 'static, S: ::std::hash::BuildHasher> WithSchema for HashSet<K, S> {
5091    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5092        Schema::Vector(
5093            Box::new(context.possible_recursion::<K>(|context| K::schema(version, context))),
5094            VecOrStringLayout::Unknown,
5095        )
5096    }
5097}
5098impl<K: Serialize + 'static, S: ::std::hash::BuildHasher> Serialize for HashSet<K, S> {
5099    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5100        serializer.write_usize(self.len())?;
5101        for item in self {
5102            item.serialize(serializer)?;
5103        }
5104        Ok(())
5105    }
5106}
5107impl<K: Deserialize + Eq + Hash + 'static, S: ::std::hash::BuildHasher + Default> Deserialize for HashSet<K, S> {
5108    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5109        let cnt = deserializer.read_usize()?;
5110        let mut ret = HashSet::with_capacity_and_hasher(cnt, S::default());
5111        for _ in 0..cnt {
5112            ret.insert(<_ as Deserialize>::deserialize(deserializer)?);
5113        }
5114        Ok(ret)
5115    }
5116}
5117
5118impl<K: WithSchema + Eq + Hash + 'static, V: WithSchema + 'static, S: ::std::hash::BuildHasher> WithSchema
5119    for HashMap<K, V, S>
5120{
5121    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5122        Schema::Vector(
5123            Box::new(Schema::Struct(SchemaStruct {
5124                dbg_name: "KeyValuePair".to_string(),
5125                size: None,
5126                alignment: None,
5127                fields: vec![
5128                    Field {
5129                        name: "key".to_string(),
5130                        value: Box::new(context.possible_recursion::<K>(|context| K::schema(version, context))),
5131                        offset: None,
5132                    },
5133                    Field {
5134                        name: "value".to_string(),
5135                        value: Box::new(context.possible_recursion::<K>(|context| V::schema(version, context))),
5136                        offset: None,
5137                    },
5138                ],
5139            })),
5140            VecOrStringLayout::Unknown,
5141        )
5142    }
5143}
5144impl<K: Eq + Hash, V, S: ::std::hash::BuildHasher> Packed for HashMap<K, V, S> {}
5145impl<K: Serialize + Eq + Hash + 'static, V: Serialize + 'static, S: ::std::hash::BuildHasher> Serialize
5146    for HashMap<K, V, S>
5147{
5148    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5149        serializer.write_usize(self.len())?;
5150        for (k, v) in self.iter() {
5151            k.serialize(serializer)?;
5152            v.serialize(serializer)?;
5153        }
5154        Ok(())
5155    }
5156}
5157
5158impl<K: Deserialize + Eq + Hash + 'static, V: Deserialize + 'static, S: ::std::hash::BuildHasher + Default> Deserialize
5159    for HashMap<K, V, S>
5160{
5161    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5162        let l = deserializer.read_usize()?;
5163        let mut ret: Self = HashMap::with_capacity_and_hasher(l, Default::default());
5164        for _ in 0..l {
5165            ret.insert(K::deserialize(deserializer)?, V::deserialize(deserializer)?);
5166        }
5167        Ok(ret)
5168    }
5169}
5170
5171#[cfg(feature = "indexmap")]
5172impl<K: WithSchema + Eq + Hash + 'static, V: WithSchema + 'static, S: ::std::hash::BuildHasher> WithSchema
5173    for IndexMap<K, V, S>
5174{
5175    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5176        Schema::Vector(
5177            Box::new(Schema::Struct(SchemaStruct {
5178                dbg_name: "KeyValuePair".to_string(),
5179                size: None,
5180                alignment: None,
5181                fields: vec![
5182                    Field {
5183                        name: "key".to_string(),
5184                        value: Box::new(context.possible_recursion::<K>(|context| K::schema(version, context))),
5185                        offset: None,
5186                    },
5187                    Field {
5188                        name: "value".to_string(),
5189                        value: Box::new(context.possible_recursion::<K>(|context| V::schema(version, context))),
5190                        offset: None,
5191                    },
5192                ],
5193            })),
5194            VecOrStringLayout::Unknown,
5195        )
5196    }
5197}
5198
5199#[cfg(all(not(feature = "nightly"), feature = "indexmap"))]
5200impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for IndexMap<K, V, S> {
5201    fn introspect_value(&self) -> String {
5202        format!(
5203            "IndexMap<{},{}>",
5204            std::any::type_name::<K>(),
5205            std::any::type_name::<V>()
5206        )
5207    }
5208
5209    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5210        let bucket = index / 2;
5211        let off = index % 2;
5212        if let Some((k, v)) = self.get_index(bucket) {
5213            if off == 0 {
5214                Some(introspect_item(format!("Key #{}", bucket), k))
5215            } else {
5216                Some(introspect_item(format!("Value #{}", bucket), v))
5217            }
5218        } else {
5219            None
5220        }
5221    }
5222
5223    fn introspect_len(&self) -> usize {
5224        self.len()
5225    }
5226}
5227
5228#[cfg(all(feature = "nightly", feature = "indexmap"))]
5229impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for IndexMap<K, V, S> {
5230    default fn introspect_value(&self) -> String {
5231        format!(
5232            "IndexMap<{},{}>",
5233            std::any::type_name::<K>(),
5234            std::any::type_name::<V>()
5235        )
5236    }
5237
5238    default fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5239        let bucket = index / 2;
5240        let off = index % 2;
5241        if let Some((k, v)) = self.get_index(bucket) {
5242            if off == 0 {
5243                Some(introspect_item(format!("Key #{}", bucket), k))
5244            } else {
5245                Some(introspect_item(format!("Value #{}", bucket), v))
5246            }
5247        } else {
5248            None
5249        }
5250    }
5251
5252    default fn introspect_len(&self) -> usize {
5253        self.len()
5254    }
5255}
5256
5257#[cfg(all(feature = "nightly", feature = "indexmap"))]
5258impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for IndexMap<K, V, S>
5259where
5260    K: ToString,
5261{
5262    fn introspect_value(&self) -> String {
5263        format!(
5264            "IndexMap<{},{}>",
5265            std::any::type_name::<K>(),
5266            std::any::type_name::<V>()
5267        )
5268    }
5269
5270    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5271        if let Some((k, v)) = self.get_index(index) {
5272            Some(introspect_item(k.to_string(), v))
5273        } else {
5274            None
5275        }
5276    }
5277
5278    fn introspect_len(&self) -> usize {
5279        self.len()
5280    }
5281}
5282#[cfg(feature = "indexmap")]
5283impl<K: Eq + Hash, V, S: ::std::hash::BuildHasher> Packed for IndexMap<K, V, S> {}
5284
5285#[cfg(feature = "indexmap")]
5286impl<K: Serialize + Eq + Hash + 'static, V: Serialize + 'static, S: ::std::hash::BuildHasher> Serialize
5287    for IndexMap<K, V, S>
5288{
5289    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5290        serializer.write_usize(self.len())?;
5291        for (k, v) in self.iter() {
5292            k.serialize(serializer)?;
5293            v.serialize(serializer)?;
5294        }
5295        Ok(())
5296    }
5297}
5298
5299#[cfg(feature = "indexmap")]
5300impl<K: Deserialize + Eq + Hash + 'static, V: Deserialize + 'static> Deserialize for IndexMap<K, V> {
5301    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5302        let l = deserializer.read_usize()?;
5303        let mut ret = IndexMap::with_capacity(l);
5304        for _ in 0..l {
5305            ret.insert(K::deserialize(deserializer)?, V::deserialize(deserializer)?);
5306        }
5307        Ok(ret)
5308    }
5309}
5310
5311#[cfg(feature = "indexmap")]
5312impl<K: Introspect + Eq + Hash, S: ::std::hash::BuildHasher> Introspect for IndexSet<K, S> {
5313    fn introspect_value(&self) -> String {
5314        format!("IndexSet<{}>", std::any::type_name::<K>())
5315    }
5316
5317    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5318        if let Some(val) = self.get_index(index) {
5319            Some(introspect_item(format!("#{}", index), val))
5320        } else {
5321            None
5322        }
5323    }
5324
5325    fn introspect_len(&self) -> usize {
5326        self.len()
5327    }
5328}
5329
5330#[cfg(feature = "indexmap")]
5331impl<K: Eq + Hash, S: ::std::hash::BuildHasher> Packed for IndexSet<K, S> {}
5332
5333#[cfg(feature = "indexmap")]
5334impl<K: WithSchema + Eq + Hash + 'static, S: ::std::hash::BuildHasher> WithSchema for IndexSet<K, S> {
5335    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5336        Schema::Vector(
5337            Box::new(Schema::Struct(SchemaStruct {
5338                dbg_name: "Key".to_string(),
5339                size: None,
5340                alignment: None,
5341                fields: vec![Field {
5342                    name: "key".to_string(),
5343                    value: Box::new(context.possible_recursion::<K>(|context| K::schema(version, context))),
5344                    offset: None,
5345                }],
5346            })),
5347            VecOrStringLayout::Unknown,
5348        )
5349    }
5350}
5351
5352#[cfg(feature = "indexmap")]
5353impl<K: Serialize + Eq + Hash + 'static, S: ::std::hash::BuildHasher> Serialize for IndexSet<K, S> {
5354    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5355        serializer.write_usize(self.len())?;
5356        for k in self.iter() {
5357            k.serialize(serializer)?;
5358        }
5359        Ok(())
5360    }
5361}
5362
5363#[cfg(feature = "indexmap")]
5364impl<K: Deserialize + Eq + Hash + 'static> Deserialize for IndexSet<K> {
5365    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5366        let l = deserializer.read_usize()?;
5367        let mut ret = IndexSet::with_capacity(l);
5368        for _ in 0..l {
5369            ret.insert(K::deserialize(deserializer)?);
5370        }
5371        Ok(ret)
5372    }
5373}
5374
5375/// Something that can construct a value of type T.
5376/// Used when a field has been removed using the `AbiRemoved` type.
5377/// Usage:
5378/// ```rust
5379/// use savefile::{AbiRemoved, ValueConstructor};
5380/// use savefile_derive::Savefile;
5381/// #[derive(Savefile)]
5382/// struct MyStruct {
5383///     my_field: String,
5384///     #[savefile_versions="..0"]
5385///     my_removed_field: AbiRemoved<String, MyStructMyRemovedFieldFactory>,
5386/// }
5387/// struct MyStructMyRemovedFieldFactory;
5388/// impl ValueConstructor<String> for MyStructMyRemovedFieldFactory {
5389///     fn make_value() -> String {
5390///         "Default value for when values of version 0 are to be serialized".to_string()
5391///     }
5392/// }
5393/// ```
5394#[cfg_attr(
5395    feature = "rust1_78",
5396    diagnostic::on_unimplemented(
5397        message = "`{Self}` cannot serve as a factory generating default values of type {T}, since it doesn't implement the trait `savefile::ValueConstructor<{T}>`-",
5398        label = "`{Self}` cannot produce values of type `{T}`",
5399        note = "Check that any type used as 2nd type parameter to AbiRemoved implements `savefile::ValueConstructor<{T}>`.",
5400        note = "Alternatively, skip the 2nd parameter entirely, and ensure that `{T}` implements `Default`.",
5401    )
5402)]
5403pub trait ValueConstructor<T> {
5404    /// Create a value of type T.
5405    /// This is used by the AbiRemoved trait to be able to invent
5406    /// values when writing removed fields from old protocols.
5407    fn make_value() -> T;
5408}
5409
5410/// A value constructor that delegates to the 'Default' trait.
5411/// Requires that type `T` implements `Default`.
5412#[derive(Debug, PartialEq, Eq)]
5413pub struct DefaultValueConstructor<T> {
5414    phantom: PhantomData<*const T>,
5415}
5416
5417impl<T: Default> ValueConstructor<T> for DefaultValueConstructor<T> {
5418    fn make_value() -> T {
5419        <T as Default>::default()
5420    }
5421}
5422
5423/// Helper struct which represents a field which has been removed.
5424///
5425/// In contrast to AbiRemoved, this type only supports deserialization.
5426/// It is thus not recommended for use when SavefileAbi is to be used, and
5427/// forward compatibility is desired.
5428///
5429/// The difference is that Removed does not require T to implement Default,
5430/// or any other factory trait, since we never need to serialize dummy
5431/// values of Removed (we never serialize using a schema where a field i Removed).
5432#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
5433pub struct Removed<T> {
5434    phantom: std::marker::PhantomData<*const T>,
5435}
5436
5437/// Removed is a zero-sized type. It contains a PhantomData<*const T>, which means
5438/// it doesn't implement Send or Sync per default. However, implementing these
5439/// is actually safe, so implement it manually.
5440unsafe impl<T> Send for Removed<T> {}
5441/// Removed is a zero-sized type. It contains a PhantomData<*const T>, which means
5442/// it doesn't implement Send or Sync per default. However, implementing these
5443/// is actually safe, so implement it manually.
5444unsafe impl<T> Sync for Removed<T> {}
5445
5446impl<T> Removed<T> {
5447    /// Helper to create an instance of `Removed<T>`. `Removed<T>` has no data.
5448    pub fn new() -> Removed<T> {
5449        Removed {
5450            phantom: std::marker::PhantomData,
5451        }
5452    }
5453}
5454impl<T: WithSchema> WithSchema for Removed<T> {
5455    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5456        <T>::schema(version, context)
5457    }
5458}
5459
5460impl<T: Introspect> Introspect for Removed<T> {
5461    fn introspect_value(&self) -> String {
5462        format!("Removed<{}>", std::any::type_name::<T>())
5463    }
5464
5465    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5466        None
5467    }
5468}
5469impl<T> Packed for Removed<T> {
5470    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
5471        IsPacked::yes()
5472    }
5473}
5474impl<T: WithSchema> Serialize for Removed<T> {
5475    fn serialize(&self, _serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5476        panic!("Something is wrong with version-specification of fields - there was an attempt to actually serialize a removed field!");
5477    }
5478}
5479impl<T: WithSchema + Deserialize> Deserialize for Removed<T> {
5480    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5481        T::deserialize(deserializer)?;
5482        Ok(Removed {
5483            phantom: std::marker::PhantomData,
5484        })
5485    }
5486}
5487
5488/// Helper struct which represents a field which has been removed, for use with
5489/// SavefileAbi - supporting both serialization and deserialization.
5490///
5491/// In contrast to `Removed`, this type supports both serialization and
5492/// deserialization, and is preferred when SavefileAbi is to be used.
5493/// Regular Savefile does not support serializing older versions, whereas
5494/// SavefileAbi does.
5495#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
5496pub struct AbiRemoved<T, D = DefaultValueConstructor<T>>
5497where
5498    D: ValueConstructor<T>,
5499{
5500    phantom: std::marker::PhantomData<(*const T, *const D)>,
5501}
5502
5503/// Removed is a zero-sized type. It contains a PhantomData<*const T>, which means
5504/// it doesn't implement Send or Sync per default. However, implementing these
5505/// is actually safe, so implement it manually.
5506unsafe impl<T, D: ValueConstructor<T>> Send for AbiRemoved<T, D> {}
5507/// Removed is a zero-sized type. It contains a PhantomData<*const T>, which means
5508/// it doesn't implement Send or Sync per default. However, implementing these
5509/// is actually safe, so implement it manually.
5510unsafe impl<T, D: ValueConstructor<T>> Sync for AbiRemoved<T, D> {}
5511
5512impl<T, D: ValueConstructor<T>> AbiRemoved<T, D> {
5513    /// Helper to create an instance of `AbiRemoved<T>`. `AbiRemoved<T>` has no data.
5514    pub fn new() -> AbiRemoved<T, D> {
5515        AbiRemoved {
5516            phantom: std::marker::PhantomData,
5517        }
5518    }
5519}
5520
5521impl<T: WithSchema, D: ValueConstructor<T>> WithSchema for AbiRemoved<T, D> {
5522    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5523        <T>::schema(version, context)
5524    }
5525}
5526
5527impl<T: Introspect, D: ValueConstructor<T>> Introspect for AbiRemoved<T, D> {
5528    fn introspect_value(&self) -> String {
5529        format!("AbiRemoved<{}>", std::any::type_name::<T>())
5530    }
5531
5532    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5533        None
5534    }
5535}
5536impl<T, D: ValueConstructor<T>> Packed for AbiRemoved<T, D> {
5537    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
5538        IsPacked::yes()
5539    }
5540}
5541impl<T: WithSchema + Serialize + Default, D: ValueConstructor<T>> Serialize for AbiRemoved<T, D> {
5542    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5543        let dummy = D::make_value();
5544        dummy.serialize(serializer)?;
5545        Ok(())
5546    }
5547}
5548impl<T: WithSchema + Deserialize, D: ValueConstructor<T>> Deserialize for AbiRemoved<T, D> {
5549    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5550        T::deserialize(deserializer)?;
5551        Ok(AbiRemoved {
5552            phantom: std::marker::PhantomData,
5553        })
5554    }
5555}
5556
5557impl<T> Introspect for PhantomData<T> {
5558    fn introspect_value(&self) -> String {
5559        "PhantomData".to_string()
5560    }
5561
5562    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5563        None
5564    }
5565}
5566impl<T> WithSchema for std::marker::PhantomData<T> {
5567    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
5568        Schema::ZeroSize
5569    }
5570}
5571impl<T> Packed for std::marker::PhantomData<T> {
5572    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
5573        IsPacked::yes()
5574    }
5575}
5576impl<T> Serialize for std::marker::PhantomData<T> {
5577    fn serialize(&self, _serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5578        Ok(())
5579    }
5580}
5581impl<T> Deserialize for std::marker::PhantomData<T> {
5582    fn deserialize(_deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5583        Ok(std::marker::PhantomData)
5584    }
5585}
5586
5587impl<T: Introspect> Introspect for Box<T> {
5588    fn introspect_value(&self) -> String {
5589        self.deref().introspect_value()
5590    }
5591    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5592        self.deref().introspect_child(index)
5593    }
5594    fn introspect_len(&self) -> usize {
5595        self.deref().introspect_len()
5596    }
5597}
5598impl<T: Introspect> Introspect for Option<T> {
5599    fn introspect_value(&self) -> String {
5600        if let Some(cont) = self {
5601            format!("Some({})", cont.introspect_value())
5602        } else {
5603            "None".to_string()
5604        }
5605    }
5606
5607    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5608        if let Some(cont) = self {
5609            cont.introspect_child(index)
5610        } else {
5611            None
5612        }
5613    }
5614    fn introspect_len(&self) -> usize {
5615        if let Some(cont) = self {
5616            cont.introspect_len()
5617        } else {
5618            0
5619        }
5620    }
5621}
5622
5623impl<T: WithSchema> WithSchema for Option<T> {
5624    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5625        Schema::SchemaOption(Box::new(T::schema(version, context)))
5626    }
5627}
5628impl<T> Packed for Option<T> {} //Sadly, Option does not allow the #"reprC"-optimization
5629impl<T: Serialize> Serialize for Option<T> {
5630    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5631        match self {
5632            Some(ref x) => {
5633                serializer.write_bool(true)?;
5634                x.serialize(serializer)
5635            }
5636            None => serializer.write_bool(false),
5637        }
5638    }
5639}
5640impl<T: Deserialize> Deserialize for Option<T> {
5641    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5642        let issome = deserializer.read_bool()?;
5643        if issome {
5644            Ok(Some(T::deserialize(deserializer)?))
5645        } else {
5646            Ok(None)
5647        }
5648    }
5649}
5650
5651impl<T: Introspect, R: Introspect> Introspect for Result<T, R> {
5652    fn introspect_value(&self) -> String {
5653        match self {
5654            Ok(cont) => format!("Ok({})", cont.introspect_value()),
5655            Err(cont) => format!("Err({})", cont.introspect_value()),
5656        }
5657    }
5658
5659    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5660        match self {
5661            Ok(cont) => cont.introspect_child(index),
5662            Err(cont) => cont.introspect_child(index),
5663        }
5664    }
5665    fn introspect_len(&self) -> usize {
5666        match self {
5667            Ok(cont) => cont.introspect_len(),
5668            Err(cont) => cont.introspect_len(),
5669        }
5670    }
5671}
5672
5673impl<T: WithSchema, R: WithSchema> WithSchema for Result<T, R> {
5674    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5675        Schema::Enum(SchemaEnum {
5676            dbg_name: "Result".to_string(),
5677            size: None,
5678            alignment: None,
5679            variants: vec![
5680                Variant {
5681                    name: "Ok".to_string(),
5682                    discriminant: 0,
5683                    fields: vec![Field {
5684                        name: "ok".to_string(),
5685                        value: Box::new(T::schema(version, context)),
5686                        offset: None,
5687                    }],
5688                },
5689                Variant {
5690                    name: "Err".to_string(),
5691                    discriminant: 0,
5692                    fields: vec![Field {
5693                        name: "err".to_string(),
5694                        value: Box::new(R::schema(version, context)),
5695                        offset: None,
5696                    }],
5697                },
5698            ],
5699            discriminant_size: 1,
5700            has_explicit_repr: false,
5701        })
5702    }
5703}
5704impl<T, R> Packed for Result<T, R> {} //Sadly, Result does not allow the #"reprC"-optimization
5705impl<T: Serialize, R: Serialize> Serialize for Result<T, R> {
5706    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5707        match self {
5708            Ok(x) => {
5709                serializer.write_bool(true)?;
5710                x.serialize(serializer)
5711            }
5712            Err(x) => {
5713                serializer.write_bool(false)?;
5714                x.serialize(serializer)
5715            }
5716        }
5717    }
5718}
5719impl<T: Deserialize, R: Deserialize> Deserialize for Result<T, R> {
5720    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5721        let issome = deserializer.read_bool()?;
5722        if issome {
5723            Ok(Ok(T::deserialize(deserializer)?))
5724        } else {
5725            Ok(Err(R::deserialize(deserializer)?))
5726        }
5727    }
5728}
5729
5730#[cfg(any(feature = "bit-vec", feature = "bit-vec08"))]
5731#[cfg(target_endian = "big")]
5732compile_error!("savefile bit-vec feature does not support big-endian machines");
5733
5734#[cfg(feature = "bit-vec")]
5735impl WithSchema for bit_vec::BitVec {
5736    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5737        Schema::Struct(SchemaStruct {
5738            dbg_name: "BitVec".to_string(),
5739            size: None,
5740            alignment: None,
5741            fields: vec![
5742                Field {
5743                    name: "num_bits".to_string(),
5744                    value: Box::new(usize::schema(version, context)),
5745                    offset: None,
5746                },
5747                Field {
5748                    name: "num_bytes".to_string(),
5749                    value: Box::new(usize::schema(version, context)),
5750                    offset: None,
5751                },
5752                Field {
5753                    name: "buffer".to_string(),
5754                    value: Box::new(Schema::Vector(
5755                        Box::new(u8::schema(version, context)),
5756                        VecOrStringLayout::Unknown,
5757                    )),
5758                    offset: None,
5759                },
5760            ],
5761        })
5762    }
5763}
5764
5765#[cfg(feature = "bit-vec")]
5766impl Introspect for bit_vec::BitVec {
5767    fn introspect_value(&self) -> String {
5768        let mut ret = String::new();
5769        for i in 0..self.len() {
5770            if self[i] {
5771                ret.push('1');
5772            } else {
5773                ret.push('0');
5774            }
5775        }
5776        ret
5777    }
5778
5779    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5780        None
5781    }
5782}
5783
5784#[cfg(feature = "bit-vec")]
5785impl Serialize for bit_vec::BitVec<u32> {
5786    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5787        let l = self.len();
5788        serializer.write_usize(l)?;
5789        let storage = self.storage();
5790        let rawbytes_ptr = storage.as_ptr() as *const u8;
5791        let rawbytes: &[u8] = unsafe { std::slice::from_raw_parts(rawbytes_ptr, 4 * storage.len()) };
5792        serializer.write_usize(rawbytes.len() | (1 << 63))?;
5793        serializer.write_bytes(rawbytes)?;
5794        Ok(())
5795    }
5796}
5797
5798#[cfg(feature = "bit-vec")]
5799impl Packed for bit_vec::BitVec<u32> {}
5800
5801#[cfg(feature = "bit-vec")]
5802impl Deserialize for bit_vec::BitVec<u32> {
5803    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5804        let numbits = deserializer.read_usize()?;
5805        let mut numbytes = deserializer.read_usize()?;
5806        if numbytes & (1 << 63) != 0 {
5807            //New format
5808            numbytes &= !(1 << 63);
5809            let mut ret = bit_vec::BitVec::with_capacity(numbytes * 8);
5810            unsafe {
5811                let num_words = numbytes / 4;
5812                let storage = ret.storage_mut();
5813                storage.resize(num_words, 0);
5814                let storage_ptr = storage.as_ptr() as *mut u8;
5815                let storage_bytes: &mut [u8] = std::slice::from_raw_parts_mut(storage_ptr, 4 * num_words);
5816                deserializer.read_bytes_to_buf(storage_bytes)?;
5817                ret.set_len(numbits);
5818            }
5819            Ok(ret)
5820        } else {
5821            let bytes = deserializer.read_bytes(numbytes)?;
5822            let mut ret = bit_vec::BitVec::from_bytes(&bytes);
5823            ret.truncate(numbits);
5824            Ok(ret)
5825        }
5826    }
5827}
5828
5829#[cfg(feature = "bit-set")]
5830impl WithSchema for bit_set::BitSet {
5831    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5832        Schema::Struct(SchemaStruct {
5833            dbg_name: "BitSet".to_string(),
5834            size: None,
5835            alignment: None,
5836            fields: vec![
5837                Field {
5838                    name: "num_bits".to_string(),
5839                    value: Box::new(usize::schema(version, context)),
5840                    offset: None,
5841                },
5842                Field {
5843                    name: "num_bytes".to_string(),
5844                    value: Box::new(usize::schema(version, context)),
5845                    offset: None,
5846                },
5847                Field {
5848                    name: "buffer".to_string(),
5849                    value: Box::new(Schema::Vector(
5850                        Box::new(u8::schema(version, context)),
5851                        VecOrStringLayout::Unknown,
5852                    )),
5853                    offset: None,
5854                },
5855            ],
5856        })
5857    }
5858}
5859
5860#[cfg(feature = "bit-set")]
5861impl Introspect for bit_set::BitSet {
5862    fn introspect_value(&self) -> String {
5863        let mut ret = String::new();
5864        for i in 0..self.len() {
5865            if self.contains(i) {
5866                use std::fmt::Write;
5867                if !ret.is_empty() {
5868                    ret += " ";
5869                }
5870                write!(&mut ret, "{}", i).unwrap();
5871            }
5872        }
5873        ret
5874    }
5875
5876    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5877        None
5878    }
5879}
5880
5881#[cfg(feature = "bit-set")]
5882impl Packed for bit_set::BitSet<u32> {}
5883
5884#[cfg(feature = "bit-set")]
5885impl Serialize for bit_set::BitSet<u32> {
5886    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5887        let bitset = self.get_ref();
5888        bitset.serialize(serializer)
5889    }
5890}
5891
5892#[cfg(feature = "bit-set")]
5893impl Deserialize for bit_set::BitSet<u32> {
5894    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5895        let bit_vec: bit_vec::BitVec = bit_vec::BitVec::deserialize(deserializer)?;
5896        Ok(bit_set::BitSet::from_bit_vec(bit_vec))
5897    }
5898}
5899
5900#[cfg(feature = "bit-vec08")]
5901impl WithSchema for bit_vec08::BitVec {
5902    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5903        Schema::Struct(SchemaStruct {
5904            dbg_name: "BitVec".to_string(),
5905            size: None,
5906            alignment: None,
5907            fields: vec![
5908                Field {
5909                    name: "num_bits".to_string(),
5910                    value: Box::new(usize::schema(version, context)),
5911                    offset: None,
5912                },
5913                Field {
5914                    name: "num_bytes".to_string(),
5915                    value: Box::new(usize::schema(version, context)),
5916                    offset: None,
5917                },
5918                Field {
5919                    name: "buffer".to_string(),
5920                    value: Box::new(Schema::Vector(
5921                        Box::new(u8::schema(version, context)),
5922                        VecOrStringLayout::Unknown,
5923                    )),
5924                    offset: None,
5925                },
5926            ],
5927        })
5928    }
5929}
5930
5931#[cfg(feature = "bit-vec08")]
5932impl Introspect for bit_vec08::BitVec {
5933    fn introspect_value(&self) -> String {
5934        let mut ret = String::new();
5935        for i in 0..self.len() {
5936            if self[i] {
5937                ret.push('1');
5938            } else {
5939                ret.push('0');
5940            }
5941        }
5942        ret
5943    }
5944
5945    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
5946        None
5947    }
5948}
5949
5950#[cfg(feature = "bit-vec08")]
5951impl Serialize for bit_vec08::BitVec<u32> {
5952    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
5953        let l = self.len();
5954        serializer.write_usize(l)?;
5955        let storage = self.storage();
5956        let rawbytes_ptr = storage.as_ptr() as *const u8;
5957        let rawbytes: &[u8] = unsafe { std::slice::from_raw_parts(rawbytes_ptr, 4 * storage.len()) };
5958        serializer.write_usize(rawbytes.len() | (1 << 63))?;
5959        serializer.write_bytes(rawbytes)?;
5960        Ok(())
5961    }
5962}
5963
5964#[cfg(feature = "bit-vec08")]
5965impl Packed for bit_vec08::BitVec<u32> {}
5966
5967#[cfg(feature = "bit-vec08")]
5968impl Deserialize for bit_vec08::BitVec<u32> {
5969    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
5970        let numbits = deserializer.read_usize()?;
5971        let mut numbytes = deserializer.read_usize()?;
5972        if numbytes & (1 << 63) != 0 {
5973            //New format
5974            numbytes &= !(1 << 63);
5975            let mut ret = bit_vec08::BitVec::with_capacity(numbytes * 8);
5976            unsafe {
5977                let num_words = numbytes / 4;
5978                let storage = ret.storage_mut();
5979                storage.resize(num_words, 0);
5980                let storage_ptr = storage.as_ptr() as *mut u8;
5981                let storage_bytes: &mut [u8] = std::slice::from_raw_parts_mut(storage_ptr, 4 * num_words);
5982                deserializer.read_bytes_to_buf(storage_bytes)?;
5983                ret.set_len(numbits);
5984            }
5985            Ok(ret)
5986        } else {
5987            let bytes = deserializer.read_bytes(numbytes)?;
5988            let mut ret = bit_vec08::BitVec::from_bytes(&bytes);
5989            ret.truncate(numbits);
5990            Ok(ret)
5991        }
5992    }
5993}
5994
5995#[cfg(feature = "bit-set")]
5996impl WithSchema for bit_set08::BitSet {
5997    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
5998        Schema::Struct(SchemaStruct {
5999            dbg_name: "BitSet".to_string(),
6000            size: None,
6001            alignment: None,
6002            fields: vec![
6003                Field {
6004                    name: "num_bits".to_string(),
6005                    value: Box::new(usize::schema(version, context)),
6006                    offset: None,
6007                },
6008                Field {
6009                    name: "num_bytes".to_string(),
6010                    value: Box::new(usize::schema(version, context)),
6011                    offset: None,
6012                },
6013                Field {
6014                    name: "buffer".to_string(),
6015                    value: Box::new(Schema::Vector(
6016                        Box::new(u8::schema(version, context)),
6017                        VecOrStringLayout::Unknown,
6018                    )),
6019                    offset: None,
6020                },
6021            ],
6022        })
6023    }
6024}
6025
6026#[cfg(feature = "bit-set08")]
6027impl Introspect for bit_set08::BitSet {
6028    fn introspect_value(&self) -> String {
6029        let mut ret = String::new();
6030        for i in 0..self.len() {
6031            if self.contains(i) {
6032                use std::fmt::Write;
6033                if !ret.is_empty() {
6034                    ret += " ";
6035                }
6036                write!(&mut ret, "{}", i).unwrap();
6037            }
6038        }
6039        ret
6040    }
6041
6042    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
6043        None
6044    }
6045}
6046
6047#[cfg(feature = "bit-set08")]
6048impl Packed for bit_set08::BitSet<u32> {}
6049
6050#[cfg(feature = "bit-set08")]
6051impl Serialize for bit_set08::BitSet<u32> {
6052    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6053        let bitset = self.get_ref();
6054        bitset.serialize(serializer)
6055    }
6056}
6057
6058#[cfg(feature = "bit-set")]
6059impl Deserialize for bit_set08::BitSet<u32> {
6060    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6061        let bit_vec: bit_vec08::BitVec = bit_vec08::BitVec::deserialize(deserializer)?;
6062        Ok(bit_set08::BitSet::from_bit_vec(bit_vec))
6063    }
6064}
6065
6066impl<T: Introspect> Introspect for BinaryHeap<T> {
6067    fn introspect_value(&self) -> String {
6068        "BinaryHeap".to_string()
6069    }
6070
6071    fn introspect_child<'a>(&'a self, index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
6072        if index >= self.len() {
6073            return None;
6074        }
6075        return Some(introspect_item(index.to_string(), self.iter().nth(index).unwrap()));
6076    }
6077
6078    fn introspect_len(&self) -> usize {
6079        self.len()
6080    }
6081}
6082
6083impl<T> Packed for BinaryHeap<T> {}
6084impl<T: WithSchema + 'static> WithSchema for BinaryHeap<T> {
6085    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6086        Schema::Vector(
6087            Box::new(context.possible_recursion::<T>(|context| T::schema(version, context))),
6088            VecOrStringLayout::Unknown,
6089        )
6090    }
6091}
6092impl<T: Serialize + Ord + 'static> Serialize for BinaryHeap<T> {
6093    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6094        let l = self.len();
6095        serializer.write_usize(l)?;
6096        for item in self.iter() {
6097            item.serialize(serializer)?
6098        }
6099        Ok(())
6100    }
6101}
6102impl<T: Deserialize + Ord + 'static> Deserialize for BinaryHeap<T> {
6103    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6104        let l = deserializer.read_usize()?;
6105        let mut ret = BinaryHeap::with_capacity(l);
6106        for _ in 0..l {
6107            ret.push(T::deserialize(deserializer)?);
6108        }
6109        Ok(ret)
6110    }
6111}
6112
6113#[cfg(feature = "smallvec")]
6114impl<T: smallvec::Array> Introspect for smallvec::SmallVec<T>
6115where
6116    T::Item: Introspect,
6117{
6118    fn introspect_value(&self) -> String {
6119        format!("SmallVec<{}>", std::any::type_name::<T>())
6120    }
6121
6122    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
6123        if let Some(val) = self.get(index) {
6124            Some(introspect_item(index.to_string(), val))
6125        } else {
6126            None
6127        }
6128    }
6129
6130    fn introspect_len(&self) -> usize {
6131        self.len()
6132    }
6133}
6134
6135#[cfg(feature = "smallvec")]
6136impl<T: smallvec::Array + 'static> WithSchema for smallvec::SmallVec<T>
6137where
6138    T::Item: WithSchema,
6139{
6140    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6141        Schema::Vector(
6142            Box::new(context.possible_recursion::<T>(|context| T::Item::schema(version, context))),
6143            VecOrStringLayout::Unknown,
6144        )
6145    }
6146}
6147#[cfg(feature = "smallvec")]
6148impl<T: smallvec::Array> Packed for smallvec::SmallVec<T> {}
6149
6150#[cfg(feature = "smallvec")]
6151impl<T: smallvec::Array + 'static> Serialize for smallvec::SmallVec<T>
6152where
6153    T::Item: Serialize,
6154{
6155    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6156        let l = self.len();
6157        serializer.write_usize(l)?;
6158        for item in self.iter() {
6159            item.serialize(serializer)?
6160        }
6161        Ok(())
6162    }
6163}
6164#[cfg(feature = "smallvec")]
6165impl<T: smallvec::Array + 'static> Deserialize for smallvec::SmallVec<T>
6166where
6167    T::Item: Deserialize,
6168{
6169    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6170        let l = deserializer.read_usize()?;
6171        let mut ret = Self::with_capacity(l);
6172        for _ in 0..l {
6173            ret.push(T::Item::deserialize(deserializer)?);
6174        }
6175        Ok(ret)
6176    }
6177}
6178
6179fn regular_serialize_vec<T: Serialize>(
6180    items: &[T],
6181    serializer: &mut Serializer<impl Write>,
6182) -> Result<(), SavefileError> {
6183    let l = items.len();
6184    serializer.write_usize(l)?;
6185    if std::mem::size_of::<T>() == 0 {
6186        return Ok(());
6187    }
6188
6189    if std::mem::size_of::<T>() < 32 {
6190        //<-- This optimization seems to help a little actually, but maybe not enough to warrant it
6191        let chunks = items.chunks_exact((64 / std::mem::size_of::<T>()).max(1));
6192        let remainder = chunks.remainder();
6193        for chunk in chunks {
6194            for item in chunk {
6195                item.serialize(serializer)?;
6196            }
6197        }
6198        for item in remainder {
6199            item.serialize(serializer)?;
6200        }
6201        Ok(())
6202    } else {
6203        for item in items {
6204            item.serialize(serializer)?;
6205        }
6206        Ok(())
6207    }
6208}
6209
6210impl<T: WithSchema + 'static> WithSchema for Box<[T]> {
6211    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6212        Schema::Vector(
6213            Box::new(context.possible_recursion::<T>(|context| T::schema(version, context))),
6214            VecOrStringLayout::Unknown,
6215        )
6216    }
6217}
6218impl<T: WithSchema + 'static> WithSchema for Arc<[T]> {
6219    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6220        Schema::Vector(
6221            Box::new(context.possible_recursion::<T>(|context| T::schema(version, context))),
6222            VecOrStringLayout::Unknown,
6223        )
6224    }
6225}
6226impl<T: Introspect> Introspect for Box<[T]> {
6227    fn introspect_value(&self) -> String {
6228        return "Box[]".to_string();
6229    }
6230
6231    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
6232        if index >= self.len() {
6233            return None;
6234        }
6235        return Some(introspect_item(index.to_string(), &self[index]));
6236    }
6237    fn introspect_len(&self) -> usize {
6238        self.len()
6239    }
6240}
6241
6242impl<T: Introspect> Introspect for Arc<[T]> {
6243    fn introspect_value(&self) -> String {
6244        return "Arc[]".to_string();
6245    }
6246
6247    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
6248        if index >= self.len() {
6249            return None;
6250        }
6251        return Some(introspect_item(index.to_string(), &self[index]));
6252    }
6253    fn introspect_len(&self) -> usize {
6254        self.len()
6255    }
6256}
6257
6258impl WithSchema for Arc<str> {
6259    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
6260        Schema::Primitive(SchemaPrimitive::schema_string(VecOrStringLayout::Unknown))
6261    }
6262}
6263impl Introspect for Arc<str> {
6264    fn introspect_value(&self) -> String {
6265        self.deref().to_string()
6266    }
6267
6268    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_>>> {
6269        None
6270    }
6271    fn introspect_len(&self) -> usize {
6272        0
6273    }
6274}
6275impl Serialize for Arc<str> {
6276    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6277        serializer.write_string(self)
6278    }
6279}
6280
6281impl Packed for Arc<str> {}
6282
6283impl Deserialize for Arc<str> {
6284    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6285        let s = deserializer.read_string()?;
6286
6287        let state = deserializer.get_state::<Arc<str>, HashMap<String, Arc<str>>>();
6288
6289        if let Some(needle) = state.get(&s) {
6290            return Ok(Arc::clone(needle));
6291        }
6292
6293        let arc_ref = state.entry(s.clone()).or_insert(s.into());
6294        Ok(Arc::clone(arc_ref))
6295    }
6296}
6297
6298impl<T: Serialize + Packed + 'static> Serialize for Box<[T]> {
6299    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6300        unsafe {
6301            if T::repr_c_optimization_safe(serializer.file_version).is_false() {
6302                regular_serialize_vec(self, serializer)
6303            } else {
6304                let l = self.len();
6305                serializer.write_usize(l)?;
6306                serializer.write_buf(std::slice::from_raw_parts(
6307                    (*self).as_ptr() as *const u8,
6308                    std::mem::size_of::<T>() * l,
6309                ))
6310            }
6311        }
6312    }
6313}
6314impl<T: Packed> Packed for Box<[T]> {}
6315
6316impl<T: Serialize + Packed + 'static> Serialize for Arc<[T]> {
6317    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6318        unsafe {
6319            if T::repr_c_optimization_safe(serializer.file_version).is_false() {
6320                regular_serialize_vec(self, serializer)
6321            } else {
6322                let l = self.len();
6323                serializer.write_usize(l)?;
6324                serializer.write_buf(std::slice::from_raw_parts(
6325                    (*self).as_ptr() as *const u8,
6326                    std::mem::size_of::<T>() * l,
6327                ))
6328            }
6329        }
6330    }
6331}
6332impl<T: Packed> Packed for Arc<[T]> {}
6333
6334impl<T: Deserialize + Packed + 'static> Deserialize for Arc<[T]> {
6335    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6336        Ok(Vec::<T>::deserialize(deserializer)?.into())
6337    }
6338}
6339impl<T: Deserialize + Packed + 'static> Deserialize for Box<[T]> {
6340    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6341        Ok(Vec::<T>::deserialize(deserializer)?.into_boxed_slice())
6342    }
6343}
6344impl WithSchema for &'_ str {
6345    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
6346        Schema::Primitive(SchemaPrimitive::schema_string(calculate_string_memory_layout()))
6347        //TODO: This is _not_ the same memory layout as vec. Make a new Box type for slices?
6348    }
6349}
6350impl Serialize for &'_ str {
6351    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6352        let l = self.len();
6353        serializer.write_usize(l)?;
6354        serializer.write_buf(self.as_bytes())
6355    }
6356}
6357
6358impl<T: WithSchema + 'static> WithSchema for &'_ [T] {
6359    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6360        Schema::Vector(
6361            Box::new(context.possible_recursion::<T>(|context| T::schema(version, context))),
6362            calculate_slice_memory_layout::<T>(),
6363        )
6364        //TODO: This is _not_ the same memory layout as vec. Make a new Box type for slices?
6365    }
6366}
6367impl<T: Serialize + Packed + 'static> Serialize for &'_ [T] {
6368    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6369        unsafe {
6370            if T::repr_c_optimization_safe(serializer.file_version).is_false() {
6371                regular_serialize_vec(self, serializer)
6372            } else {
6373                let l = self.len();
6374                serializer.write_usize(l)?;
6375                #[allow(clippy::manual_slice_size_calculation)] // I feel this way is clearer
6376                serializer.write_buf(std::slice::from_raw_parts(
6377                    self.as_ptr() as *const u8,
6378                    std::mem::size_of::<T>() * l,
6379                ))
6380            }
6381        }
6382    }
6383}
6384
6385/// Deserialize a slice into a Vec
6386/// Unsized slices cannot be deserialized into unsized slices.
6387pub fn deserialize_slice_as_vec<R: Read, T: Deserialize + Packed + 'static>(
6388    deserializer: &mut Deserializer<R>,
6389) -> Result<Vec<T>, SavefileError> {
6390    Vec::deserialize(deserializer)
6391}
6392
6393impl<T> Packed for Vec<T> {}
6394
6395/// 0 = Uninitialized
6396static STRING_IS_STANDARD_LAYOUT: AtomicU8 = AtomicU8::new(255);
6397#[derive(Debug)]
6398#[repr(C)]
6399struct RawVecInspector {
6400    p1: usize,
6401    p2: usize,
6402    p3: usize,
6403}
6404#[derive(Debug)]
6405#[repr(C)]
6406struct RawSliceInspector {
6407    p1: usize,
6408    p2: usize,
6409}
6410impl RawSliceInspector {
6411    const fn get_layout(&self) -> VecOrStringLayout {
6412        if self.p1 == 0 {
6413            VecOrStringLayout::LengthData
6414        } else {
6415            VecOrStringLayout::DataLength
6416        }
6417    }
6418}
6419impl RawVecInspector {
6420    fn get_layout(&self, ptr: *const u8) -> VecOrStringLayout {
6421        let ptr = ptr as usize;
6422        // We know size is 1, and capacity is 2.
6423        const LENGTH: usize = 0;
6424        const CAPACITY: usize = 7;
6425        match (self.p1, self.p2, self.p3) {
6426            (LENGTH, CAPACITY, x) if x == ptr => VecOrStringLayout::LengthCapacityData,
6427            (CAPACITY, LENGTH, x) if x == ptr => VecOrStringLayout::CapacityLengthData,
6428            (LENGTH, x, CAPACITY) if x == ptr => VecOrStringLayout::LengthDataCapacity,
6429            (CAPACITY, x, LENGTH) if x == ptr => VecOrStringLayout::CapacityDataLength,
6430            (x, LENGTH, CAPACITY) if x == ptr => VecOrStringLayout::DataLengthCapacity,
6431            (x, CAPACITY, LENGTH) if x == ptr => VecOrStringLayout::DataCapacityLength,
6432            _ => VecOrStringLayout::Unknown,
6433        }
6434    }
6435}
6436
6437/// Calculate the memory layout of `&[T]`.
6438///
6439/// I.e, of the reference to the data.
6440/// This type is typically 16 bytes, consisting of two words, one being the length,
6441/// the other being a pointer to the start of the data.
6442pub const fn calculate_slice_memory_layout<T>() -> VecOrStringLayout {
6443    if std::mem::size_of::<&[T]>() != 16 || std::mem::size_of::<RawSliceInspector>() != 16 {
6444        VecOrStringLayout::Unknown
6445    } else {
6446        let test_slice: &[T] = &[];
6447        let insp: RawSliceInspector = unsafe { std::mem::transmute_copy::<&[T], RawSliceInspector>(&test_slice) };
6448        insp.get_layout()
6449    }
6450}
6451/// Calculate the memory layout of a Vec of the given type
6452pub fn calculate_vec_memory_layout<T>() -> VecOrStringLayout {
6453    if std::mem::size_of::<Vec<u8>>() != 24 || std::mem::size_of::<RawVecInspector>() != 24 {
6454        VecOrStringLayout::Unknown
6455    } else {
6456        let test_vec = Vec::with_capacity(7);
6457        let insp: RawVecInspector = unsafe { std::mem::transmute_copy(&test_vec) };
6458        let ptr = test_vec.as_ptr();
6459        insp.get_layout(ptr)
6460    }
6461}
6462fn calculate_string_memory_layout() -> VecOrStringLayout {
6463    let mut is_std = STRING_IS_STANDARD_LAYOUT.load(Ordering::Relaxed);
6464    if is_std != 255 {
6465        // SAFETY
6466        // We 'is_std' is always initialized using a valid VecOrStringLayout enum value,
6467        // unless it's 255.
6468        return unsafe { std::mem::transmute::<u8, VecOrStringLayout>(is_std) };
6469    }
6470    if std::mem::size_of::<String>() != 24 || std::mem::size_of::<RawVecInspector>() != 24 {
6471        is_std = VecOrStringLayout::Unknown as u8;
6472    } else {
6473        let test_string = String::with_capacity(7);
6474        let insp: RawVecInspector = unsafe { std::mem::transmute_copy(&test_string) };
6475        let ptr = test_string.as_ptr();
6476
6477        is_std = insp.get_layout(ptr) as u8;
6478
6479        drop(test_string);
6480    }
6481
6482    STRING_IS_STANDARD_LAYOUT.store(is_std, Ordering::Relaxed);
6483    return unsafe { std::mem::transmute::<u8, VecOrStringLayout>(is_std) };
6484}
6485impl<T: WithSchema + 'static> WithSchema for Vec<T> {
6486    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6487        Schema::Vector(
6488            Box::new(context.possible_recursion::<T>(|context| T::schema(version, context))),
6489            calculate_vec_memory_layout::<T>(),
6490        )
6491    }
6492}
6493
6494impl<T: Introspect> Introspect for Vec<T> {
6495    fn introspect_value(&self) -> String {
6496        return "vec[]".to_string();
6497    }
6498
6499    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
6500        if index >= self.len() {
6501            return None;
6502        }
6503        return Some(introspect_item(index.to_string(), &self[index]));
6504    }
6505    fn introspect_len(&self) -> usize {
6506        self.len()
6507    }
6508}
6509
6510impl<T: Serialize + Packed + 'static> Serialize for Vec<T> {
6511    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6512        unsafe {
6513            if T::repr_c_optimization_safe(serializer.file_version).is_false() {
6514                regular_serialize_vec(self, serializer)
6515            } else {
6516                let l = self.len();
6517                serializer.write_usize(l)?;
6518                serializer.write_buf(std::slice::from_raw_parts(
6519                    self.as_ptr() as *const u8,
6520                    std::mem::size_of::<T>() * l,
6521                ))
6522            }
6523        }
6524    }
6525}
6526
6527fn regular_deserialize_vec<T: Deserialize>(
6528    deserializer: &mut Deserializer<impl Read>,
6529) -> Result<Vec<T>, SavefileError> {
6530    let l = deserializer.read_usize()?;
6531
6532    #[cfg(feature = "size_sanity_checks")]
6533    {
6534        if l > 1_000_000 {
6535            return Err(SavefileError::GeneralError {
6536                msg: format!("Too many items in Vec: {}", l),
6537            });
6538        }
6539    }
6540    let mut ret = Vec::with_capacity(l);
6541    for _ in 0..l {
6542        ret.push(T::deserialize(deserializer)?);
6543    }
6544    Ok(ret)
6545}
6546
6547impl<T: Deserialize + Packed + 'static> Deserialize for Vec<T> {
6548    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6549        if unsafe { T::repr_c_optimization_safe(deserializer.file_version) }.is_false() {
6550            Ok(regular_deserialize_vec(deserializer)?)
6551        } else {
6552            use std::mem;
6553
6554            let align = mem::align_of::<T>();
6555            let elem_size = mem::size_of::<T>();
6556            let num_elems = deserializer.read_usize()?;
6557
6558            if num_elems == 0 {
6559                return Ok(Vec::new());
6560            }
6561            let num_bytes = elem_size * num_elems;
6562
6563            let layout = if let Ok(layout) = std::alloc::Layout::from_size_align(num_bytes, align) {
6564                Ok(layout)
6565            } else {
6566                Err(SavefileError::MemoryAllocationLayoutError)
6567            }?;
6568            let ptr = if elem_size == 0 {
6569                NonNull::dangling().as_ptr()
6570            } else {
6571                let ptr = unsafe { std::alloc::alloc(layout) };
6572                if ptr.is_null() {
6573                    panic!("Failed to allocate {} bytes of memory", num_bytes);
6574                }
6575
6576                ptr
6577            };
6578
6579            {
6580                let slice = unsafe { std::slice::from_raw_parts_mut(ptr, num_bytes) };
6581                match deserializer.reader.read_exact(slice) {
6582                    Ok(()) => Ok(()),
6583                    Err(err) => {
6584                        unsafe {
6585                            std::alloc::dealloc(ptr, layout);
6586                        }
6587                        Err(err)
6588                    }
6589                }?;
6590            }
6591            let ret = unsafe { Vec::from_raw_parts(ptr as *mut T, num_elems, num_elems) };
6592            Ok(ret)
6593        }
6594    }
6595}
6596
6597impl<T: Introspect> Introspect for VecDeque<T> {
6598    fn introspect_value(&self) -> String {
6599        format!("VecDeque<{}>", std::any::type_name::<T>())
6600    }
6601
6602    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
6603        if let Some(val) = self.get(index) {
6604            Some(introspect_item(index.to_string(), val))
6605        } else {
6606            None
6607        }
6608    }
6609
6610    fn introspect_len(&self) -> usize {
6611        self.len()
6612    }
6613}
6614
6615impl<T: WithSchema + 'static> WithSchema for VecDeque<T> {
6616    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6617        Schema::Vector(
6618            Box::new(context.possible_recursion::<T>(|context| T::schema(version, context))),
6619            VecOrStringLayout::Unknown,
6620        )
6621    }
6622}
6623
6624impl<T> Packed for VecDeque<T> {}
6625impl<T: Serialize + 'static> Serialize for VecDeque<T> {
6626    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6627        regular_serialize_vecdeque(self, serializer)
6628    }
6629}
6630
6631impl<T: Deserialize + 'static> Deserialize for VecDeque<T> {
6632    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6633        Ok(regular_deserialize_vecdeque(deserializer)?)
6634    }
6635}
6636
6637fn regular_serialize_vecdeque<T: Serialize>(
6638    item: &VecDeque<T>,
6639    serializer: &mut Serializer<impl Write>,
6640) -> Result<(), SavefileError> {
6641    let l = item.len();
6642    serializer.write_usize(l)?;
6643    for item in item.iter() {
6644        item.serialize(serializer)?
6645    }
6646    Ok(())
6647}
6648
6649fn regular_deserialize_vecdeque<T: Deserialize>(
6650    deserializer: &mut Deserializer<impl Read>,
6651) -> Result<VecDeque<T>, SavefileError> {
6652    let l = deserializer.read_usize()?;
6653    let mut ret = VecDeque::with_capacity(l);
6654    for _ in 0..l {
6655        ret.push_back(T::deserialize(deserializer)?);
6656    }
6657    Ok(ret)
6658}
6659
6660impl Packed for bool {
6661    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6662        IsPacked::yes()
6663    }
6664} //It isn't really guaranteed that bool is an u8 or i8 where false = 0 and true = 1. But it's true in practice. And the breakage would be hard to measure if this were ever changed, so a change is unlikely.
6665impl Packed for u8 {
6666    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6667        IsPacked::yes()
6668    }
6669}
6670impl Packed for i8 {
6671    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6672        IsPacked::yes()
6673    }
6674}
6675impl Packed for u16 {
6676    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6677        IsPacked::yes()
6678    }
6679}
6680impl Packed for i16 {
6681    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6682        IsPacked::yes()
6683    }
6684}
6685impl Packed for u32 {
6686    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6687        IsPacked::yes()
6688    }
6689}
6690impl Packed for i32 {
6691    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6692        IsPacked::yes()
6693    }
6694}
6695impl Packed for u64 {
6696    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6697        IsPacked::yes()
6698    }
6699}
6700impl Packed for u128 {
6701    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6702        IsPacked::yes()
6703    }
6704}
6705impl Packed for i128 {
6706    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6707        IsPacked::yes()
6708    }
6709}
6710impl Packed for i64 {
6711    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6712        IsPacked::yes()
6713    }
6714}
6715impl Packed for char {
6716    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6717        IsPacked::yes()
6718    }
6719}
6720impl Packed for f32 {
6721    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6722        IsPacked::yes()
6723    }
6724}
6725impl Packed for f64 {
6726    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6727        IsPacked::yes()
6728    }
6729}
6730impl Packed for usize {
6731    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6732        IsPacked::no()
6733    } // Doesn't have a fixed size
6734}
6735impl Packed for isize {
6736    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6737        IsPacked::no()
6738    } // Doesn't have a fixed size
6739}
6740impl Packed for () {
6741    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
6742        IsPacked::yes()
6743    }
6744}
6745
6746impl<T: WithSchema + 'static, const N: usize> WithSchema for [T; N] {
6747    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6748        Schema::Array(SchemaArray {
6749            item_type: Box::new(context.possible_recursion::<T>(|context| T::schema(version, context))),
6750            count: N,
6751        })
6752    }
6753}
6754
6755impl<T: Introspect, const N: usize> Introspect for [T; N] {
6756    fn introspect_value(&self) -> String {
6757        format!("[{}; {}]", std::any::type_name::<T>(), N)
6758    }
6759
6760    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
6761        if index >= self.len() {
6762            None
6763        } else {
6764            Some(introspect_item(index.to_string(), &self[index]))
6765        }
6766    }
6767}
6768
6769impl<T: Packed, const N: usize> Packed for [T; N] {
6770    unsafe fn repr_c_optimization_safe(version: u32) -> IsPacked {
6771        T::repr_c_optimization_safe(version)
6772    }
6773}
6774impl<T: Serialize + Packed + 'static, const N: usize> Serialize for [T; N] {
6775    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6776        if N == 0 {
6777            return Ok(());
6778        }
6779        unsafe {
6780            if T::repr_c_optimization_safe(serializer.file_version).is_false() {
6781                for item in self.iter() {
6782                    item.serialize(serializer)?
6783                }
6784                Ok(())
6785            } else {
6786                serializer.write_buf(std::slice::from_raw_parts(
6787                    self.as_ptr() as *const u8,
6788                    std::mem::size_of::<T>() * N,
6789                ))
6790            }
6791        }
6792    }
6793}
6794
6795impl<T: Deserialize + Packed + 'static, const N: usize> Deserialize for [T; N] {
6796    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6797        if N == 0 {
6798            return Ok([(); N].map(|_| unreachable!()));
6799        }
6800
6801        if unsafe { T::repr_c_optimization_safe(deserializer.file_version) }.is_false() {
6802            let mut data: [MaybeUninit<T>; N] = unsafe {
6803                MaybeUninit::uninit().assume_init() //This seems strange, but is correct according to rust docs: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html, see chapter 'Initializing an array element-by-element'
6804            };
6805            for idx in 0..N {
6806                data[idx] = MaybeUninit::new(T::deserialize(deserializer)?); //This leaks on panic, but we shouldn't panic and at least it isn't UB!
6807            }
6808            let ptr = &mut data as *mut _ as *mut [T; N];
6809            let res = unsafe { ptr.read() };
6810            Ok(res)
6811        } else {
6812            let mut data: [MaybeUninit<T>; N] = unsafe {
6813                MaybeUninit::uninit().assume_init() //This seems strange, but is correct according to rust docs: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html, see chapter 'Initializing an array element-by-element'
6814            };
6815
6816            {
6817                let ptr = data.as_mut_ptr();
6818                let num_bytes: usize = std::mem::size_of::<T>() * N;
6819                let slice: &mut [MaybeUninit<u8>] =
6820                    unsafe { std::slice::from_raw_parts_mut(ptr as *mut MaybeUninit<u8>, num_bytes) };
6821                deserializer
6822                    .reader
6823                    .read_exact(unsafe { std::mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(slice) })?;
6824            }
6825            let ptr = &mut data as *mut _ as *mut [T; N];
6826            let res = unsafe { ptr.read() };
6827            Ok(res)
6828        }
6829    }
6830}
6831
6832impl<T1> Packed for Range<T1> {}
6833impl<T1: WithSchema> WithSchema for Range<T1> {
6834    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6835        Schema::new_tuple2::<T1, T1>(version, context)
6836    }
6837}
6838impl<T1: Serialize> Serialize for Range<T1> {
6839    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6840        self.start.serialize(serializer)?;
6841        self.end.serialize(serializer)?;
6842        Ok(())
6843    }
6844}
6845impl<T1: Deserialize> Deserialize for Range<T1> {
6846    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6847        Ok(T1::deserialize(deserializer)?..T1::deserialize(deserializer)?)
6848    }
6849}
6850impl<T1: Introspect> Introspect for Range<T1> {
6851    fn introspect_value(&self) -> String {
6852        return "Range".to_string();
6853    }
6854
6855    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
6856        if index == 0 {
6857            return Some(introspect_item("start".to_string(), &self.start));
6858        }
6859        if index == 1 {
6860            return Some(introspect_item("end".to_string(), &self.end));
6861        }
6862        return None;
6863    }
6864}
6865
6866impl<T1: Packed> Packed for (T1,) {
6867    unsafe fn repr_c_optimization_safe(version: u32) -> IsPacked {
6868        if offset_of_tuple!((T1,), 0) == 0 && std::mem::size_of::<T1>() == std::mem::size_of::<(T1,)>() {
6869            T1::repr_c_optimization_safe(version)
6870        } else {
6871            IsPacked::no()
6872        }
6873    }
6874}
6875impl<T1: Packed, T2: Packed> Packed for (T1, T2) {
6876    unsafe fn repr_c_optimization_safe(version: u32) -> IsPacked {
6877        if offset_of_tuple!((T1, T2), 0) == 0
6878            && std::mem::size_of::<T1>() + std::mem::size_of::<T2>() == std::mem::size_of::<(T1, T2)>()
6879        {
6880            T1::repr_c_optimization_safe(version) & T2::repr_c_optimization_safe(version)
6881        } else {
6882            IsPacked::no()
6883        }
6884    }
6885}
6886impl<T1: Packed, T2: Packed, T3: Packed> Packed for (T1, T2, T3) {
6887    unsafe fn repr_c_optimization_safe(version: u32) -> IsPacked {
6888        if offset_of_tuple!((T1, T2, T3), 0) == 0
6889            && offset_of_tuple!((T1, T2, T3), 1) == std::mem::size_of::<T1>()
6890            && std::mem::size_of::<T1>() + std::mem::size_of::<T2>() + std::mem::size_of::<T3>()
6891                == std::mem::size_of::<(T1, T2, T3)>()
6892        {
6893            T1::repr_c_optimization_safe(version)
6894                & T2::repr_c_optimization_safe(version)
6895                & T3::repr_c_optimization_safe(version)
6896        } else {
6897            IsPacked::no()
6898        }
6899    }
6900}
6901impl<T1: Packed, T2: Packed, T3: Packed, T4: Packed> Packed for (T1, T2, T3, T4) {
6902    unsafe fn repr_c_optimization_safe(version: u32) -> IsPacked {
6903        if offset_of_tuple!((T1, T2, T3, T4), 0) == 0
6904            && offset_of_tuple!((T1, T2, T3, T4), 1) == std::mem::size_of::<T1>()
6905            && offset_of_tuple!((T1, T2, T3, T4), 2) == std::mem::size_of::<T1>() + std::mem::size_of::<T2>()
6906            && std::mem::size_of::<T1>()
6907                + std::mem::size_of::<T2>()
6908                + std::mem::size_of::<T3>()
6909                + std::mem::size_of::<T4>()
6910                == std::mem::size_of::<(T1, T2, T3, T4)>()
6911        {
6912            T1::repr_c_optimization_safe(version)
6913                & T2::repr_c_optimization_safe(version)
6914                & T3::repr_c_optimization_safe(version)
6915                & T4::repr_c_optimization_safe(version)
6916        } else {
6917            IsPacked::no()
6918        }
6919    }
6920}
6921
6922impl<T1: WithSchema, T2: WithSchema, T3: WithSchema> WithSchema for (T1, T2, T3) {
6923    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6924        Schema::new_tuple3::<T1, T2, T3>(version, context)
6925    }
6926}
6927impl<T1: Serialize, T2: Serialize, T3: Serialize> Serialize for (T1, T2, T3) {
6928    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6929        self.0.serialize(serializer)?;
6930        self.1.serialize(serializer)?;
6931        self.2.serialize(serializer)
6932    }
6933}
6934impl<T1: Deserialize, T2: Deserialize, T3: Deserialize> Deserialize for (T1, T2, T3) {
6935    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6936        Ok((
6937            T1::deserialize(deserializer)?,
6938            T2::deserialize(deserializer)?,
6939            T3::deserialize(deserializer)?,
6940        ))
6941    }
6942}
6943
6944impl<T1: WithSchema, T2: WithSchema> WithSchema for (T1, T2) {
6945    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6946        Schema::new_tuple2::<T1, T2>(version, context)
6947    }
6948}
6949impl<T1: Serialize, T2: Serialize> Serialize for (T1, T2) {
6950    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6951        self.0.serialize(serializer)?;
6952        self.1.serialize(serializer)
6953    }
6954}
6955impl<T1: Deserialize, T2: Deserialize> Deserialize for (T1, T2) {
6956    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6957        Ok((T1::deserialize(deserializer)?, T2::deserialize(deserializer)?))
6958    }
6959}
6960
6961impl<T1: WithSchema> WithSchema for (T1,) {
6962    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
6963        Schema::new_tuple1::<T1>(version, context)
6964    }
6965}
6966impl<T1: Serialize> Serialize for (T1,) {
6967    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
6968        self.0.serialize(serializer)
6969    }
6970}
6971impl<T1: Deserialize> Deserialize for (T1,) {
6972    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
6973        Ok((T1::deserialize(deserializer)?,))
6974    }
6975}
6976
6977#[cfg(feature = "nalgebra")]
6978impl<T: nalgebra::Scalar> Introspect for nalgebra::Point3<T> {
6979    fn introspect_value(&self) -> String {
6980        format!("{:?}", self)
6981    }
6982
6983    fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
6984        None
6985    }
6986}
6987#[cfg(feature = "nalgebra")]
6988impl<T: nalgebra::Scalar> Introspect for nalgebra::Vector3<T> {
6989    fn introspect_value(&self) -> String {
6990        format!("{:?}", self)
6991    }
6992
6993    fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
6994        None
6995    }
6996}
6997#[cfg(feature = "nalgebra")]
6998impl<T: nalgebra::Scalar> Introspect for nalgebra::Isometry3<T> {
6999    fn introspect_value(&self) -> String {
7000        format!("{:?}", self)
7001    }
7002
7003    fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
7004        None
7005    }
7006}
7007#[cfg(feature = "nalgebra")]
7008impl<T: Packed + nalgebra::Scalar + Default> Packed for nalgebra::Point3<T> {
7009    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
7010        let d = nalgebra::Point3::<T>::new(T::default(), T::default(), T::default());
7011        let p1 = &d.x as *const T;
7012        let p2 = &d.y as *const T;
7013        let p3 = &d.z as *const T;
7014
7015        if std::mem::size_of::<nalgebra::Point3<T>>() == 3 * std::mem::size_of::<T>()
7016            && p1.offset(1) == p2
7017            && p1.offset(2) == p3
7018        {
7019            IsPacked::yes()
7020        } else {
7021            IsPacked::no()
7022        }
7023    }
7024}
7025#[cfg(feature = "nalgebra")]
7026impl<T: WithSchema + nalgebra::Scalar> WithSchema for nalgebra::Point3<T> {
7027    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
7028        Schema::Array(SchemaArray {
7029            item_type: Box::new(T::schema(version, context)),
7030            count: 3,
7031        })
7032    }
7033}
7034#[cfg(feature = "nalgebra")]
7035impl<T: Serialize + Packed + WithSchema + nalgebra::Scalar> Serialize for nalgebra::Point3<T> {
7036    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7037        self.coords.x.serialize(serializer)?;
7038        self.coords.y.serialize(serializer)?;
7039        self.coords.z.serialize(serializer)?;
7040
7041        Ok(())
7042    }
7043}
7044#[cfg(feature = "nalgebra")]
7045impl<T: Deserialize + Packed + WithSchema + nalgebra::Scalar + nalgebra::SimdValue + nalgebra::RealField> Deserialize
7046    for nalgebra::Point3<T>
7047{
7048    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7049        Ok(nalgebra::Point3::new(
7050            <T as Deserialize>::deserialize(deserializer)?,
7051            <T as Deserialize>::deserialize(deserializer)?,
7052            <T as Deserialize>::deserialize(deserializer)?,
7053        ))
7054    }
7055}
7056
7057#[cfg(feature = "nalgebra")]
7058impl<T: Packed + nalgebra::Scalar + Default> Packed for nalgebra::Vector3<T> {
7059    unsafe fn repr_c_optimization_safe(_version: u32) -> IsPacked {
7060        let d = nalgebra::Vector3::<T>::new(T::default(), T::default(), T::default());
7061        let p1 = &d.x as *const T;
7062        let p2 = &d.y as *const T;
7063        let p3 = &d.z as *const T;
7064
7065        if std::mem::size_of::<nalgebra::Point3<T>>() == 3 * std::mem::size_of::<T>()
7066            && p1.offset(1) == p2
7067            && p1.offset(2) == p3
7068        {
7069            IsPacked::yes()
7070        } else {
7071            IsPacked::no()
7072        }
7073    }
7074}
7075#[cfg(feature = "nalgebra")]
7076impl<T: WithSchema + nalgebra::Scalar> WithSchema for nalgebra::Vector3<T> {
7077    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
7078        Schema::Array(SchemaArray {
7079            item_type: Box::new(T::schema(version, context)),
7080            count: 3,
7081        })
7082    }
7083}
7084#[cfg(feature = "nalgebra")]
7085impl<T: Serialize + Packed + WithSchema + nalgebra::Scalar> Serialize for nalgebra::Vector3<T> {
7086    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7087        self.x.serialize(serializer)?;
7088        self.y.serialize(serializer)?;
7089        self.z.serialize(serializer)?;
7090
7091        Ok(())
7092    }
7093}
7094#[cfg(feature = "nalgebra")]
7095impl<T: Deserialize + Packed + WithSchema + nalgebra::Scalar + nalgebra::SimdValue + nalgebra::RealField> Deserialize
7096    for nalgebra::Vector3<T>
7097{
7098    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7099        Ok(nalgebra::Vector3::new(
7100            <T as Deserialize>::deserialize(deserializer)?,
7101            <T as Deserialize>::deserialize(deserializer)?,
7102            <T as Deserialize>::deserialize(deserializer)?,
7103        ))
7104    }
7105}
7106
7107#[cfg(feature = "nalgebra")]
7108impl<T: Packed> Packed for nalgebra::Isometry3<T> {}
7109#[cfg(feature = "nalgebra")]
7110impl<T: WithSchema> WithSchema for nalgebra::Isometry3<T> {
7111    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
7112        Schema::Array(SchemaArray {
7113            item_type: Box::new(T::schema(version, context)),
7114            count: 7,
7115        })
7116    }
7117}
7118#[cfg(feature = "nalgebra")]
7119impl<T: Serialize + Packed + WithSchema + nalgebra::Scalar> Serialize for nalgebra::Isometry3<T> {
7120    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7121        self.translation.vector.x.serialize(serializer)?;
7122        self.translation.vector.y.serialize(serializer)?;
7123        self.translation.vector.z.serialize(serializer)?;
7124
7125        self.rotation.coords.w.serialize(serializer)?;
7126        self.rotation.coords.x.serialize(serializer)?;
7127        self.rotation.coords.y.serialize(serializer)?;
7128        self.rotation.coords.z.serialize(serializer)?;
7129
7130        Ok(())
7131    }
7132}
7133#[cfg(feature = "nalgebra")]
7134impl<T: Deserialize + Packed + WithSchema + nalgebra::Scalar + nalgebra::SimdValue + nalgebra::RealField> Deserialize
7135    for nalgebra::Isometry3<T>
7136{
7137    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7138        Ok(nalgebra::Isometry3::from_parts(
7139            nalgebra::Point3::new(
7140                <T as Deserialize>::deserialize(deserializer)?,
7141                <T as Deserialize>::deserialize(deserializer)?,
7142                <T as Deserialize>::deserialize(deserializer)?,
7143            )
7144            .into(),
7145            nalgebra::UnitQuaternion::new_unchecked(nalgebra::Quaternion::new(
7146                <T as Deserialize>::deserialize(deserializer)?,
7147                <T as Deserialize>::deserialize(deserializer)?,
7148                <T as Deserialize>::deserialize(deserializer)?,
7149                <T as Deserialize>::deserialize(deserializer)?,
7150            )),
7151        ))
7152    }
7153}
7154
7155#[cfg(feature = "arrayvec")]
7156impl<const C: usize> Packed for arrayvec::ArrayString<C> {}
7157
7158#[cfg(feature = "arrayvec")]
7159impl<const C: usize> WithSchema for arrayvec::ArrayString<C> {
7160    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7161        Schema::Primitive(SchemaPrimitive::schema_string(VecOrStringLayout::Unknown))
7162    }
7163}
7164#[cfg(feature = "arrayvec")]
7165impl<const C: usize> Serialize for arrayvec::ArrayString<C> {
7166    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7167        serializer.write_string(self.as_str())
7168    }
7169}
7170#[cfg(feature = "arrayvec")]
7171impl<const C: usize> Deserialize for arrayvec::ArrayString<C> {
7172    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7173        let l = deserializer.read_usize()?;
7174        if l > C {
7175            return Err(SavefileError::ArrayvecCapacityError {
7176                msg: format!("Deserialized data had length {}, but ArrayString capacity is {}", l, C),
7177            });
7178        }
7179        let mut tempbuf = [0u8; C];
7180        deserializer.read_bytes_to_buf(&mut tempbuf[0..l])?;
7181
7182        match std::str::from_utf8(&tempbuf[0..l]) {
7183            Ok(s) => Ok(arrayvec::ArrayString::try_from(s)?),
7184            Err(_err) => Err(SavefileError::InvalidUtf8 {
7185                msg: format!("ArrayString<{}> contained invalid UTF8", C),
7186            }),
7187        }
7188    }
7189}
7190#[cfg(feature = "arrayvec")]
7191impl<const C: usize> Introspect for arrayvec::ArrayString<C> {
7192    fn introspect_value(&self) -> String {
7193        self.to_string()
7194    }
7195
7196    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_>>> {
7197        None
7198    }
7199}
7200
7201#[cfg(feature = "arrayvec")]
7202impl<V: WithSchema, const C: usize> WithSchema for arrayvec::ArrayVec<V, C> {
7203    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
7204        Schema::Vector(Box::new(V::schema(version, context)), VecOrStringLayout::Unknown)
7205    }
7206}
7207
7208#[cfg(feature = "arrayvec")]
7209impl<V: Introspect + 'static, const C: usize> Introspect for arrayvec::ArrayVec<V, C> {
7210    fn introspect_value(&self) -> String {
7211        return "arrayvec[]".to_string();
7212    }
7213
7214    fn introspect_child<'s>(&'s self, index: usize) -> Option<Box<dyn IntrospectItem<'s> + 's>> {
7215        if index >= self.len() {
7216            return None;
7217        }
7218        return Some(Box::new(IntrospectItemSimple {
7219            key: index.to_string(),
7220            val: &self[index],
7221        }));
7222    }
7223    fn introspect_len(&self) -> usize {
7224        self.len()
7225    }
7226}
7227
7228#[cfg(feature = "arrayvec")]
7229impl<V: Packed, const C: usize> Packed for arrayvec::ArrayVec<V, C> {
7230    unsafe fn repr_c_optimization_safe(version: u32) -> IsPacked {
7231        V::repr_c_optimization_safe(version)
7232    }
7233}
7234
7235#[cfg(feature = "arrayvec")]
7236impl<V: Serialize + Packed, const C: usize> Serialize for arrayvec::ArrayVec<V, C> {
7237    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7238        unsafe {
7239            if V::repr_c_optimization_safe(serializer.file_version).is_false() {
7240                regular_serialize_vec(self, serializer)
7241            } else {
7242                let l = self.len();
7243                serializer.write_usize(l)?;
7244                serializer.write_buf(std::slice::from_raw_parts(
7245                    self.as_ptr() as *const u8,
7246                    std::mem::size_of::<V>() * l,
7247                ))
7248            }
7249        }
7250    }
7251}
7252
7253#[cfg(feature = "arrayvec")]
7254impl<V: Deserialize + Packed, const C: usize> Deserialize for arrayvec::ArrayVec<V, C> {
7255    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<arrayvec::ArrayVec<V, C>, SavefileError> {
7256        let mut ret = arrayvec::ArrayVec::new();
7257        let l = deserializer.read_usize()?;
7258        if l > ret.capacity() {
7259            return Err(SavefileError::ArrayvecCapacityError {
7260                msg: format!("ArrayVec with capacity {} can't hold {} items", ret.capacity(), l),
7261            });
7262        }
7263        if unsafe { V::repr_c_optimization_safe(deserializer.file_version) }.is_false() {
7264            for _ in 0..l {
7265                ret.push(V::deserialize(deserializer)?);
7266            }
7267        } else {
7268            unsafe {
7269                let bytebuf = std::slice::from_raw_parts_mut(ret.as_mut_ptr() as *mut u8, std::mem::size_of::<V>() * l);
7270                deserializer.reader.read_exact(bytebuf)?; //We 'leak' Packed objects here on error, but the idea is they are drop-less anyway, so this has no effect
7271                ret.set_len(l);
7272            }
7273        }
7274        Ok(ret)
7275    }
7276}
7277
7278use std::ops::{Deref, Range};
7279impl<T: WithSchema + 'static> WithSchema for Box<T> {
7280    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
7281        context.possible_recursion::<T>(|context| T::schema(version, context))
7282    }
7283}
7284impl<T> Packed for Box<T> {}
7285impl<T: Serialize + 'static> Serialize for Box<T> {
7286    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7287        self.deref().serialize(serializer)
7288    }
7289}
7290impl<T: Deserialize + 'static> Deserialize for Box<T> {
7291    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7292        Ok(Box::new(T::deserialize(deserializer)?))
7293    }
7294}
7295
7296use std::rc::Rc;
7297
7298impl<T> Packed for Rc<T> {}
7299impl<T: WithSchema + 'static> WithSchema for Rc<T> {
7300    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
7301        context.possible_recursion::<T>(|context| T::schema(version, context))
7302    }
7303}
7304impl<T: Serialize + 'static> Serialize for Rc<T> {
7305    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7306        self.deref().serialize(serializer)
7307    }
7308}
7309impl<T: Deserialize + 'static> Deserialize for Rc<T> {
7310    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7311        Ok(Rc::new(T::deserialize(deserializer)?))
7312    }
7313}
7314
7315impl<T> Packed for Arc<T> {}
7316impl<T: WithSchema + 'static> WithSchema for Arc<T> {
7317    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
7318        context.possible_recursion::<T>(|context| T::schema(version, context))
7319    }
7320}
7321impl<T: Serialize + 'static> Serialize for Arc<T> {
7322    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7323        self.deref().serialize(serializer)
7324    }
7325}
7326impl<T: Deserialize + 'static> Deserialize for Arc<T> {
7327    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7328        Ok(Arc::new(T::deserialize(deserializer)?))
7329    }
7330}
7331use byteorder::{ReadBytesExt, WriteBytesExt};
7332#[cfg(feature = "bzip2")]
7333use bzip2::Compression;
7334use memoffset::offset_of_tuple;
7335use std::any::Any;
7336use std::cell::Cell;
7337use std::cell::RefCell;
7338use std::collections::hash_map::Entry;
7339#[allow(unused_imports)]
7340use std::convert::{TryFrom, TryInto};
7341use std::fmt::{Debug, Display, Formatter};
7342use std::marker::PhantomData;
7343use std::path::{Path, PathBuf};
7344use std::ptr::NonNull;
7345use std::slice;
7346use std::sync::Arc;
7347use std::time::{Duration, SystemTime};
7348
7349impl<T> Packed for RefCell<T> {}
7350impl<T: WithSchema> WithSchema for RefCell<T> {
7351    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
7352        T::schema(version, context)
7353    }
7354}
7355impl<T: Serialize> Serialize for RefCell<T> {
7356    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7357        self.borrow().serialize(serializer)
7358    }
7359}
7360impl<T: Deserialize> Deserialize for RefCell<T> {
7361    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7362        Ok(RefCell::new(T::deserialize(deserializer)?))
7363    }
7364}
7365
7366impl<T: Packed> Packed for Cell<T> {
7367    unsafe fn repr_c_optimization_safe(version: u32) -> IsPacked {
7368        T::repr_c_optimization_safe(version)
7369    }
7370}
7371impl<T: WithSchema> WithSchema for Cell<T> {
7372    fn schema(version: u32, context: &mut WithSchemaContext) -> Schema {
7373        T::schema(version, context)
7374    }
7375}
7376impl<T: Serialize + Copy> Serialize for Cell<T> {
7377    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7378        let t: T = self.get();
7379        t.serialize(serializer)
7380    }
7381}
7382impl<T: Deserialize> Deserialize for Cell<T> {
7383    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7384        Ok(Cell::new(T::deserialize(deserializer)?))
7385    }
7386}
7387
7388impl WithSchema for () {
7389    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7390        Schema::ZeroSize
7391    }
7392}
7393impl Serialize for () {
7394    fn serialize(&self, _serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7395        Ok(())
7396    }
7397}
7398
7399impl Introspect for () {
7400    fn introspect_value(&self) -> String {
7401        "()".to_string()
7402    }
7403    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7404        None
7405    }
7406}
7407impl Deserialize for () {
7408    fn deserialize(_deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7409        Ok(())
7410    }
7411}
7412
7413impl<T: Introspect> Introspect for (T,) {
7414    fn introspect_value(&self) -> String {
7415        return "1-tuple".to_string();
7416    }
7417
7418    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7419        if index == 0 {
7420            return Some(introspect_item("0".to_string(), &self.0));
7421        }
7422        return None;
7423    }
7424}
7425
7426impl<T1: Introspect, T2: Introspect> Introspect for (T1, T2) {
7427    fn introspect_value(&self) -> String {
7428        return "2-tuple".to_string();
7429    }
7430
7431    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7432        if index == 0 {
7433            return Some(introspect_item("0".to_string(), &self.0));
7434        }
7435        if index == 1 {
7436            return Some(introspect_item("1".to_string(), &self.1));
7437        }
7438        return None;
7439    }
7440}
7441impl<T1: Introspect, T2: Introspect, T3: Introspect> Introspect for (T1, T2, T3) {
7442    fn introspect_value(&self) -> String {
7443        return "3-tuple".to_string();
7444    }
7445
7446    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7447        if index == 0 {
7448            return Some(introspect_item("0".to_string(), &self.0));
7449        }
7450        if index == 1 {
7451            return Some(introspect_item("1".to_string(), &self.1));
7452        }
7453        if index == 2 {
7454            return Some(introspect_item("2".to_string(), &self.2));
7455        }
7456        return None;
7457    }
7458}
7459impl<T1: Introspect, T2: Introspect, T3: Introspect, T4: Introspect> Introspect for (T1, T2, T3, T4) {
7460    fn introspect_value(&self) -> String {
7461        return "4-tuple".to_string();
7462    }
7463
7464    fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7465        if index == 0 {
7466            return Some(introspect_item("0".to_string(), &self.0));
7467        }
7468        if index == 1 {
7469            return Some(introspect_item("1".to_string(), &self.1));
7470        }
7471        if index == 2 {
7472            return Some(introspect_item("2".to_string(), &self.2));
7473        }
7474        if index == 3 {
7475            return Some(introspect_item("3".to_string(), &self.3));
7476        }
7477        return None;
7478    }
7479}
7480
7481impl Introspect for AtomicBool {
7482    fn introspect_value(&self) -> String {
7483        self.load(Ordering::SeqCst).to_string()
7484    }
7485    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7486        None
7487    }
7488}
7489impl Introspect for AtomicU8 {
7490    fn introspect_value(&self) -> String {
7491        self.load(Ordering::SeqCst).to_string()
7492    }
7493    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7494        None
7495    }
7496}
7497impl Introspect for AtomicI8 {
7498    fn introspect_value(&self) -> String {
7499        self.load(Ordering::SeqCst).to_string()
7500    }
7501    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7502        None
7503    }
7504}
7505impl Introspect for AtomicU16 {
7506    fn introspect_value(&self) -> String {
7507        self.load(Ordering::SeqCst).to_string()
7508    }
7509    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7510        None
7511    }
7512}
7513impl Introspect for AtomicI16 {
7514    fn introspect_value(&self) -> String {
7515        self.load(Ordering::SeqCst).to_string()
7516    }
7517    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7518        None
7519    }
7520}
7521impl Introspect for AtomicU32 {
7522    fn introspect_value(&self) -> String {
7523        self.load(Ordering::SeqCst).to_string()
7524    }
7525    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7526        None
7527    }
7528}
7529impl Introspect for AtomicI32 {
7530    fn introspect_value(&self) -> String {
7531        self.load(Ordering::SeqCst).to_string()
7532    }
7533    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7534        None
7535    }
7536}
7537impl Introspect for AtomicU64 {
7538    fn introspect_value(&self) -> String {
7539        self.load(Ordering::SeqCst).to_string()
7540    }
7541    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7542        None
7543    }
7544}
7545impl Introspect for AtomicI64 {
7546    fn introspect_value(&self) -> String {
7547        self.load(Ordering::SeqCst).to_string()
7548    }
7549    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7550        None
7551    }
7552}
7553impl Introspect for AtomicUsize {
7554    fn introspect_value(&self) -> String {
7555        self.load(Ordering::SeqCst).to_string()
7556    }
7557    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7558        None
7559    }
7560}
7561impl Introspect for AtomicIsize {
7562    fn introspect_value(&self) -> String {
7563        self.load(Ordering::SeqCst).to_string()
7564    }
7565    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7566        None
7567    }
7568}
7569
7570impl WithSchema for AtomicBool {
7571    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7572        Schema::Primitive(SchemaPrimitive::schema_bool)
7573    }
7574}
7575impl WithSchema for AtomicU8 {
7576    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7577        Schema::Primitive(SchemaPrimitive::schema_u8)
7578    }
7579}
7580impl WithSchema for AtomicI8 {
7581    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7582        Schema::Primitive(SchemaPrimitive::schema_i8)
7583    }
7584}
7585impl WithSchema for AtomicU16 {
7586    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7587        Schema::Primitive(SchemaPrimitive::schema_u16)
7588    }
7589}
7590impl WithSchema for AtomicI16 {
7591    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7592        Schema::Primitive(SchemaPrimitive::schema_i16)
7593    }
7594}
7595impl WithSchema for AtomicU32 {
7596    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7597        Schema::Primitive(SchemaPrimitive::schema_u32)
7598    }
7599}
7600impl WithSchema for AtomicI32 {
7601    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7602        Schema::Primitive(SchemaPrimitive::schema_i32)
7603    }
7604}
7605impl WithSchema for AtomicU64 {
7606    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7607        Schema::Primitive(SchemaPrimitive::schema_u64)
7608    }
7609}
7610impl WithSchema for AtomicI64 {
7611    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7612        Schema::Primitive(SchemaPrimitive::schema_i64)
7613    }
7614}
7615impl WithSchema for AtomicUsize {
7616    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7617        match std::mem::size_of::<usize>() {
7618            4 => Schema::Primitive(SchemaPrimitive::schema_u32),
7619            8 => Schema::Primitive(SchemaPrimitive::schema_u64),
7620            _ => panic!("Size of usize was neither 32 bit nor 64 bit. This is not supported by the savefile crate."),
7621        }
7622    }
7623}
7624impl WithSchema for AtomicIsize {
7625    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7626        match std::mem::size_of::<isize>() {
7627            4 => Schema::Primitive(SchemaPrimitive::schema_i32),
7628            8 => Schema::Primitive(SchemaPrimitive::schema_i64),
7629            _ => panic!("Size of isize was neither 32 bit nor 64 bit. This is not supported by the savefile crate."),
7630        }
7631    }
7632}
7633
7634impl WithSchema for bool {
7635    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7636        Schema::Primitive(SchemaPrimitive::schema_bool)
7637    }
7638}
7639impl WithSchema for u8 {
7640    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7641        Schema::Primitive(SchemaPrimitive::schema_u8)
7642    }
7643}
7644impl WithSchema for i8 {
7645    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7646        Schema::Primitive(SchemaPrimitive::schema_i8)
7647    }
7648}
7649impl WithSchema for u16 {
7650    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7651        Schema::Primitive(SchemaPrimitive::schema_u16)
7652    }
7653}
7654impl WithSchema for i16 {
7655    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7656        Schema::Primitive(SchemaPrimitive::schema_i16)
7657    }
7658}
7659impl WithSchema for u32 {
7660    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7661        Schema::Primitive(SchemaPrimitive::schema_u32)
7662    }
7663}
7664impl WithSchema for i32 {
7665    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7666        Schema::Primitive(SchemaPrimitive::schema_i32)
7667    }
7668}
7669impl WithSchema for u64 {
7670    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7671        Schema::Primitive(SchemaPrimitive::schema_u64)
7672    }
7673}
7674impl WithSchema for u128 {
7675    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7676        Schema::Primitive(SchemaPrimitive::schema_u128)
7677    }
7678}
7679impl WithSchema for i128 {
7680    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7681        Schema::Primitive(SchemaPrimitive::schema_i128)
7682    }
7683}
7684impl WithSchema for i64 {
7685    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7686        Schema::Primitive(SchemaPrimitive::schema_i64)
7687    }
7688}
7689impl WithSchema for char {
7690    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7691        Schema::Primitive(SchemaPrimitive::schema_char)
7692    }
7693}
7694impl WithSchema for usize {
7695    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7696        match std::mem::size_of::<usize>() {
7697            4 => Schema::Primitive(SchemaPrimitive::schema_u32),
7698            8 => Schema::Primitive(SchemaPrimitive::schema_u64),
7699            _ => panic!("Size of usize was neither 32 bit nor 64 bit. This is not supported by the savefile crate."),
7700        }
7701    }
7702}
7703impl WithSchema for isize {
7704    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7705        match std::mem::size_of::<isize>() {
7706            4 => Schema::Primitive(SchemaPrimitive::schema_i32),
7707            8 => Schema::Primitive(SchemaPrimitive::schema_i64),
7708            _ => panic!("Size of isize was neither 32 bit nor 64 bit. This is not supported by the savefile crate."),
7709        }
7710    }
7711}
7712impl WithSchema for f32 {
7713    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7714        Schema::Primitive(SchemaPrimitive::schema_f32)
7715    }
7716}
7717impl WithSchema for f64 {
7718    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
7719        Schema::Primitive(SchemaPrimitive::schema_f64)
7720    }
7721}
7722
7723impl Introspect for bool {
7724    fn introspect_value(&self) -> String {
7725        self.to_string()
7726    }
7727    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7728        None
7729    }
7730}
7731impl Introspect for u8 {
7732    fn introspect_value(&self) -> String {
7733        self.to_string()
7734    }
7735    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7736        None
7737    }
7738}
7739impl Introspect for u16 {
7740    fn introspect_value(&self) -> String {
7741        self.to_string()
7742    }
7743    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7744        None
7745    }
7746}
7747impl Introspect for u32 {
7748    fn introspect_value(&self) -> String {
7749        self.to_string()
7750    }
7751    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7752        None
7753    }
7754}
7755impl Introspect for u64 {
7756    fn introspect_value(&self) -> String {
7757        self.to_string()
7758    }
7759    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7760        None
7761    }
7762}
7763impl Introspect for u128 {
7764    fn introspect_value(&self) -> String {
7765        self.to_string()
7766    }
7767    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7768        None
7769    }
7770}
7771impl Introspect for i8 {
7772    fn introspect_value(&self) -> String {
7773        self.to_string()
7774    }
7775    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7776        None
7777    }
7778}
7779impl Introspect for i16 {
7780    fn introspect_value(&self) -> String {
7781        self.to_string()
7782    }
7783    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7784        None
7785    }
7786}
7787impl Introspect for i32 {
7788    fn introspect_value(&self) -> String {
7789        self.to_string()
7790    }
7791    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7792        None
7793    }
7794}
7795impl Introspect for i64 {
7796    fn introspect_value(&self) -> String {
7797        self.to_string()
7798    }
7799    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7800        None
7801    }
7802}
7803impl Introspect for char {
7804    fn introspect_value(&self) -> String {
7805        self.to_string()
7806    }
7807    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7808        None
7809    }
7810}
7811impl Introspect for i128 {
7812    fn introspect_value(&self) -> String {
7813        self.to_string()
7814    }
7815    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7816        None
7817    }
7818}
7819impl Introspect for f32 {
7820    fn introspect_value(&self) -> String {
7821        self.to_string()
7822    }
7823    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7824        None
7825    }
7826}
7827impl Introspect for f64 {
7828    fn introspect_value(&self) -> String {
7829        self.to_string()
7830    }
7831    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7832        None
7833    }
7834}
7835impl Introspect for usize {
7836    fn introspect_value(&self) -> String {
7837        self.to_string()
7838    }
7839    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7840        None
7841    }
7842}
7843impl Introspect for isize {
7844    fn introspect_value(&self) -> String {
7845        self.to_string()
7846    }
7847    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
7848        None
7849    }
7850}
7851
7852impl Serialize for u8 {
7853    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7854        serializer.write_u8(*self)
7855    }
7856}
7857impl Deserialize for u8 {
7858    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7859        deserializer.read_u8()
7860    }
7861}
7862impl Serialize for bool {
7863    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7864        serializer.write_bool(*self)
7865    }
7866}
7867impl Deserialize for bool {
7868    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7869        deserializer.read_bool()
7870    }
7871}
7872
7873impl Serialize for f32 {
7874    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7875        serializer.write_f32(*self)
7876    }
7877}
7878impl Deserialize for f32 {
7879    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7880        deserializer.read_f32()
7881    }
7882}
7883
7884impl Serialize for f64 {
7885    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7886        serializer.write_f64(*self)
7887    }
7888}
7889impl Deserialize for f64 {
7890    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7891        deserializer.read_f64()
7892    }
7893}
7894
7895impl Serialize for i8 {
7896    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7897        serializer.write_i8(*self)
7898    }
7899}
7900impl Deserialize for i8 {
7901    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7902        deserializer.read_i8()
7903    }
7904}
7905impl Serialize for u16 {
7906    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7907        serializer.write_u16(*self)
7908    }
7909}
7910impl Deserialize for u16 {
7911    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7912        deserializer.read_u16()
7913    }
7914}
7915impl Serialize for i16 {
7916    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7917        serializer.write_i16(*self)
7918    }
7919}
7920impl Deserialize for i16 {
7921    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7922        deserializer.read_i16()
7923    }
7924}
7925
7926impl Serialize for u32 {
7927    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7928        serializer.write_u32(*self)
7929    }
7930}
7931impl Deserialize for u32 {
7932    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7933        deserializer.read_u32()
7934    }
7935}
7936impl Serialize for i32 {
7937    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7938        serializer.write_i32(*self)
7939    }
7940}
7941impl Deserialize for i32 {
7942    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7943        deserializer.read_i32()
7944    }
7945}
7946
7947impl Serialize for u64 {
7948    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7949        serializer.write_u64(*self)
7950    }
7951}
7952impl Deserialize for u64 {
7953    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7954        deserializer.read_u64()
7955    }
7956}
7957impl Serialize for i64 {
7958    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7959        serializer.write_i64(*self)
7960    }
7961}
7962impl Serialize for char {
7963    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7964        serializer.write_u32((*self).into())
7965    }
7966}
7967impl Deserialize for i64 {
7968    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7969        deserializer.read_i64()
7970    }
7971}
7972impl Deserialize for char {
7973    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7974        let uc = deserializer.read_u32()?;
7975        match uc.try_into() {
7976            Ok(x) => Ok(x),
7977            Err(_) => Err(SavefileError::InvalidChar),
7978        }
7979    }
7980}
7981impl Serialize for u128 {
7982    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7983        serializer.write_u128(*self)
7984    }
7985}
7986impl Deserialize for u128 {
7987    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7988        deserializer.read_u128()
7989    }
7990}
7991impl Serialize for i128 {
7992    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
7993        serializer.write_i128(*self)
7994    }
7995}
7996impl Deserialize for i128 {
7997    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
7998        deserializer.read_i128()
7999    }
8000}
8001
8002impl Serialize for usize {
8003    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8004        serializer.write_usize(*self)
8005    }
8006}
8007impl Deserialize for usize {
8008    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8009        deserializer.read_usize()
8010    }
8011}
8012impl Serialize for isize {
8013    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8014        serializer.write_isize(*self)
8015    }
8016}
8017impl Deserialize for isize {
8018    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8019        deserializer.read_isize()
8020    }
8021}
8022
8023impl Serialize for AtomicBool {
8024    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8025        serializer.write_bool(self.load(Ordering::SeqCst))
8026    }
8027}
8028impl Deserialize for AtomicBool {
8029    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8030        Ok(AtomicBool::new(deserializer.read_bool()?))
8031    }
8032}
8033
8034impl Serialize for AtomicU8 {
8035    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8036        serializer.write_u8(self.load(Ordering::SeqCst))
8037    }
8038}
8039impl Deserialize for AtomicU8 {
8040    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8041        Ok(AtomicU8::new(deserializer.read_u8()?))
8042    }
8043}
8044impl Serialize for AtomicI8 {
8045    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8046        serializer.write_i8(self.load(Ordering::SeqCst))
8047    }
8048}
8049impl Deserialize for AtomicI8 {
8050    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8051        Ok(AtomicI8::new(deserializer.read_i8()?))
8052    }
8053}
8054impl Serialize for AtomicU16 {
8055    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8056        serializer.write_u16(self.load(Ordering::SeqCst))
8057    }
8058}
8059impl Deserialize for AtomicU16 {
8060    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8061        Ok(AtomicU16::new(deserializer.read_u16()?))
8062    }
8063}
8064impl Serialize for AtomicI16 {
8065    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8066        serializer.write_i16(self.load(Ordering::SeqCst))
8067    }
8068}
8069impl Deserialize for AtomicI16 {
8070    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8071        Ok(AtomicI16::new(deserializer.read_i16()?))
8072    }
8073}
8074
8075impl Serialize for AtomicU32 {
8076    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8077        serializer.write_u32(self.load(Ordering::SeqCst))
8078    }
8079}
8080impl Deserialize for AtomicU32 {
8081    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8082        Ok(AtomicU32::new(deserializer.read_u32()?))
8083    }
8084}
8085impl Serialize for AtomicI32 {
8086    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8087        serializer.write_i32(self.load(Ordering::SeqCst))
8088    }
8089}
8090impl Deserialize for AtomicI32 {
8091    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8092        Ok(AtomicI32::new(deserializer.read_i32()?))
8093    }
8094}
8095
8096impl Serialize for AtomicU64 {
8097    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8098        serializer.write_u64(self.load(Ordering::SeqCst))
8099    }
8100}
8101impl Deserialize for AtomicU64 {
8102    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8103        Ok(AtomicU64::new(deserializer.read_u64()?))
8104    }
8105}
8106impl Serialize for AtomicI64 {
8107    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8108        serializer.write_i64(self.load(Ordering::SeqCst))
8109    }
8110}
8111impl Deserialize for AtomicI64 {
8112    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8113        Ok(AtomicI64::new(deserializer.read_i64()?))
8114    }
8115}
8116
8117impl Serialize for AtomicUsize {
8118    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8119        serializer.write_usize(self.load(Ordering::SeqCst))
8120    }
8121}
8122impl Deserialize for AtomicUsize {
8123    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8124        Ok(AtomicUsize::new(deserializer.read_usize()?))
8125    }
8126}
8127impl Serialize for AtomicIsize {
8128    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8129        serializer.write_isize(self.load(Ordering::SeqCst))
8130    }
8131}
8132impl Deserialize for AtomicIsize {
8133    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8134        Ok(AtomicIsize::new(deserializer.read_isize()?))
8135    }
8136}
8137
8138impl Packed for AtomicBool {}
8139impl Packed for AtomicI8 {}
8140impl Packed for AtomicU8 {}
8141impl Packed for AtomicI16 {}
8142impl Packed for AtomicU16 {}
8143impl Packed for AtomicI32 {}
8144impl Packed for AtomicU32 {}
8145impl Packed for AtomicI64 {}
8146impl Packed for AtomicU64 {}
8147impl Packed for AtomicIsize {}
8148impl Packed for AtomicUsize {}
8149
8150/// A zero-sized marker for troubleshooting purposes.
8151///
8152/// It serializes to a magic value,
8153/// and verifies this value on deserialization. Does not consume memory
8154/// data structure. Useful to troubleshoot broken Serialize/Deserialize implementations.
8155#[derive(Clone, Copy, Eq, PartialEq, Default, Debug)]
8156pub struct Canary1 {}
8157impl Canary1 {
8158    /// Create a new Canary1 object. Object has no contents.
8159    pub fn new() -> Canary1 {
8160        Canary1 {}
8161    }
8162}
8163impl Introspect for Canary1 {
8164    fn introspect_value(&self) -> String {
8165        "Canary1".to_string()
8166    }
8167
8168    fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem<'_> + '_>> {
8169        None
8170    }
8171}
8172
8173impl Deserialize for Canary1 {
8174    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8175        let magic = deserializer.read_u32()?;
8176        if magic != 0x47566843 {
8177            return Err(SavefileError::GeneralError {
8178                msg: format!(
8179                    "Encountered bad magic value when deserializing Canary1. Expected {} but got {}",
8180                    0x47566843, magic
8181                ),
8182            });
8183        }
8184        Ok(Canary1 {})
8185    }
8186}
8187
8188impl Serialize for Canary1 {
8189    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8190        serializer.write_u32(0x47566843)
8191    }
8192}
8193impl Packed for Canary1 {}
8194impl WithSchema for Canary1 {
8195    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
8196        Schema::Primitive(SchemaPrimitive::schema_canary1)
8197    }
8198}
8199
8200impl WithSchema for Duration {
8201    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
8202        Schema::Struct(SchemaStruct {
8203            dbg_name: "Duration".to_string(),
8204            size: None,
8205            alignment: None,
8206            fields: vec![Field {
8207                name: "Duration".to_string(),
8208                value: Box::new(Schema::Primitive(SchemaPrimitive::schema_u128)),
8209                offset: None,
8210            }],
8211        })
8212    }
8213}
8214impl Packed for Duration {}
8215impl Serialize for Duration {
8216    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8217        serializer.write_u128(self.as_nanos())
8218    }
8219}
8220impl Deserialize for Duration {
8221    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8222        let temp = deserializer.read_u128()?;
8223        Ok(Duration::from_secs((temp / 1_000_000_000) as u64) + Duration::from_nanos((temp % 1_000_000_000) as u64))
8224    }
8225}
8226
8227impl Introspect for Duration {
8228    fn introspect_value(&self) -> String {
8229        format!("{:?}", self)
8230    }
8231
8232    fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
8233        None
8234    }
8235
8236    fn introspect_len(&self) -> usize {
8237        0
8238    }
8239}
8240impl Introspect for SystemTime {
8241    fn introspect_value(&self) -> String {
8242        format!("{:?}", self)
8243    }
8244
8245    fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
8246        None
8247    }
8248
8249    fn introspect_len(&self) -> usize {
8250        0
8251    }
8252}
8253impl WithSchema for SystemTime {
8254    fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
8255        Schema::Struct(SchemaStruct {
8256            dbg_name: "SystemTime".to_string(),
8257            size: None,
8258            alignment: None,
8259            fields: vec![Field {
8260                name: "SystemTimeDuration".to_string(),
8261                value: Box::new(Schema::Primitive(SchemaPrimitive::schema_u128)),
8262                offset: None,
8263            }],
8264        })
8265    }
8266}
8267impl Packed for SystemTime {}
8268impl Serialize for SystemTime {
8269    fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
8270        match self.duration_since(SystemTime::UNIX_EPOCH) {
8271            Ok(nanos) => {
8272                let temp = nanos.as_nanos();
8273                if temp >= 1u128 << 120 {
8274                    return Err(SavefileError::GeneralError {
8275                        msg: "Savefile cannot handle dates where the year is larger than ca 10^19 years.".to_string(),
8276                    });
8277                }
8278                serializer.write_u128(temp)?;
8279            }
8280            Err(err) => {
8281                //Before UNIX Epoch
8282                let mut temp = err.duration().as_nanos();
8283                if temp >= 1u128 << 120 {
8284                    return Err(SavefileError::GeneralError {
8285                        msg: "Savefile cannot handle dates much earlier than the creation of the universe.".to_string(),
8286                    });
8287                }
8288                temp |= 1u128 << 127;
8289                serializer.write_u128(temp)?;
8290            }
8291        }
8292        Ok(())
8293    }
8294}
8295
8296impl Introspect for std::time::Instant {
8297    fn introspect_value(&self) -> String {
8298        format!("{:?}", self)
8299    }
8300    fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
8301        None
8302    }
8303}
8304
8305fn u128_duration_nanos(nanos: u128) -> Duration {
8306    if nanos > u64::MAX as u128 {
8307        Duration::from_nanos((nanos % 1_000_000_000) as u64) + Duration::from_secs((nanos / 1_000_000_000) as u64)
8308    } else {
8309        Duration::from_nanos(nanos as u64)
8310    }
8311}
8312impl Deserialize for SystemTime {
8313    fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
8314        let mut temp = deserializer.read_u128()?;
8315        if temp >= (1u128 << 127) {
8316            temp &= (1u128 << 127) - 1; //Before UNIX Epoch
8317            return Ok(SystemTime::UNIX_EPOCH - u128_duration_nanos(temp));
8318        } else {
8319            return Ok(SystemTime::UNIX_EPOCH + u128_duration_nanos(temp));
8320        }
8321    }
8322}
8323
8324#[derive(Clone, Debug)]
8325struct PathElement {
8326    key: String,
8327    key_disambiguator: usize,
8328    max_children: usize,
8329}
8330
8331/// A helper which allows navigating an introspected object.
8332/// It remembers a path down into the guts of the object.
8333#[derive(Clone, Debug)]
8334pub struct Introspector {
8335    path: Vec<PathElement>,
8336    child_load_count: usize,
8337}
8338
8339/// A command to navigate within an introspected object
8340#[derive(Debug, PartialEq, Eq, Clone)]
8341pub enum IntrospectorNavCommand {
8342    /// Select the given object and expand its children.
8343    /// Use this when you know the string name of the key you wish to expand.
8344    ExpandElement(IntrospectedElementKey),
8345    /// Select the Nth object at the given depth in the tree.
8346    /// Use this when you know the index of the field you wish to expand.
8347    SelectNth {
8348        /// Depth of item to select and expand
8349        select_depth: usize,
8350        /// Index of item to select and expand
8351        select_index: usize,
8352    },
8353    /// Don't navigate
8354    Nothing,
8355    /// Navigate one level up
8356    Up,
8357}
8358
8359/// Identifies an introspected element somewhere in the introspection tree
8360/// of an object.
8361#[derive(PartialEq, Eq, Clone)]
8362pub struct IntrospectedElementKey {
8363    /// Depth in the tree. Fields on top level struct are at depth 0.
8364    pub depth: usize,
8365    /// The name of the field
8366    pub key: String,
8367    /// If several fields have the same name, the key_disambiguator is 0 for the first field,
8368    /// 1 for the next, etc.
8369    pub key_disambiguator: usize,
8370}
8371impl Default for IntrospectedElementKey {
8372    fn default() -> Self {
8373        IntrospectedElementKey {
8374            depth: 0,
8375            key: "".to_string(),
8376            key_disambiguator: 0,
8377        }
8378    }
8379}
8380
8381/// A node in the introspection tree
8382#[derive(PartialEq, Eq, Clone)]
8383pub struct IntrospectedElement {
8384    /// Identifying key
8385    pub key: IntrospectedElementKey,
8386    /// Value of node
8387    pub value: String,
8388    /// Flag which tells if there are children below this node
8389    pub has_children: bool,
8390    /// Flag which tells if this child is selected
8391    pub selected: bool,
8392}
8393
8394impl Debug for IntrospectedElementKey {
8395    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
8396        write!(
8397            f,
8398            "Key({} (at depth {}, key disambig {}))",
8399            self.key, self.depth, self.key_disambiguator
8400        )
8401    }
8402}
8403
8404impl Debug for IntrospectedElement {
8405    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
8406        write!(
8407            f,
8408            "KeyVal({} = {} (at depth {}, key disambig {}))",
8409            self.key.key, self.value, self.key.depth, self.key.key_disambiguator
8410        )
8411    }
8412}
8413
8414impl Display for IntrospectedElement {
8415    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
8416        write!(f, "{} = {}", self.key.key, self.value)
8417    }
8418}
8419
8420/// Ways in which introspection may fail
8421#[derive(Debug, PartialEq, Eq, Clone, Copy)]
8422pub enum IntrospectionError {
8423    /// The given depth value is invalid. At start of introspection,
8424    /// max depth value is 0, and fields of the root object are introspected. If a field
8425    /// is selected, a new level is expanded and max depth value is 1.
8426    BadDepth,
8427    /// The given key was not found
8428    UnknownKey,
8429    /// An attempt was made to select/expand a node which has no children.
8430    NoChildren,
8431    /// An attempt was made to select/expand a child with an index greater or equal to the number of children.
8432    IndexOutOfRange,
8433    /// An attempt was made to back up when already at the top.
8434    AlreadyAtTop,
8435}
8436
8437/// All fields at a specific depth in the introspection tree
8438#[derive(Debug, Clone)]
8439pub struct IntrospectionFrame {
8440    /// The index of the expanded child, if any
8441    pub selected: Option<usize>,
8442    /// All fields at this level
8443    pub keyvals: Vec<IntrospectedElement>,
8444    /// True if there may have been more children, but expansion was stopped
8445    /// because the limit given to the Introspector was reached.
8446    pub limit_reached: bool,
8447}
8448/// An introspection tree. Note that each node in the tree can only have
8449/// one expanded field, and thus at most one child (a bit of a boring 'tree' :-) ).
8450#[derive(Debug, Clone)]
8451pub struct IntrospectionResult {
8452    /// The levels in the tree
8453    pub frames: Vec<IntrospectionFrame>,
8454    cached_total_len: usize,
8455}
8456
8457impl Display for IntrospectionResult {
8458    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
8459        self.format_result_row(f)
8460    }
8461}
8462
8463impl IntrospectionResult {
8464    /// Indexes the result with a single index, which will reach all levels in the tree.
8465    /// Printing all elements in the order returned here, with indentation equal to
8466    /// item.key.depth, will yield a readable tree.
8467    pub fn total_index(&self, index: usize) -> Option<IntrospectedElement> {
8468        let mut cur = 0;
8469        self.total_index_impl(index, 0, &mut cur)
8470    }
8471    fn total_index_impl(&self, index: usize, depth: usize, cur: &mut usize) -> Option<IntrospectedElement> {
8472        if depth >= self.frames.len() {
8473            return None;
8474        }
8475        let frame = &self.frames[depth];
8476        {
8477            let mut offset = 0;
8478            if let Some(selection) = frame.selected {
8479                if index <= *cur + selection {
8480                    return Some(frame.keyvals[index - *cur].clone());
8481                }
8482                *cur += selection + 1;
8483                if let Some(result) = self.total_index_impl(index, depth + 1, cur) {
8484                    return Some(result);
8485                }
8486                offset = selection + 1;
8487            }
8488            if (index - *cur) + offset < frame.keyvals.len() {
8489                return Some(frame.keyvals[(index - *cur) + offset].clone());
8490            }
8491            *cur += frame.keyvals.len() - offset;
8492        }
8493        return None;
8494    }
8495
8496    /// The total number of nodes in the tree.
8497    /// The value returns is the exclusive upper bound of valid
8498    /// indexes to the 'total_index'-method.
8499    pub fn total_len(&self) -> usize {
8500        self.cached_total_len
8501    }
8502
8503    fn format_result_row(self: &IntrospectionResult, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
8504        if self.frames.len() == 0 {
8505            writeln!(f, "Introspectionresult:\n*empty*")?;
8506            return Ok(());
8507        }
8508        let mut idx = 0;
8509        let mut depth = Vec::new();
8510
8511        writeln!(f, "Introspectionresult:")?;
8512
8513        'outer: loop {
8514            let cur_row = &self.frames[depth.len()];
8515            if idx >= cur_row.keyvals.len() {
8516                if let Some(new_idx) = depth.pop() {
8517                    idx = new_idx;
8518                    continue;
8519                } else {
8520                    break;
8521                }
8522            }
8523            while idx < cur_row.keyvals.len() {
8524                let item = &cur_row.keyvals[idx];
8525                let is_selected = Some(idx) == cur_row.selected;
8526                let pad = if is_selected {
8527                    "*"
8528                } else if item.has_children {
8529                    ">"
8530                } else {
8531                    " "
8532                };
8533                writeln!(f, "{:>indent$}{}", pad, item, indent = 1 + 2 * depth.len())?;
8534                idx += 1;
8535                if is_selected && depth.len() + 1 < self.frames.len() {
8536                    depth.push(idx);
8537                    idx = 0;
8538                    continue 'outer;
8539                }
8540            }
8541        }
8542        Ok(())
8543    }
8544}
8545impl Display for IntrospectedElementKey {
8546    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
8547        write!(f, "{}", self.key)
8548    }
8549}
8550impl Introspector {
8551    /// Returns a new Introspector with no limit to the number of fields introspected per level
8552    pub fn new() -> Introspector {
8553        Introspector {
8554            path: vec![],
8555            child_load_count: usize::MAX,
8556        }
8557    }
8558    /// Returns a new Introspector which will not enumerate more than 'child_load_count'
8559    /// elements on each level (useful for performance reasons to stop a 1 megabyte byte array
8560    /// from overwhelming the user of the introspector).
8561    pub fn new_with(child_load_count: usize) -> Introspector {
8562        Introspector {
8563            path: vec![],
8564            child_load_count,
8565        }
8566    }
8567
8568    /// The current number of nodes in the tree.
8569    pub fn num_frames(&self) -> usize {
8570        self.path.len()
8571    }
8572
8573    fn dive(
8574        &mut self,
8575        depth: usize,
8576        object: &dyn Introspect,
8577        navigation_command: IntrospectorNavCommand,
8578    ) -> Result<Vec<IntrospectionFrame>, IntrospectionError> {
8579        let mut result_vec = Vec::new();
8580        let mut navigation_command = Some(navigation_command);
8581        let mut cur_path = self.path.get(depth).cloned();
8582        let mut index = 0;
8583        let mut row = IntrospectionFrame {
8584            selected: None,
8585            keyvals: vec![],
8586            limit_reached: false,
8587        };
8588        let mut key_disambig_map = HashMap::new();
8589
8590        let mut do_select_nth = None;
8591
8592        let mut err_if_key_not_found = false;
8593        if let Some(navigation_command) = navigation_command.as_ref() {
8594            match navigation_command {
8595                IntrospectorNavCommand::ExpandElement(elem) => {
8596                    if elem.depth > self.path.len() {
8597                        return Err(IntrospectionError::BadDepth);
8598                    }
8599                    if depth == elem.depth {
8600                        self.path.drain(depth..);
8601                        self.path.push(PathElement {
8602                            key: elem.key.clone(),
8603                            key_disambiguator: elem.key_disambiguator,
8604                            max_children: self.child_load_count,
8605                        });
8606                        cur_path = self.path.get(depth).cloned();
8607                        err_if_key_not_found = true;
8608                    }
8609                }
8610                IntrospectorNavCommand::SelectNth {
8611                    select_depth,
8612                    select_index,
8613                } => {
8614                    if depth == *select_depth {
8615                        do_select_nth = Some(*select_index);
8616                    }
8617                }
8618                IntrospectorNavCommand::Nothing => {}
8619                IntrospectorNavCommand::Up => {}
8620            }
8621        }
8622
8623        loop {
8624            if let Some(child_item) = object.introspect_child(index) {
8625                let key: String = child_item.key().into();
8626
8627                let disambig_counter: &mut usize = key_disambig_map.entry(key.clone()).or_insert(0usize);
8628                let has_children = child_item.val().introspect_child(0).is_some();
8629                row.keyvals.push(IntrospectedElement {
8630                    key: IntrospectedElementKey {
8631                        depth,
8632                        key: key.clone(),
8633                        key_disambiguator: *disambig_counter,
8634                    },
8635                    value: child_item.val().introspect_value(),
8636                    has_children,
8637                    selected: false,
8638                });
8639
8640                if Some(index) == do_select_nth {
8641                    self.path.push(PathElement {
8642                        key: key.clone(),
8643                        key_disambiguator: *disambig_counter,
8644                        max_children: self.child_load_count,
8645                    });
8646                    do_select_nth = None;
8647                    cur_path = self.path.last().cloned();
8648                }
8649
8650                if let Some(cur_path_obj) = &cur_path {
8651                    if row.selected.is_none()
8652                        && cur_path_obj.key == key
8653                        && cur_path_obj.key_disambiguator == *disambig_counter
8654                    {
8655                        row.selected = Some(index);
8656                        row.keyvals.last_mut().unwrap().selected = true;
8657                        if has_children {
8658                            let mut subresult =
8659                                self.dive(depth + 1, child_item.val(), navigation_command.take().unwrap())?;
8660                            debug_assert_eq!(result_vec.len(), 0);
8661                            std::mem::swap(&mut result_vec, &mut subresult);
8662                        }
8663                    }
8664                }
8665
8666                *disambig_counter += 1;
8667            } else {
8668                break;
8669            }
8670
8671            index += 1;
8672            if index
8673                >= cur_path
8674                    .as_ref()
8675                    .map(|x| x.max_children)
8676                    .unwrap_or(self.child_load_count)
8677            {
8678                row.limit_reached = true;
8679                break;
8680            }
8681        }
8682        if do_select_nth.is_some() {
8683            if index == 0 {
8684                return Err(IntrospectionError::NoChildren);
8685            }
8686            return Err(IntrospectionError::IndexOutOfRange);
8687        }
8688        if err_if_key_not_found && row.selected.is_none() {
8689            self.path.pop().unwrap();
8690            return Err(IntrospectionError::UnknownKey);
8691        }
8692        result_vec.insert(0, row);
8693        Ok(result_vec)
8694    }
8695
8696    /// Navigate the introspection tree using the given navigation_command, and also
8697    /// return the tree as an IntrospectionResult.
8698    pub fn do_introspect(
8699        &mut self,
8700        object: &dyn Introspect,
8701        navigation_command: IntrospectorNavCommand,
8702    ) -> Result<IntrospectionResult, IntrospectionError> {
8703        match &navigation_command {
8704            IntrospectorNavCommand::ExpandElement(_) => {}
8705            IntrospectorNavCommand::SelectNth { .. } => {}
8706            IntrospectorNavCommand::Nothing => {}
8707            IntrospectorNavCommand::Up => {
8708                if self.path.len() == 0 {
8709                    return Err(IntrospectionError::AlreadyAtTop);
8710                }
8711                self.path.pop();
8712            }
8713        }
8714        let frames = self.dive(0, object, navigation_command)?;
8715
8716        let mut total = 0;
8717        for frame in &frames {
8718            total += frame.keyvals.len();
8719        }
8720        let accum = IntrospectionResult {
8721            frames,
8722            cached_total_len: total,
8723        };
8724        Ok(accum)
8725    }
8726}