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
-v0provide
s 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, id
define-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-num
deserialize-info:
is
bound for each id
-other-vers-num
other-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))) (deserialize
ps) ; =>(make-point 1 2)
(define x (make-point 1 10)) (set-point-x! x x) (define xs (serialize
x)) (deserialize
xs) ; =>x0
, wherex0
is(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)]) (values
p0 (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)
(deserialize
ps) ; =>(make-point 1 2 0)
(deserialize
xs) ; =>x1
, wherex1
is(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-struct
ordefine-serializable-struct/version
, or more generally structures with theprop:serializable
property (seeprop:serializable
for more information);instances of classes defined with
define-serializable-class
ordefine-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
date
andarity-at-least
structures.
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-count
that represents the number of distinct structure types represented in the serialized data.A list
s-types
of lengths-count
, where each element represents a structure types. Each structure type is encoded as a pair. The
of the pair iscar
#f
for a structure whose deserialization information is defined at the top level, otherwise it is a quoted module path for a module that exports the structure's deserialization information. The
of 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 eithercdr
namespace-variable-binding
ordynamic-require
to obtain deserialization information. Seemake-deserialization-info
for more information on the binding's value.A non-negative exact integer,
g-count
that represents the number of graph points contained in the following list.A list
graph
of 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
#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 thei
th element of thes-types
list;'c
for a pair;'b
for a box;a pair whose
iscar
'v
and whose
is a non-negative exact integercdr
s
for a vector of lengths
; ora list whose first element is
'h
and whose remaining elements are flags formake-hash-table
for a hash table.'date
for adate
structure;'arity-at-least
for anarity-at-least
structure;
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 whose
is a non-negative exact integercdr
i
; it represents the value constructed for thei
th element ofgraph
, wherei
is less than the position of this element withingraph
.a pair whose
is a numbercar
i
; it represents an instance of a structure type that is described by thei
th element of thes-types
list. The
of the pair is a list of serials representing arguments to be provided to the structure type's deserializer.cdr
a pair whose
iscar
'void
, representing void.a pair whose
iscar
'u
and whose
is either a byte string or character string; it represents a mutable byte or character string.cdr
a pair whose
iscar
'c
and whose
is a pair of serials; it represents an immutable pair.cdr
a pair whose
iscar
'c!
and whose
is a pair of serials; it represents a mutable pair.cdr
a pair whose
iscar
'v
and whose
is a list of serials; it represents an immutable vector.cdr
a pair whose
iscar
'v!
and whose
is a list of serials; it represents a mutable vector.cdr
a pair whose
iscar
'b
and whose
is a serial; it represents an immutable box.cdr
a pair whose
iscar
'b!
and whose
is a serial; it represents a mutable box.cdr
a pair whose
iscar
'h
, whose
is eithercadr
'!
or'-
(mutable or immutable, respectively), whose
is a list of symbols to be used as flags forcaddr
make-hash-table
, and whose
is a list of pairs, where thecdddr
of each pair is a serial for a hash-table key and thecar
is a serial for the corresponding value.cdr
a pair whose
iscar
'date
and whose
is a list of serials; it represents acdr
date
structure.a pair whose
iscar
'arity-at-least
and whose
is a serial; it represents ancdr
arity-at-least
structure.
A list of pairs, where the
of each pair is a non-negative exact integercar
i
and the
is a serial (as defined in the previous bullet). Each element represents an update to ancdr
i
th element ofgraphs
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 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-id
is 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-binding
deserialize-id)
is used to obtain the name of an exported identifier or top-level definition.syntax-e
If
deserialize-id
is a symbol, it indicates a top-level variable that is named by the symbol.If
deserialize-id
is a pair, the
must be a symbol to name an exported identifier, and thecar
must 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.