rust - What is the correct way to write `Vec<u16>` content to a file? -


i'm having trouble writing vec<u16> content file:

use std::fs::file; use std::io::{write, bufwriter}; use std::mem;  #[derive(debug, copy, clone, partialeq)] pub enum imageformat {     grayscale,     rgb32, }  #[derive(debug, copy, clone, partialeq)] pub struct imageheader {     pub width: usize,     pub height: usize,     pub format: imageformat, }  pub struct image {     pub header: imageheader,     pub data: vec<u16>, }  fn write_to_file(path: &str, img: &image) -> std::io::result<()> {     let f = try!(file::create(path));     let mut bw = bufwriter::new(f);     let slice = &img.data[..];     println!("before length: {}", slice.len());     let sl: &[u8];     unsafe {         sl = mem::transmute::<&[u16], &[u8]>(slice);     }     println!("after length: {}", sl.len());     try!(bw.write_all(sl));     return ok(()); }  fn main() {} 

since write_all() asks &[u8], i'm doing unsafe conversion of &[u16] &[u8]. because conversion not change slice length (slice.len() , sl.len() have same values), half of image data output file.

it better if don't need unsafe conversion or copying.

to directly you'd want use std::slice::from_raw_parts():

use std::slice; use std::mem;  fn main() {     let slice_u16: &[u16] = &*vec![1, 2, 3, 4, 5, 6];     println!("u16s: {:?}", slice_u16);      let slice_u8: &[u8] = unsafe {         slice::from_raw_parts(             slice_u16.as_ptr() *const u8,             slice_u16.len() * mem::size_of::<u16>(),         )     };      println!("u8s: {:?}", slice_u8); } 

it require unsafe because from_raw_parts() can't guarantee can pass valid pointer it, , can create slices arbitrary lifetime.

however, approach not potentially unsafe, not portable. when work integers larger 1 byte, endianness issues arise. if write file in way on x86 machine, read garbage on arm machine. proper way use libraries byteorder allow specify endianness explicitly:

extern crate byteorder;  use byteorder::{writebytesext, littleendian};  fn main() {     let slice_u16: &[u16] = &*vec![1, 2, 3, 4, 5, 6];     println!("u16s: {:?}", slice_u16);      let mut result: vec<u8> = vec::new();     &n in slice_u16 {         let _ = result.write_u16::<littleendian>(n);     }      println!("u8s: {:?}", result); } 

note i've used vec<u8> here, implements write, , write_u16() , other methods writebytesext trait defined on write, use these methods directly on bufwriter, example.

while may less efficient reinterpreting piece of memory, safe , portable.


Comments

Popular posts from this blog

c# - Validate object ID from GET to POST -

node.js - Custom Model Validator SailsJS -

php - Find a regex to take part of Email -