**char to str

С документацией по Rust на данный момент не очень, зато в почтовой рассылке rust-dev@mozilla.org на вопросы отвечают очень быстро. Пусть и дают примеры с ошибками
Сейчас я пишу враппер для libevent, правильнее сказать начал писать. С первой же функцией, которую я выбрал как наиболее простую и ни на что не завязанную, я натолкнулся на вопрос с преобразованием массива Си строк в массив Rust строк.
Для начала пишем прототип функции event_get_supported_methods из libevent и объясняем Rust с какой библиотекой линковаться.

import libc::c_char;

#[link_name = "event"]
native mod c {
    fn event_get_supported_methods() -> **libc::c_char;
}

Теперь сам метод, где нам требуется перекодировка:

fn re_get_supported_methods() -> [str] {
    let methods = c::event_get_supported_methods();
    let buflen = unsafe { buf_len( methods ) };
    let strs = unsafe {
        let cstrs: [*c_char] = vec::unsafe::from_buf(methods, buflen);
        vec::map(cstrs) {|cstr| str::unsafe::from_c_str(cstr) }
    };
    ret strs;
}

Пока что все довольно просто: получаем Си список, расчитываем количество элементов в нем и и производим его преобразования: сначала в Rust массив содержащий *c_char, а затем уже его конвертируем в массив Rust строк. Осталось привести реализацию функции расчета длинны массива Си указателей с завершающимся нулем. И тут натыкаемся еще на одну трудность: в текущей версии libcore нет функции расчета позиции искомого элемента для Си массивов, так что пишем и ее (position):

unsafe fn buf_len<T>(buf : **T) -> uint {
    position(buf){|i|
        i == ptr::null()
    }
}

unsafe fn position<T>(buf : **T, f:fn(*T) -> bool) -> uint {
    let mut offset = 0u;
    loop {
        if f(*ptr::offset(buf, offset)) {
            ret offset;
        } else {
            offset += 1u;
        }
    }
}

Как видно из последнего примера, в Rust есть поддержка шаблонов, которые тут зовутся generics-ами. Пока что они довольно куцинькие, но и последняя версия компилятора всего-то 0.2.

Leave a Reply