Push и Pop

Отлично. Мы можем инициализировать. Мы можем выделять память. Давайте теперь реализуем немного функциональности! Начнём с push. Все что ему нужно, это проверить можем ли мы расти, безусловно записать по следующему индексу элемент и увеличить длину.

Для записи нам надо быть осторожными с обращениями к памяти, в которую мы собираемся делать запись. В худшем случае - это настоящая неинициализированная память, полученная от аллокатора. В лучшем - это биты, оставшиеся от старых значений, которые уже удалились. Так или иначе, мы не можем проиндексировать её и разыменовать, потому что это приведёт к обращению к ней, как к правильному экземпляру типа T. Что хуже, foo[idx] = x попытается вызвать drop у старого значения foo[idx]!

Правильным путём будет сделать ptr::write, который вслепую заменяет значение по заданному адресу значением, которое мы предоставим. Никаких обращений не происходит.

Для push если старая длина (до его вызова) была 0, то записываем по 0-ому индексу. Итак, нам нужно сместиться на старое значение длины.

pub fn push(&mut self, elem: T) {
    if self.len == self.cap { self.grow(); }

    unsafe {
        ptr::write(self.ptr.as_ptr().add(self.len), elem);
    }

    // Не вызовет ошибку, потому что мы вызовем сначала OOM.
    self.len += 1;
}

Легко! Что насчёт pop? Хоть индекс и инициализирован во время доступа, Rust не позволит нам разыменовать место в памяти для вытаскивания значения, потому что это оставит память неинициализированной! Для этого нам нужно ptr::read, которая просто копирует байты из целевого адреса и интерпретирует их как значение типа T. Это оставит память по этому адресу логически неинициализированной, хотя на самом деле там отличный экземпляр типа T.

Для pop если старое значение длины 1, то мы хотим прочитать 0-й индекс. Итак, нам нужно сместиться на новое значение длины.

pub fn pop(&mut self) -> Option<T> {
    if self.len == 0 {
        None
    } else {
        self.len -= 1;
        unsafe {
            Some(ptr::read(self.ptr.as_ptr().add(self.len)))
        }
    }
}