How to slice a large Vec as &[u8]?

后端 未结 2 799
悲哀的现实
悲哀的现实 2021-01-19 06:33

I don\'t know how to convert a Vec into a &[u8] slice.

fn main() {
    let v: Vec = vec![1; 100_000_000];         


        
相关标签:
2条回答
  • 2021-01-19 06:39

    Since Rust 1.30, the best solution is to use slice::align_to:

    fn main() {
        let v: Vec<i32> = vec![1; 8];
    
        let (head, body, tail) = unsafe { v.align_to::<u8>() };
        assert!(head.is_empty());
        assert!(tail.is_empty());
    
        println!("{:#x?}", body);
    }
    

    This properly handles the cases where the alignment of the first type and the second type do not match. In this example, I ensure that the alignment of the i32 is greater than that of the u8 via the assert! statements.


    I took @swizards answer and ran with it a bit to get the other side of the coin - reading the vector back in:

    use std::fs::File;
    use std::io::{Read, Write};
    use std::{mem, slice};
    
    fn as_u8_slice(v: &[i32]) -> &[u8] {
        let element_size = mem::size_of::<i32>();
        unsafe { slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * element_size) }
    }
    
    fn from_u8(v: Vec<u8>) -> Vec<i32> {
        let data = v.as_ptr();
        let len = v.len();
        let capacity = v.capacity();
        let element_size = mem::size_of::<i32>();
    
        // Make sure we have a proper amount of capacity (may be overkill)
        assert_eq!(capacity % element_size, 0);
        // Make sure we are going to read a full chunk of stuff
        assert_eq!(len % element_size, 0);
    
        unsafe {
            // Don't allow the current vector to be dropped
            // (which would invalidate the memory)
            mem::forget(v);
    
            Vec::from_raw_parts(
                data as *mut i32,
                len / element_size,
                capacity / element_size,
            )
        }
    }
    
    fn do_write(filename: &str, v: &[i32]) {
        let mut f = File::create(filename).unwrap();
        f.write_all(as_u8_slice(v)).unwrap();
    }
    
    fn do_read(filename: &str) -> Vec<i32> {
        let mut f = File::open(filename).unwrap();
        let mut bytes = Vec::new();
    
        f.read_to_end(&mut bytes).unwrap();
    
        from_u8(bytes)
    }
    
    fn main() {
        let v = vec![42; 10];
        do_write("vector.dump", &v);
        let v2 = do_read("vector.dump");
    
        assert_eq!(v, v2);
        println!("{:?}", v2)
    }
    
    0 讨论(0)
  • 2021-01-19 07:02

    You can use std::slice::from_raw_parts:

    let v_bytes: &[u8] = unsafe {
        std::slice::from_raw_parts(
            v.as_ptr() as *const u8,
            v.len() * std::mem::size_of::<i32>(),
        )
    };
    

    Following the comments on this answer, you should wrap this code in a function and have the return value borrow the input, so that you use the borrow checker as far as possible:

    fn as_u8_slice(v: &[i32]) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts(
                v.as_ptr() as *const u8,
                v.len() * std::mem::size_of::<i32>(),
            )
        }
    }
    
    0 讨论(0)
提交回复
热议问题