The following kinds of values are serializable:
structures that instantiate prefab structure types;
pairs, mutable pairs, vectors, boxes, and hash tables;
module path index values.
Serialization succeeds for a compound value, such as a pair, only if all content of the value is serializable. If a value given to serialize is not completely serializable, the exn:fail:contract exception is raised.
See deserialize for information on the format of serialized data.
A serialized representation v is a list of six or seven elements:
An optional list '(1) or '(2) that represents the version of the serialization format. If the first element of a representation is not a list, then the version is 0. Version 1 adds support for mutable pairs, and version 2 adds support for unreadable symbols.
A non-negative exact integer s-count that represents the number of distinct structure types represented in the serialized data.
A list s-types of length s-count, where each element represents a structure type. Each structure type is encoded as a pair. The car of the pair is #f for a structure whose deserialization information is defined at the top level, otherwise it is a quoted module path or a byte string (to be converted into a platform-specific path using bytes->path) for a module that exports the structure’s deserialization information. The cdr of the pair is the name of a binding (at the top level or exported from a module) for deserialization information, either a symbol or a string representing an unreadable symbol. These two are used with either namespace-variable-binding or dynamic-require to obtain deserialization information. See make-deserialization-info for more information on the binding’s value. See also deserialize-module-guard.
A non-negative exact integer, g-count that represents the number of graph points contained in the following list.
A list graph of length g-count, where each element represents a serialized value to be referenced during the construction of other serialized values. Each list element is either a box or not:
A box represents a value that is part of a cycle, and for deserialization, it must be allocated with #f for each of its fields. The content of the box indicates the shape of the value:
a non-negative exact integer i for an instance of a structure type that is represented by the ith element of the s-types list;
'c for a pair, which fails on deserialization (since pairs are immutable; this case does not appear in output generated by serialize);
'm for a mutable pair;
'b for a box;
a list whose first element is 'h and whose remaining elements are symbols that determine the hash-table type:
The #f-filled value will be updated with content specified by the fifth element of the serialization list v.
A non-box represents a serial value to be constructed immediately, and it is one of the following:
a boolean, number, character, interned symbol, or empty list, representing itself.
a string, representing an immutable string.
a byte string, representing an immutable byte string.
a pair whose car is '? and whose cdr is a non-negative exact integer i; it represents the value constructed for the ith element of graph, where i is less than the position of this element within graph.
a pair whose car is a number i; it represents an instance of a structure type that is described by the ith element of the s-types list. The cdr of the pair is a list of serials representing arguments to be provided to the structure type’s deserializer.
a pair whose car is 'void, representing #<void>.
a pair whose car is 'h, whose cadr is either '! or '- (mutable or immutable, respectively), whose caddr is a list of symbols (containing 'equal, 'weak, both, or neither) that determines the hash table type, and whose cdddr is a list of pairs, where the car of each pair is a serial for a hash-table key and the cdr is a serial for the corresponding value.
A list of pairs, where the car of each pair is a non-negative exact integer i and the cdr is a serial (as defined in the previous bullet). Each element represents an update to an ith element of graph that was specified as a box, and the serial describes how to construct a new value with the same shape as specified by the box. The content of this new value must be transferred into the value created for the box in graph.
A final serial (as defined in the two bullets back) representing the result of deserialize.
If a value provided to serialize is a simple tree (i.e., no sharing), then the fourth and fifth elements in the serialized representation will be empty.
all structure types whose deserializers are accessed with distinct module paths are actually distinct types;
all structure types are transparent; and
all structure instances contain only the constituent values recorded in each of v1 and v2.
|→ (module-path? symbol? . -> . void?)|
|(deserialize-module-guard guard) → void?|
|guard : (module-path? symbol? . -> . void?)|
Serialization only supports cycles involving the created structure type when all fields are mutable (or when the cycle can be broken through some other mutable value).
In addition to the bindings generated by struct, serializable-struct binds deserialize-info:id-v0 to deserialization information. Furthermore, in a module context, it automatically provides this binding.
The serializable-struct form enables the construction of structure instances from places where id is not accessible, since deserialization must construct instances. Furthermore, serializable-struct provides limited access to field mutation, but only for instances generated through the deserialization information bound to deserialize-info:id-v0. See make-deserialize-info for more information.
The -v0 suffix on the deserialization enables future versioning on the structure type through serializable-struct/version.
When a supertype is supplied in maybe-super is supplied, compile-time information bound to the supertype identifier must include all of the supertype’s field accessors. If any field mutator is missing, the structure type will be treated as immutable for the purposes of marshaling (so cycles involving only instances of the structure type cannot be handled by the deserializer).
|> (serializable-struct point (x y))|
|> (point-x (deserialize (serialize (point 1 2))))|
Each make-proc-expr should produce a procedure, and the procedure should accept as many argument as fields in the corresponding version of the structure type, and it produce an instance of id. Each graph-make-proc-expr should produce a procedure of no arguments; this procedure should return two values: an instance x of id (typically with #f for all fields) and a procedure that accepts another instance of id and copies its field values into x.
|> (serializable-struct point (x y) #:mutable #:transparent)|
|> (define ps (serialize (point 1 2)))|
|> (deserialize ps)|
(point 1 2)
|> (define x (point 1 10))|
|> (set-point-x! x x)|
|> (define xs (serialize x))|
|> (deserialize xs)|
#0=(point #0# 10)
|> (deserialize (serialize (point 4 5 6)))|
(point 4 5 6)
|> (deserialize ps)|
(point 1 2 0)
|> (deserialize xs)|
#0=(point #0# 10 0)
|(make-deserialize-info make cycle-make) → any|
|make : procedure?|
|cycle-make : (-> (values any/c procedure?))|
The make procedure should accept as many argument as the structure’s serializer put into a vector; normally, this is the number of fields in the structure. It should return an instance of the structure.
The cycle-make procedure should accept no arguments, and it should return two values: a structure instance x (with dummy field values) and an update procedure. The update procedure takes another structure instance generated by the make, and it transfers the field values of this instance into x.
|prop:serializable : property?|
|to-vector : (any/c . -> . vector?)|
|can-cycle? : any/c|
|dir : path-string?|
The to-vector procedure should accept a structure instance and produce a vector for the instance’s content.
The deserialize-id value indicates a binding for deserialize information, to either a module export or a top-level definition. It must be one of the following:
If deserialize-id is an identifier, and if (identifier-binding deserialize-id) produces a list, then the third element is used for the exporting module, otherwise the top-level is assumed. In either case, syntax-e is used to obtain the name of an exported identifier or top-level definition.
If deserialize-id is a symbol, it indicates a top-level variable that is named by the symbol.
The can-cycle? argument should be false if instances should not be serialized in such a way that deserialization requires creating a structure instance with dummy field values and then updating the instance later.
The dir argument should be a directory path that is used to resolve a module reference for the binding of deserialize-id. This directory path is used as a last resort when deserialize-id indicates a module that was loaded through a relative path with respect to the top level. Usually, it should be (or (current-load-relative-directory) (current-directory)).