Точная настройка макета памяти в Rust?

Насколько мне известно, компилятору Rust разрешено упаковывать, изменять порядок и добавлять дополнения к каждому полю структуры. Как я могу указать точную схему памяти, если мне это нужно?

В С# у меня есть атрибут StructLayout, а в C/С++ я могу использовать различные расширения компилятора. Я могу проверить макет памяти, проверив смещение байтов ожидаемых значений.

Я хотел бы написать код OpenGL с использованием пользовательских шейдеров, которым требуется точная компоновка памяти. Есть ли способ сделать это, не жертвуя производительностью?

Ответы

Ответ 1

Как описано в руководство FFI, вы можете добавить атрибуты к структурам, чтобы использовать тот же макет, что и C:

#[repr(C)]
struct Object {
    a: i32,
    // other members
}

и у вас также есть возможность упаковать структуру:

#[repr(C, packed)]
struct Object {
    a: i32,
    // other members
}

И для обнаружения того, что макет памяти в порядке, вы можете инициализировать структуру и проверить, что смещения в порядке, отбрасывая указатели на целые числа:

#[repr(C, packed)]
struct Object {
    a: u8,
    b: u16,
    c: u32, // other members
}

fn main() {
    let obj = Object {
        a: 0xaa,
        b: 0xbbbb,
        c: 0xcccccccc,
    };
    let a_ptr: *const u8 = &obj.a;
    let b_ptr: *const u16 = &obj.b;
    let c_ptr: *const u32 = &obj.c;

    let base = a_ptr as usize;

    println!("a: {}", a_ptr as usize - base);
    println!("b: {}", b_ptr as usize - base);
    println!("c: {}", c_ptr as usize - base);
}

выходы:

a: 0
b: 1
c: 3

Ответ 2

Больше нет to_uint. В Rust 1.0 код может быть:

#[repr(C, packed)]
struct Object {
    a: i8,
    b: i16,
    c: i32, // other members
}

fn main() {
    let obj = Object {
        a: 0x1a,
        b: 0x1bbb,
        c: 0x1ccccccc,
    };

    let base = &obj as *const _ as usize;
    let a_off = &obj.a as *const _ as usize - base;
    let b_off = &obj.b as *const _ as usize - base;
    let c_off = &obj.c as *const _ as usize - base;

    println!("a: {}", a_off);
    println!("b: {}", b_off);
    println!("c: {}", c_off);
}