13.9 Serialization

► |  | The Racket Reference

1 | Language Model
2 | Notation for Documentation
3 | Syntactic Forms
4 | Datatypes
5 | Structures
6 | Classes and Objects
7 | Units
8 | Contracts
9 | Pattern Matching
10 | Control Flow
11 | Concurrency and Parallelism
12 | Macros
13 | Input and Output
14 | Reflection and Security
15 | Operating System
16 | Memory Management
17 | Unsafe Operations
18 | Running Racket
| Bibliography
| Index

▼ | 13 | Input and Output

13.1 | Ports
13.2 | Byte and String Input
13.3 | Byte and String Output
13.4 | Reading
13.5 | Writing
13.6 | Pretty Printing
13.7 | Reader Extension
13.8 | Printer Extension
13.9 | Serialization
13.10 | Fast-Load Serialization
13.11 | Cryptographic Hashing

► | 13.9 | Serialization

13.9.1 | Serialization Structures

On this page:

serializable?
serialize
deserialize
serialized=?
deserialize-module-guard
serializable-struct
define-serializable-struct
serializable-struct/ versions
define-serializable-struct/ versions
make-deserialize-info
prop: serializable
make-serialize-info
13.9.1`` Serialization Structures

top contents ← prev up next →

#### 13.9`` Serialization🔗ℹ

(require racket/serialize) | package: base

The bindings documented in this section are provided by the racket/serialize library, not racket/base or racket.

> procedure (serializable? v) → boolean?
> v : any/c

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.

> > procedure
> > (serialize |
> > |  | v |
> > | [ | #:relative-directory relative-to |
> > |  | #:deserialize-relative-directory deserialize-relative-to]) |
> → any
> v : serializable?
> | relative-to |  | : |  |
> (or/c (and/c path? complete-path?)
> (cons/c (and/c path? complete-path?)
> (and/c path? complete-path?))
> #f)
> |  | = |  | #f
> | deserialize-relative-to |  | : |  |
> (or/c (and/c path? complete-path?)
> (cons/c (and/c path? complete-path?)
> (and/c path? complete-path?))
> #f)
> |  |  | = |  | relative-to

Returns a value that encapsulates the value v. This value includes only readable values, so it can be written to a stream with write or s-exp->fasl, later read from a stream using read or fasl->s-exp, 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 serializable-struct or serializable-struct/versions, or more generally structures with the prop:serializable property (see prop:serializable for more information);

- prefab structures;

- instances of classes defined with define-serializable-class or define-serializable-class*;

- booleans, numbers, characters, interned symbols, unreadable symbols, keywords, strings, byte strings, paths (for a specific convention), regexp values, #<void>, and the empty list;

- pairs, mutable pairs, vectors, flvectors, fxvectors, boxes, hash tables, sets, and treelists;

- date, date*, arity-at-least and srcloc structures; and

- 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.

If v contains a cycle (i.e., a collection of objects that are all reachable from each other), then v can be serialized only if the cycle includes a mutable value, where a prefab structure counts as mutable only if all of its fields are mutable.

If relative-to is not #f, then paths to serialize that extend the path in relative-to are recorded in relative and platform-independent form. The possible values and treatment of relative-to are the same as for current-write-relative-directory.

If deserialize-relative-to is not #f, then any paths to deserializers as extracted via prop:serializable are recorded in relative form. Note that relative-to and deserialize-relative-to are independent, but deserialize-relative-to defaults to relative-to.

> > > The serialize and deserialize functions currently do not handle certain cyclic values that read and write can handle, such as '#0=(#0#).

See deserialize for information on the format of serialized data.

Changed in version 6.5.0.4 of package base: Added keywords and regexp values as serializable.
Changed in version 7.0.0.6: Added the #:relative-directory and #:deserialize-relative-directory arguments.

> procedure (deserialize v) → any
> v : any/c

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 or seven elements:

- An optional list '(1), '(2), '(3), or '(4) 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, version 2 adds support for unreadable symbols, version 3 adds support for date* structures, and version 4 adds support for paths that are meant to be relative to the deserialization directory.

- 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, a byte string (to be converted into a platform-specific path using bytes->path) for a module that exports the structure’s deserialization information, or a relative path element list for a module to be resolved with respect to current-load-relative-directory or (as a fallback) current-directory; the list-of-relative-elements form is produced by serialize when the #:deserialize-relative-directory argument is not #f. 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-deserialize-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 pair whose car is 'v and whose cdr is a non-negative exact integer s for a vector of length s;

    - a list whose first element is 'h and whose remaining elements are symbols that determine the hash-table type:

      - 'equal — (make-hash)

      - 'equal 'weak — (make-weak-hash)

      - 'weak — (make-weak-hasheq)

      - no symbols — (make-hasheq)

    - 'date* for a date* structure, which fails on deserialization (since dates are immutable; this case does not appear in output generated by serialize);

    - 'date for a date structure, which fails on deserialization (since dates are immutable; this case does not appear in output generated by serialize);

    - 'arity-at-least for an arity-at-least structure, which fails on deserialization (since arity-at-least are immutable; this case does not appear in output generated by serialize); or

    - 'mpi for a module path index, which fails on deserialization (since a module path index is immutable; this case does not appear in output generated by serialize).

    - 'srcloc for a srcloc structure, which fails on deserialization (since srclocs are immutable; this case does not appear in output generated by serialize).

    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 'q and whose cdr is an immutable value; it represents the quoted value.

    - a pair whose car is 'f; it represents an instance of a prefab structure type. The cadr of the pair is a prefab structure type key, and the cddr is a list of serials representing the field values.

    - a pair whose car is 'void, representing #<void>.

    - a pair whose car is 'su and whose cdr is a character string; it represents an unreadable symbol.

    - a pair whose car is 'u and whose cdr is either a byte string or character string; it represents a mutable byte or character string.

    - a pair whose car is 'p and whose cdr is a byte string; it represents a path using the serializer’s path convention (deprecated in favor of 'p+).

    - a pair whose car is 'p+, whose cadr is a byte string, and whose cddr is one of the possible symbol results of system-path-convention-type; it represents a path using the specified convention.

    - a pair whose car is 'p* and whose cdr is a list of byte strings represents a relative path; it will be converted by deserialization based on current-load-relative-directory, falling back to current-directory.

    - a pair whose car is 'c and whose cdr is a pair of serials; it represents an immutable pair.

    - a pair whose car is 'c! and whose cdr is a pair of serials; it represents a pair (but formerly represented a mutable pair), and does not appear in output generated by serialize.

    - a pair whose car is 'm and whose cdr is a pair of serials; it represents a mutable pair.

    - a pair whose car is 'v and whose cdr is a list of serials; it represents an immutable vector.

    - a pair whose car is 'v! and whose cdr is a list of serials; it represents a mutable vector.

    - a pair whose car is 'vl and whose cdr is a list of serials; it represents a flvector.

    - a pair whose car is 'vx and whose cdr is a list of serials; it represents a fxvector.

    - a pair whose car is 'b and whose cdr is a serial; it represents an immutable box.

    - a pair whose car is 'b! and whose cdr is a serial; it represents a mutable box.

    - 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 pair whose car is 'date* and whose cdr is a list of serials; it represents a date* structure.

    - a pair whose car is 'date and whose cdr is a list of serials; it represents a date structure.

    - a pair whose car is 'arity-at-least and whose cdr is a serial; it represents an arity-at-least structure.

    - a pair whose car is 'mpi and whose cdr is a pair; it represents a module path index that joins the paired values.

    - a pair whose car is 'srcloc and whose cdr is a list of serials; it represents a srcloc structure.

- 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.

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.

> procedure (serialized=? v1 v2) → boolean?
> v1 : any/c
> v2 : any/c

Returns #t if v1 and v2 represent the same serialization information.

More precisely, it returns the same value that (equal? (deserialize v1) (deserialize v2)) would return if

- 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.

> parameter (deserialize-module-guard)
> | → |  |
> (-> module-path? symbol?
> (or/c void? (cons/c module-path? symbol?)))
> (deserialize-module-guard guard) → void?
> | guard |  | : |  |
> (-> module-path? symbol?
> (or/c void? (cons/c module-path? symbol?)))

A parameter whose value is called by deserialize before dynamically loading a module via dynamic-require. The two arguments provided to the procedure are the same as the arguments to be passed to dynamic-require. The procedure can raise an exception to disallow the dynamic-require.

The procedure can optionally return a pair containing a module-path and symbol. If returned, deserialize will use them as arguments to dynamic-require instead.

Changed in version 6.90.0.30 of package base: Adds optional return values for bindings.

> > syntax
> > (serializable-struct id maybe-super (field ...)
> > struct-option ...)

Like 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).

Serialization supports cycles involving the created structure type only 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 in a deserialize-info submodule using module+.

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.

Beware that the previous paragraph means that if a serializable struct is exported via contract-out, for example, the contracts are not checked during deserialization. Consider using struct-guard/c instead.

The -v0 suffix on the deserialization enables future versioning on the structure type through serializable-struct/versions.

When a supertype is supplied as maybe-super, 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).

Examples:

> > (serializable-struct point (x y))
> > (point-x (deserialize (serialize (point 1 2))))
> 1

> > syntax
> > (define-serializable-struct id-maybe-super (field ...)
> > struct-option ...)

Like serializable-struct, but with the supertype syntax and default constructor name of define-struct.

> > syntax
> > (serializable-struct/versions id maybe-super vers (field ...)
> > (other-version-clause ...)
> > struct-option ...)
> other-version-clause |  | = |  |
> (other-vers make-proc-expr
> cycle-make-proc-expr)

Like serializable-struct, but the generated deserializer binding is deserialize-info: id-vvers. In addition, deserialize-info: id-vother-vers is bound for each other-vers. The vers and each other-vers must be a literal, exact, nonnegative integer.

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 produces an instance of id. Each cycle-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.

Examples:

> > (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)
> > (serializable-struct/versions point 1 (x y z)
> ([0
> ; Constructor for simple v0 instances:
> (lambda (x y) (point x y 0))
> ; Constructor for v0 instance in a cycle:
> (lambda ()
> (let ([p0 (point #f #f 0)])
> (values
> p0
> (lambda (p)
> (set-point-x! p0 (point-x p))
> (set-point-y! p0 (point-y p))))))])
> #:mutable #:transparent)
> > (deserialize (serialize (point 4 5 6)))
> (point 4 5 6)
> > (deserialize ps)
> (point 1 2 0)
> > (deserialize xs)
> #0=(point #0# 10 0)

> > syntax
> > (define-serializable-struct/versions id-maybe-super vers (field ...)
> > (other-version-clause ...)
> > struct-option ...)

Like serializable-struct/versions, but with the supertype syntax and default constructor name of define-struct.

> procedure (make-deserialize-info make cycle-make) → any
> make : procedure?
> cycle-make : (-> (values any/c 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 procedure should accept as many arguments 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.

> value prop:serializable : property?

This property identifies structures and structure types that are serializable. The property value should be constructed with make-serialize-info.

> > procedure
> > (make-serialize-info |  | to-vector |  |  |  |
> > |  | deserialize-id |  |  |  |
> > |  | can-cycle? |  |  |  |
> > |  | dir) |  | → |  | any
> to-vector : (any/c . -> . vector?)
> | deserialize-id |  | : |  |
> (or identifier?
> symbol?
> (cons/c symbol?
> module-path-index?)
> (-> any/c))
> can-cycle? : any/c
> dir : path-string?

Produces a value to be associated with a structure type through the prop:serializable property. This value is used by serialize.

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. Before trying an exporting module directly, its deserialize-info submodule is tried; the module itself is tried if no deserialize-info submodule is available or if the export is not found. 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.

- If deserialize-id is a pair, the car must be a symbol to name an exported identifier, and the cdr must be a module path index to specify the exporting module.

- If deserialize-id is a procedure, then it is applied during serialization and its result is used for deserialize-id.

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 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)).

Changed in version 7.0.0.6 of package base: Allow deserialize-id to be a procedure.

Examples:

> > (struct pie (type)
> #:mutable
> #:property prop:serializable
> (make-serialize-info
> (λ (this)
> (vector (pie-type this)))
> 'pie-beam
> #t
> (or (current-load-relative-directory) (current-directory))))
> > (define pie-beam
> (make-deserialize-info
> (λ (type)
> (pie type))
> (λ ()
> (define pie-pattern (pie 'transporter-error))
> (values pie-pattern
> (λ (type)
> (set-pie-type! pie-pattern type))))))
> > (define original-pie
> (pie 'apple))
> > original-pie
> #<pie>
> > (define pie-in-transit
> (serialize original-pie))
> > pie-in-transit
> '((3) 1 ((#f . pie-beam)) 0 () () (0 apple))
> > (define beamed-up-pie
> (deserialize pie-in-transit))
> > beamed-up-pie
> #<pie>
> > (pie-type beamed-up-pie)
> 'apple
> > (equal? beamed-up-pie original-pie)
> #f

##### 13.9.1`` Serialization Structures🔗ℹ

(require racket/serialize-structs) | package: base

The racket/serialize-structs module provides only prop:serializable, make-serialize-info, make-deserialize-info, which is useful for minimizing dependencies with supporting serialization.

Added in version 8.15.0.3 of package base.

top contents ← prev up next →