serialize.ss: Serializing Data
To load: (require (lib "serialize.ss"))
( SYNTAX
define-serializable-struct id )(field-id ···) [inspector-expr]
( SYNTAX
define-serializable-struct (id super-id) )(field-id ···) [inspector-expr]
Like define-struct, but instances of the structure type are
serializable with serialize. This form is allowed only at
the top level or in a module's top level (so that deserialization
information can be found later).
In addition to the bindings generated by define-struct,
define-serializable-struct binds
deserialize-info: to deserialization
information. Furthermore, in a module context, it automatically
id-v0provides this binding.
Naturally, define-serializable-struct enables the construction
of structure instances from places where make- is
not accessible, since deserialization must construct
instances. Furthermore, iddefine-serializable-struct provides
limited access to field mutation, but only for instances generated
through the deserialization information bound to
deserialize-info:. See
id-v0make-deserialize-info for more information.
The -v0 suffix on the deserialization enables future
versioning on the structure type through
define-serializable-struct/version.
When super-id is supplied, compile-time information bound to
super-id 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).
Example:
(define-serializable-struct point (x y)) (deserialize(serialize(make-point 1 2))) ; =>(make-point 1 2)
( SYNTAX
define-serializable-struct/version id vers-num )(field-id ···) ((other-vers-num make-proc-expr cycle-make-proc-expr)) [inspector-expr]
( SYNTAX
define-serializable-struct/version (id super-id) vers-num )(field-id ···) ((other-vers-num make-proc-expr cycle-make-proc-expr)) [inspector-expr]
Like define-serializable-struct, but the generated deserializer
binding is deserialize-info:. In
addition, id-vers-numdeserialize-info: is
bound for each id-other-vers-numother-vers-num.
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.
Example:
(define-serializable-struct point (x y)) (define ps (serialize(make-point 1 2))) (deserializeps) ; =>(make-point 1 2)(define x (make-point 1 10)) (set-point-x! x x) (define xs (serializex)) (deserializexs) ; =>x0, wherex0is(make-point x0 10)(define-serializable-struct/versions point 1 (x y z) ([0 ;; Constructor for simple v0 instances: (lambda (x y) (make-point x y 0)) ;; Constructor for v0 instance in a cycle: (lambda () (let ([p0 (make-point #f #f 0)]) (valuesp0 (lambda (p) (set-point-x! p0 (point-x p)) (set-point-y! p0 (point-y p))))))])) (deserialize(serialize(make-point 4 5 6))) ; =>(make-point 4 5 6)(deserializeps) ; =>(make-point 1 2 0)(deserializexs) ; =>x1, wherex1is(make-point x1 10 0)
Returns a value that encapsulates the value v. This value
includes only readable values, so it can be written to a stream with
write, later read from a stream using read, and
then converted to a value like the original using
deserialize. Serialization followed by deserialization
produces a value with the same graph structure and mutability as the
original value, but the serialized value is a plain tree (i.e., no
sharing).
The following kinds of values are serializable:
structures created through
define-serializable-structordefine-serializable-struct/version, or more generally structures with theprop:serializableproperty (seeprop:serializablefor more information);instances of classes defined with
define-serializable-classordefine-serializable-class(see section 4.7);booleans, numbers, characters, symbols, strings, byte strings, paths, void, and the empty list;
pairs, vectors, boxes, and hash tables; and
dateandarity-at-leaststructures.
Of course, 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.
Given a value v that was produced by serialize,
produces a value like the one given to serialize, including
the same graph structure and mutability.
A serialized representation v is a list of six elements:
A non-negative exact integer
s-countthat represents the number of distinct structure types represented in the serialized data.A list
s-typesof lengths-count, where each element represents a structure types. Each structure type is encoded as a pair. Theof the pair iscar#ffor 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 usingbytes->path) for a module that exports the structure's deserialization information. Theof the pair is the name of a binding (at the top level or exported from a module) for deserialization information. These two are used with eithercdrnamespace-variable-bindingordynamic-requireto obtain deserialization information. Seemake-deserialization-infofor more information on the binding's value.A non-negative exact integer,
g-countthat represents the number of graph points contained in the following list.A list
graphof lengthg-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
#ffor each of its fields. The content of the box indicates the shape of the value:a non-negative exact integer
ifor an instance of a structure type that is represented by theith element of thes-typeslist;'cfor a pair;'bfor a box;a pair whose
iscar'vand whoseis a non-negative exact integercdrsfor a vector of lengths; ora list whose first element is
'hand whose remaining elements are flags formake-hash-tablefor a hash table.'datefor adatestructure;'arity-at-leastfor anarity-at-leaststructure;
The
#f-filled value will be updated with content specified by the fifth element of the serialization listv.A non-box represents a serial value to be constructed immediately, and it is one of the following:
a boolean, number, character, symbol, or empty list, representing itself.
a string, representing an immutable string.
a byte string, representing an immutable byte string.
a pair whose
iscar'?and whoseis a non-negative exact integercdri; it represents the value constructed for theith element ofgraph, whereiis less than the position of this element withingraph.a pair whose
is a numbercari; it represents an instance of a structure type that is described by theith element of thes-typeslist. Theof the pair is a list of serials representing arguments to be provided to the structure type's deserializer.cdra pair whose
iscar'void, representing void.a pair whose
iscar'uand whoseis either a byte string or character string; it represents a mutable byte or character string.cdra pair whose
iscar'cand whoseis a pair of serials; it represents an immutable pair.cdra pair whose
iscar'c!and whoseis a pair of serials; it represents a mutable pair.cdra pair whose
iscar'vand whoseis a list of serials; it represents an immutable vector.cdra pair whose
iscar'v!and whoseis a list of serials; it represents a mutable vector.cdra pair whose
iscar'band whoseis a serial; it represents an immutable box.cdra pair whose
iscar'b!and whoseis a serial; it represents a mutable box.cdra pair whose
iscar'h, whoseis eithercadr'!or'-(mutable or immutable, respectively), whoseis a list of symbols to be used as flags forcaddrmake-hash-table, and whoseis a list of pairs, where thecdddrof each pair is a serial for a hash-table key and thecaris a serial for the corresponding value.cdra pair whose
iscar'dateand whoseis a list of serials; it represents acdrdatestructure.a pair whose
iscar'arity-at-leastand whoseis a serial; it represents ancdrarity-at-leaststructure.
A list of pairs, where the
of each pair is a non-negative exact integercariand theis a serial (as defined in the previous bullet). Each element represents an update to ancdrith element ofgraphsthat 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 ingraph.A final serial (as defined in the two bullets back) representing the result of
deserialize.
The result of deserialize shares no mutable values with the
argument to 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.
(make-deserialize-info make-proc cycle-make-proc) PROCEDURE
Produces a deserialization information record to be used by
deserialize. This information is normally tied to a
particular structure because the structure has a
prop:serializable property value that points to a top-level
variable or module-exported variable that is bound to deserialization
information.
The make-proc 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-proc 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-proc, and it
transfers the field values of this instance into x.
This property identifies structures and structure types that are
serializable. The property value should be constructed with
make-serialize-info.
(make-serialize-info to-vector-proc deserialize-id can-cycle? dir-path) PROCEDURE
Produces a value to be associated with a structure type through the
prop:serializable property. This value is used by
serialize.
The to-vector-proc 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. The
deserialize-id value can be an identifier syntax object, a
symbol, or a pair:
If
deserialize-idis an identifier, and if(produces a list, then the third element is used for the exporting module, otherwise the top-level is assumed. In either case,identifier-bindingdeserialize-id)is used to obtain the name of an exported identifier or top-level definition.syntax-eIf
deserialize-idis a symbol, it indicates a top-level variable that is named by the symbol.If
deserialize-idis a pair, themust be a symbol to name an exported identifier, and thecarmust be either a symbol or a module path index to specify the exporting module.cdr
See make-deserialize-info and deserialize for more
information.
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-path 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))
Returns #t if v appears to be serializable, without
checking the content of compound values, and #f otherwise.
See serialize for an enumeration of serializable values.