Box and Memory Segments

Values in Cairo are stored in a memory segment called the execution segment by default. Values can be boxed (allocated in the boxed segment) by creating a Box<T>. A box is a smart pointer that provides a way to store a value of type T in Cairo VM's boxed segment, leaving only a pointer in the execution segment.

The main purposes of boxes are to:

  • Store values of arbitrary size while maintaining a fixed-size pointer
  • Enable recursive types that would otherwise have infinite size
  • Move large data structures efficiently by passing pointers instead of copying values

Boxed values can be accessed using the unbox() method or through the Deref trait, which retrieves the value from the boxed segment.

#[derive(Copy, Drop, Debug)]
struct Point {
    x: u128,
    y: u128,
}

// A Rectangle can be specified by where its top left and bottom right
// corners are in space
#[derive(Copy, Drop, Debug)]
struct Rectangle {
    top_left: Point,
    bottom_right: Point,
}

fn origin() -> Point {
    Point { x: 0, y: 0 }
}

fn boxed_origin() -> Box<Point> {
    // Allocate this point in the boxed segment, and return a pointer to it
    BoxTrait::new(Point { x: 0, y: 0 })
}

fn main() {
    // Values in execution segment
    let point: Point = origin();
    let _rectangle: Rectangle = Rectangle {
        top_left: origin(), bottom_right: Point { x: 3, y: 4 },
    };

    // Boxed segment allocated rectangle
    let boxed_rectangle: Box<Rectangle> = BoxTrait::new(
        Rectangle { top_left: origin(), bottom_right: Point { x: 3, y: 4 } },
    );

    // The output of functions can be boxed
    let boxed_point: Box<Point> = BoxTrait::new(origin());

    // Double indirection
    let _box_in_a_box: Box<Box<Point>> = BoxTrait::new(boxed_origin());

    // Two ways to access boxed values:
    // 1. Using unbox()
    let unboxed_point: Point = boxed_point.unbox();
    // 2. Using deref() trait
    let _derefed_point: Point = boxed_point.deref();

    // Print some values to demonstrate
    println!("point: {:?}", point);
    println!("unboxed_point: {:?}", unboxed_point);
    println!("boxed_rectangle: {:?}", boxed_rectangle.unbox().top_left);
}

Working with Recursive Types

One of the most important use cases for Box<T> is enabling recursive types. Without boxing, recursive types would have infinite size - as demonstrated in the Linked List example.