Элементы языка (lang items)

Замечание: многие элементы языка предоставляются контейнерами в стандартной поставке Rust, а у самих элементов языка нестабильный интерфейс. Рекомендуется использовать официально распространяемые контейнеры, вместо того, чтобы определять свои собственные элементы языка.

У компилятора rustc есть некоторые подключаемые операции, т.е. функционал, не встроенный жёстко в язык, а реализованный в библиотеках и специально помеченный как элемент языка. Метка — это атрибут #[lang="..."]. Есть различные значения ..., т.е. разные «элементы языка».

Например, для указателей Box нужны два элемента языка — для выделения памяти и для освобождения. Вот программа, не использующая стандартную библиотеку, и реализующая Box через malloc и free:

#![feature(lang_items, box_syntax, start, no_std, libc)]
#![no_std]

extern crate libc;

extern {
    fn abort() -> !;
}

#[lang = "owned_box"]
pub struct Box<T>(*mut T);

#[lang="exchange_malloc"]
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
    let p = libc::malloc(size as libc::size_t) as *mut u8;

    // malloc завершился ошибкой
    if p as usize == 0 {
        abort();
    }

    p
}
#[lang="exchange_free"]
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
    libc::free(ptr as *mut libc::c_void)
}

#[start]
fn main(argc: isize, argv: *const *const u8) -> isize {
    let x = box 1;

    0
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }

Заметьте, что exchange_malloc должен возвращать допустимый указатель, поэтому он производит проверку внутри и делает abort, если она не прошла.

Ниже перечислены другие возможности, предоставляемые элементами языка:

  • перегружаемые операторы через типажи: типажи, соответствующие ==, <, разыменованию (*), + и другим операторам, помечены как элементы языка; конкретно эти типажи помечены как eq, ord, deref и add;
  • раскрутка стека и общая ошибка; это элементы eh_personality, fail и fail_bounds_check;
  • типажи в модуле std::marker, используемые чтобы помечать различные типы; элементы send, sync и copy;
  • типы-метки и индикаторы вариантности из std::marker; это элементы covariant_type, contravariant_lifetime и другие.

Элементы языка загружаются компилятором лениво, т.е. если программа не использует Box, вам не нужно определять элементы exchange_malloc и exchange_free. rustc выдаст ошибку, если элемент языка необходим, но не найден ни в текущем контейнере, ни в его зависимостях.