Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Mapping for Structured Types

Generated structs have public members. This design choice is intentional for data-carrying types:

  • Simplicity: Avoids the need for getter/setter methods in three variants (by-value, by-reference, by-mutable-reference) for each field.
  • Ergonomics: Enables direct field access and struct literal syntax.
  • Consistency: Matches Rust conventions for plain data structures.
  • Flexibility: Allows partial initialization with ..Default::default().
  • Partial moves: Enables moving individual fields out of a struct without consuming the entire value.
#![allow(unused)]
fn main() {
// Rust
let _ = MyStruct {
    my_int: 5,
    my_str: "my string".into(),
    my_vec: vec![1, 2, 3],
};
}

In addition, this plays nicely alongside the Default trait: users can specify some values, whilst defaulting the rest. For example:

#![allow(unused)]
fn main() {
let _ = MyStruct {
    my_int: 5,
    ..Default::default()
};
}

The variables that were not named in such a construct will be filled in with the values acquired from the default function, i.e. the default values specified in IDL.

Derived Traits

All generated types (struct, enum, union, bitmask, exception) automatically derive a set of Rust traits. Some traits are always derived, while others are conditionally derived based on recursive type analysis.

Always Derived

The following traits are always derived for all generated types:

TraitPurpose
CloneEnables deep copying of values
DebugEnables formatting with {:?}
PartialEqEnables equality comparison (==, !=)
PartialOrdEnables ordering comparison (<, >, etc)

Conditionally Derived

The compiler performs a recursive analysis of each type to determine whether additional traits can be derived. This analysis examines all members, parent types, and nested types to make the determination.

Triviality Analysis (Copy)

A type is considered trivial if it consists only of:

  • Primitive types (bool, integers, char)
  • Arrays of trivial types
  • Other trivial user-defined types

A type is not trivial if it contains:

  • String or bounded/unbounded string types
  • Vec (sequences)
  • BTreeMap (maps)
  • Recursive/circular types
  • Any, Fixed, or interface types

Trivial types derive Copy, which enables bitwise copying without explicit .clone() calls.

Total Order Analysis (Eq, Ord, Hash)

A type has total order if all its members can form a well-ordered set. This requires that all member types satisfy:

  • The type is not a floating-point type (f32, f64)
  • All nested/member types also have total order

Floating-point types break total order because NaN != NaN, which violates the reflexivity property required by Eq.

Types with total order derive:

TraitPurpose
EqGuarantees reflexive equality (x == x)
OrdEnables total ordering comparisons
HashEnables use as keys in hash-based collections

Default Trait

All generated types implement the Default trait. The implementation delegates to the new() constructor, which initializes all members to their default values (either from @default annotations or type-specific defaults).

#![allow(unused)]
fn main() {
impl Default for MyStruct {
    fn default() -> Self {
        Self::new()
    }
}
}

Summary Table

TraitCondition
CopyType is trivial (no heap allocation, not recursive)
CloneAlways
DebugAlways
DefaultAlways (via new() constructor)
EqType has total order (no floating-point members)
PartialEqAlways
OrdType has total order (no floating-point members)
PartialOrdAlways
HashType has total order (no floating-point members)

Example

// IDL - trivial type with total order
struct Point {
    int32 x;
    int32 y;
};

// IDL - non-trivial type with total order
struct Person {
    string name;
    int32 age;
};

// IDL - non-trivial type without total order
struct Measurement {
    float value;
    string unit;
};
#![allow(unused)]
fn main() {
// Trivial + total order: derives Copy, Eq, Ord, Hash
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Point {
    pub x: i32,
    pub y: i32,
}

// Non-trivial + total order: derives Eq, Ord, Hash but not Copy
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Person {
    pub name: String,
    pub age: i32,
}

// Non-trivial + no total order: only base traits
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Measurement {
    pub value: f32,
    pub unit: String,
}
}

Example

// IDL
struct MyStruct {
    unsigned long my_int;
    string my_str;
    sequence<int32> my_vec;
};
#![allow(unused)]
fn main() {
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct MyStruct {
    pub my_int: u32,
    pub my_str: String,
    pub my_vec: Vec<i32>,
}

impl MyStruct {
    pub fn new() -> Self {
        Self {
            my_int: 0,
            my_str: String::new(),
            my_vec: Vec::new(),
        }
    }
}

impl Default for MyStruct {
    fn default() -> Self {
        Self::new()
    }
}
}

Nested Types

Nested or scoped types will be placed inside a module with the name of the parent scope.

// IDL
struct MyA {
    struct MyB {
        struct MyC {};
    };
};
#![allow(unused)]
fn main() {
// Rust
struct MyA {};

pub mod my_a {
    struct MyB {};

    pub mod my_b {
        struct MyC {};
    };
};
}

Inheritance

Rust does not support inheritance. Following the IDL specification, fields from base types will be copied into the derived type.

// IDL
struct Parent {
    int64 parent_field;
};

struct Derived : Parent {
    int64 derived_field;
};
#![allow(unused)]
fn main() {
// Rust
pub struct Parent {
    pub parent_field: i64,
}

pub struct Derived {
    pub parent_field: i64,
    pub derived_field: i64,
}
}