Ответ зависит от того, хорошо ли вы копируете данные. Если копирование не является для вас проблемой, вы можете сделать что-то вроде этого:
let img: Vec<Rgb<u8>> = ...;
let buf: Vec<u8> = img.iter().flat_map(|rgb| rgb.data.iter()).cloned().collect();
Если вы хотите выполнить преобразование без копирования, сначала нам нужно убедиться, что ваши исходные и конечные типы действительно имеют одинаковую структуру памяти. Rust дает очень мало гарантий относительно структуры памяти структур. В настоящее время он даже не гарантирует, что структура с одним элементом имеет ту же структуру памяти, что и сам элемент.
В данном конкретном случае макет памяти Rust не имеет значения, поскольку Rgb
определяется как
#[repr(C)]
pub struct Rgb<T: Primitive> {
pub data: [T; 3],
}
Атрибут #[repr(C)]
указывает, что структура памяти структуры должна совпадать с эквивалентной структурой Си. Структура памяти C не полностью указана в стандарте C, но в соответствии с рекомендациями по небезопасному коду , существуют некоторые правила, действующие для "большинства" платформ:
- Порядок полей сохраняется.
- Первое поле начинается со смещения 0.
- Предполагая, что структура не упакована, смещение каждого поля выравнивается по обязательному выравниванию ABI для типа этого поля, возможно создавая неиспользуемые биты заполнения.
- Общий размер структуры округляется до общего выравнивания.
Как указано в комментариях, стандарт C теоретически допускает дополнительное заполнение в конце структуры. Однако сама библиотека изображений Piston предполагает, что срез данных канала имеет ту же структуру памяти, что и Rgb
struct , поэтому, если вы находитесь на платформе, где это предположение не выполняется, все ставки все равно отключены (и я не смог найти никаких доказательств того, что такая платформа существует).
Rust гарантирует, что массивы, срезы и векторы плотно упакованы, и что структуры и массивы имеют выравнивание, равное максимальному выравниванию их элементов. Вместе с предположением, что расположение Rgb
соответствует правилам, которые я цитирую выше, это гарантирует, что Rgb<u8>
действительно выложен как три последовательных байта в памяти, и что Vec<Rgb<u8>>
действительно является последовательным, плотно упакованным буфер значений RGB, поэтому наше преобразование безопасно. Нам все еще нужно использовать небезопасный код, чтобы написать его:
let p = img.as_mut_ptr();
let len = img.len() * mem::size_of::<Rgb<u8>>();
let cap = img.capacity() * mem::size_of::<Rgb<u8>>();
mem::forget(img);
let buf: Vec<u8> = unsafe { Vec::from_raw_parts(p as *mut u8, len, cap) };
Если вы хотите защитить от случая, когда в конце Rgb
имеется дополнительный отступ, вы можете проверить, действительно ли size_of::<Rgb<u8>>()
равен 3. Если это так, вы можете использовать небезопасную версию без копирования, в противном случае Вы должны использовать первую версию выше.