IDL data types

August 2, 2023

ID ice_idl_data_types

Primitive types

IDL supports the following primitive types:

  • SInt8, SInt16, SInt32, SInt64 (signed integer)
  • UInt8, UInt16, UInt32, UInt64 (unsigned integer)
  • Handle (value whose binary representation consists of multiple fields, including a handle field and a handle permissions mask field)
  • bytes<<size in bytes>> (byte buffer)
  • string<<size in bytes>> (string buffer)

A byte buffer is a memory area with a size that does not exceed the defined number of bytes. A string buffer is a byte buffer whose last byte is a terminating zero. The maximum size of a string buffer is a unit larger than the defined size due to the additional byte with the terminating zero. To transfer a byte buffer or string buffer via IPC, the amount of memory that is actually occupied by this buffer will be used.

For numeric types, you can declare named constants by using the reserved word const:

const UInt32 DeviceNameMax = 64;

const UInt32 HandleTypeUserLast = 0x0001FFFF;

Constants are used to avoid problems associated with "magic numbers". For example, if an IDL description defines constants for return codes of an interface method, you can interpret these codes without additional information when describing a policy.

In addition to primitive types, the IDL language supports composite types, such as unions, structures, arrays and sequences. In a definition of composite types, constants of primitive types may be applied as parameters (for example, to assign an array size).

The bytes<<size in bytes>> and string<<size in bytes>> constructs are used in definitions of composite types, signatures of interface methods, and when creating type aliases because they define anonymous types (types without a name).

Unions

A union lets you store different types of data in one memory area. In an IPC message, a union is provided with an additional tag field that lets you define which specific member of the union is used.

The following construct is used to define a union:

union <type name> {

<member type> <member name>;

...

}

Example of a union definition:

union ExitInfo {

UInt32 code;

ExceptionInfo exc;

}

Structures

The following construct is used to define a structure:

struct <type name> {

<field type> <field name>;

...

}

Example of a structure definition:

struct SessionEvqParams {

UInt32 count;

UInt32 align;

UInt32 size;

}

Arrays

The following construct is used to define an array:

array<<type of elements, number of elements>>

This construct is used in definitions of other composite types, signatures of interface methods, and when creating type aliases because it defines an anonymous type.

Sequences

A sequence is a variable-sized array. When defining a sequence, its maximum number of elements is specified. However, you can actually transmit less than this number (via IPC). In this case, only an amount of memory necessary for the transmitted elements will be used.

The following construct is used to define a sequence:

sequence<<type of elements, number of elements>>

This construct is used in definitions of other composite types, signatures of interface methods, and when creating type aliases because it defines an anonymous type.

Types based on composite types

Composite types can be used to define other composite types. The definition of an array or sequence can also be included in the definition of another type:

struct BazInfo {

array<UInt8, 100> a;

sequence<sequence<UInt32, 100>, 200> b;

string<100> c;

bytes<4096> d;

UInt64 e;

}

The definition of a union or structure cannot be included in the definition of another type. However, a previously described definition of a union or structure can be included in a type definition. This is done by indicating the names of the included types in the type definition:

union foo {

UInt32 value1;

UInt8 value2;

}

struct bar {

UInt32 a;

UInt8 b;

}

struct BazInfo {

foo x;

bar y;

}

Creating aliases of types

Type aliases make it more convenient to work with types. For example, type aliases can be used to assign mnemonic names to types that have abstract names. Assigned aliases for anonymous types also let you receive named types.

The following construct is used to create a type alias:

typedef <type name/anonymous type definition> <type alias>

Example of creating mnemonic aliases:

typedef UInt64 ApplicationId;

typedef Handle PortHandle;

Example of creating an alias for an array definition:

typedef array<UInt8, 4> IP4;

Example of creating an alias for a sequence definition:

const UInt32 MaxDevices = 8;

struct Device {

string<32> DeviceName;

UInt8 DeviceID;

}

typedef sequence<Device, MaxDevices> Devices;

Example of creating an alias for a union definition:

union foo {

UInt32 value1;

UInt8 value2;

}

typedef foo bar;

Defining anonymous types in signatures of interface methods

Anonymous types can be defined in signatures of interface methods.

Example of defining a sequence in an interface method signature:

Poll(in Generation generation,

in UInt32 timeout,

out Generation currentGeneration,

out sequence<Report, DeviceMax> report,

out UInt32 count,

out UInt32 rc);

Did you find this article helpful?
What can we do better?
Thank you for your feedback! You're helping us improve.
Thank you for your feedback! You're helping us improve.