Next: , Previous: Implementation of XDR, Up: Implementation of XDR

4.2.1 XDR Type Representations

The XDR standard defines various basic data types and allows for the definition of compound data types (“structs”), fixed-size and variable-size arrays as well as “unions”. Fixed-size arrays and structs can actually be thought as the same type: Their size if known in advance and they are encoded as the succession of the data they contain. Thus, those types can be summarized as 4 great classes: “basic” types, variable-length arrays, structs and unions.

The (rpc xdr) module provides facilities to create Scheme objects representing XDR data types and to manipulate them. These Scheme objects, described below, are all immutable, i.e., they cannot be modified after creation.

— Scheme Procedure: make-xdr-basic-type name size type-pred encoder decoder [vector-encoder [vector-decoder]]

This returns an <xdr-basic-type> object describing a type whose encoding fits on size octets, and which is encoded/decoded using the encoder and decoder procedures. type-pred should be a predicate checking the validity of an input Scheme value for encoding into this type.

Optionally, vector-encoder and vector-decoder can be passed and should be procedures that efficiently encode/decode sequences of data items of this type (for instance, the vector decoder could use the bytevector->int-list procedure of the (r6rs bytevector) module to speed up decoding). The vector encoder is invoked as (vector-encoder type value bv index) while the vector decoder is invoked as (vector-decoder type count port).

Users should normally not need to define new basic types since all the basic types defined by XDR are already available in (rpc xdr types) (see XDR Standard Data Types). Thus, we will not describe its use further.

— Scheme Procedure: make-xdr-struct-type base-types

Return a new XDR struct type made of a sequence of XDR data items whose types are listed in base-types.

Struct types encode from/decode to Scheme lists whose length is that of base-types.

— Scheme Procedure: make-xdr-vector-type base-type max-element-count

Return an object describing an XDR variable-length array of elements of types base-type (again, an XDR type object). If max-element-count is a number, then it describes the maximum number of items of type base-type that are allow in actual arrays of this type. If base-type is #f, then arrays of this type may contain up to 2^32 - 1 items of type base-type.

Vector types are encoded from generalized vectors such as Scheme vectors, SRFI-4 vectors or strings (see Generalized Vectors). By default, vector types decode to vectors, but any other kind of generalized vector can be used: it only needs to be specified as the vector-decoder argument of make-xdr-basic-type for the corresponding base type. Of course, SRFI-4 vectors, for example, may only be used when an XDR integer vector with a matching integer range is expected.

If max-element-count is specified and a vector to be encoded contains more than max-element-count elements, then an &xdr-vector-size-exceeded-error error condition is raised. Likewise, if XDR data to be decoded describes vectors larger than max-element-count, this error condition is raised.

— Scheme Procedure: make-xdr-union-type discr-type discr/type-alist default-type

Return a new XDR discriminated union type, using discr-type as the discriminant type (which must be a 32-bit basic type) and discr/type-alist to select the “arm” type depending on the discriminant value. If no suitable value is found in discr/type-alist and default-type is not #f, then default type is used as the arm type.

Union types encode from/decode to Scheme pairs whose car is the discriminant's value and whose cdr is the actual union value.

— Scheme Procedure: xdr-union-arm-type union discriminant

Return the type that should be used for union's arm given discriminant (a Scheme value).

Sometimes, one may want to define recursive types, i.e., types that refer to themselves. This is particularly useful to implement lists. For example, in XDR language, a list of integers can be defined as follows:

     struct integer_list_t
       int x;
       integer_list_t *next;

This notation is a shortcut for the following structure:

     struct integer_list_t
       int x;
       union switch (bool opted)
         case TRUE:
           integer_list_t value;
         case FALSE:
       } next;

The integer_list_t type references itself. Defining it using our API seems impossible at first: one cannot pass a self-reference to make-xdr-struct-type (since the object is not yet created!), and the self-reference cannot be added after the fact since objects returned by make-xdr-struct-type are immutable.

The API addresses this problem by allowing thunks (zero-argument procedures) to be used as types. Together with Scheme's letrec recursive binding construct or a top-level define (see letrec), it makes it possible to create such recursive types:

     (letrec ((integer-list
                (list xdr-integer
                      (make-xdr-union-type xdr-boolean
                                           `((TRUE . ,(lambda ()
                                             (FALSE . ,xdr-void))

The trick here is that using the thunk effectively defers the evaluation of the self-reference1.

It is often useful to know the size in octets it takes to encode a given value according to an XDR type. However, as we just saw, the size of some XDR types (variable-length arrays and unions) cannot be known in advance: The encoding size depends on the actual value to encode. The following procedure allow the computation of the size of the XDR representation of some value.

— Scheme Procedure: xdr-type-size type value

Return the size (in octets) of type when applied to value. type must be an XDR type object returned by one of the above procedures, while value should be a Scheme value suitable for encoding with type.

The following section lists the standard XDR data types.


[1] This idea was inspired by Oleg Kiselyov's description of thunked parent pointers in SXML, which may be found at