ONC+ Developer's Guide

Discriminated Unions

The XDR library supports discriminated unions. A discriminated union is a C union and an enum_t value that selects an “arm” of the union.

struct xdr_discrim {
  	enum_t value;
  	bool_t (*proc)();
};

bool_t
 xdr_union(xdrs, dscmp, unp, arms, defaultarm)
   XDR *xdrs;
   enum_t *dscmp;
   char *unp;
   struct xdr_discrim *arms;
  	bool_t (*defaultarm)(); /* may equal NULL */ 

First the routine translates the discriminant of the union located at *dscmp. The discriminant is always an enum_t. Next the union located at *unp is translated. The parameter arms is a pointer to an array of xdr_discrim structures. Each structure contains an ordered pair of [value,proc]. If the union's discriminant is equal to the associated value, then the proc is called to translate the union. The end of the xdr_discrim structure array is denoted by a routine of value NULL (0). If the discriminant is not found in the arms array, then the defaultarm() procedure is called if it is nonnull. Otherwise the routine returns FALSE.

Discriminated Union Example

Suppose the type of a union is integer, character pointer (a string), or a gnumbers structure. Also, assume the union and its current type are declared in a structure. The declaration is:

enum utype {INTEGER=1, STRING=2, GNUMBERS=3};
struct u_tag {
   enum utype utype;	/* the union's discriminant */
   union {
      int ival;
      char *pval;
      struct gnumbers gn;
   } uval;
};  

The following code example constructs an XDR procedure to deserialize the discriminated union.


Example A–12 XDR Discriminated Union

struct xdr_discrim u_tag_arms[4] = {
 	{INTEGER, xdr_int},
 	{GNUMBERS, xdr_gnumbers}
 	{STRING, xdr_wrapstring},
 	{__dontcare__, NULL}
 	/* always terminate arms with a NULL xdr_proc */
 }

bool_t
xdr_u_tag(xdrs, utp)
 	XDR *xdrs;
 	struct u_tag *utp;
{
 	return(xdr_union(xdrs, &utp->utype, &utp->uval,
	       u_tag_arms, NULL));
}

The routine xdr_gnumbers() was presented previously in XDR Library. The default arm parameter to xdr_union(), the last parameter, is NULL in this example. Therefore, the value of the union's discriminant can legally take on only values listed in the u_tag_arms array. Example A–12 also demonstrates that the elements of the arm's array do not need to be sorted.

The values of the discriminant can be sparse, though in Example A–12 they are not. Make a practice of assigning explicitly integer values to each element of the discriminant's type. This practice both documents the external representation of the discriminant and guarantees that different C compilers emit identical discriminant values.