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