Next steps for the unsafe code guidelines

Responding to your "unsafe code in the wild" thread here so as not to contaminate it:

This looks like a case of missing abstractions and I'm sure it's not the only one. In this case, a write-only UninitializedVec<T> abstraction would probably help. Something like:

#![feature(untagged_unions)]

use std::ops::{Index, IndexMut};
use std::ptr::drop_in_place;

pub struct UninitializedVec<T: Sized> {
    data: *mut T,
    len: usize,
    capacity: usize,
}

impl<T: Sized> UninitializedVec<T> {
    // All the normal methods except that they operate over `Uninit<T>` instead of `T`...
    // And:
    pub unsafe fn into_vec(self) -> Vec<T> {
        Vec::from_raw_parts(self.data, self.len, self.capacity)
    }
}

impl<T: Sized> Index<usize> for UninitializedVec<T> {
    type Output = Uninit<T>;
    fn index(&self, idx: usize) -> &Uninit<T> {
        unsafe {
            assert!(idx < self.len, "out of bounds");
            &*(self.data.offset(idx as isize) as *const Uninit<T>)
        }
    }
}

impl<T: Sized> IndexMut<usize> for UninitializedVec<T> {
    fn index_mut(&mut self, idx: usize) -> &mut Uninit<T> {
        unsafe {
            assert!(idx < self.len, "out of bounds");
            &mut *(self.data.offset(idx as isize) as *mut Uninit<T>)
        }
    }
}

// I assume the alignment/size will match T...
#[allow(unions_with_drop_fields)]
pub union Uninit<T> {
    inited: T,
}

impl<T> Uninit<T> {
    /// Set to `value`. This will forget the existing value, if any.
    pub fn set(&mut self, value: T) {
        unsafe {
            self.inited = value;
        }
    }
    /// Set to `value` dropping the existing one.
    pub unsafe fn replace(&mut self, value: T) {
        drop_in_place(&mut self.inited);
        self.inited = value;
    }
    pub unsafe fn get_unchecked(&self) -> &T {
        &self.inited
    }
    pub unsafe fn get_mut_unchecked(&mut self) -> &mut T {
        &mut self.inited
    }
}