Skip to content

Instantly share code, notes, and snippets.

@tomoima525
Forked from rust-play/playground.rs
Last active September 18, 2021 06:48
Show Gist options
  • Save tomoima525/1397a359da847390a685fd43cca28a4b to your computer and use it in GitHub Desktop.
Save tomoima525/1397a359da847390a685fd43cca28a4b to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
// Implementing Vector
pub struct ToyVec<T> {
elements: Box<[T]>,
len: usize,
}
// Reference type field requires lifetime specifier
pub struct Iter<'vec, T> {
elements: &'vec Box<[T]>,
len: usize,
pos: usize
}
// Set Trait boundary of Default to get the default value of T
impl<T: Default> ToyVec<T> {
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
elements: Self::allocate_in_heap(capacity),
len: 0
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn capacity(&self) -> usize {
self.elements.len()
}
// Passing mutable reference of self, so we are manipulating ToyVec
// Passing T type, meaning the ownership of element will move to this function then to ToyVec
pub fn push(&mut self, element: T) {
if self.len == self.capacity() {
self.grow();
}
self.elements[self.len] = element;
self.len += 1;
}
// Passing reference without mutable, so we are not manipulating ToyVec
// Function returns immutable reference which self owns or none
pub fn get(&self, index: usize) -> Option<&T> {
if index < self.len {
Some(&self.elements[index])
} else {
None
}
}
// This will show a compile error about life cycle
// When arguments have &self, then returned value has the same life cycle with self
// However default_value can have longer or shorter lifecycle.
// pub fn get_or(&self, index: usize, default_value: &T) -> &T {
// match self.get(index) {
// Some(v) => v,
// None => default_value
// }
// }
// life time specifier 'a will define the lifecycle
// self and default_value are borrowed until the return type is alive
pub fn get_or<'a>(&'a self, index: usize, default_value: &'a T) -> &'a T {
self.get(index).unwrap_or(default_value)
}
// Returns value along with ownership
pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
None
} else {
// Below fails with "cannot move out of `self.elements[_]` which is behind a mutable reference"
// this method can not move the value to v because &mut does not allow moving ownership
//
// let v = self.elements[self.len - 1];
// Instead we can replace with other value
let v = std::mem::replace(&mut self.elements[self.len], Default::default());
self.len -= 1;
Some(v)
}
}
// ToyVec's ownership is borrowed while this iterator exists
pub fn iter<'vec>(&'vec self) -> Iter<'vec, T> {
Iter {
elements: &self.elements,
len: self.len,
pos: 0,
}
}
fn grow(&mut self) {
if self.capacity() == 0 {
self.elements = Self::allocate_in_heap(1)
} else {
let new_allocation = Self::allocate_in_heap(self.capacity() * 2);
let old_allocation = std::mem::replace(&mut self.elements, new_allocation);
// move existing values to the new allocation
for (i, element) in old_allocation.into_vec().into_iter().enumerate() {
self.elements[i] = element;
}
}
}
fn allocate_in_heap(capacity: usize) -> Box<[T]> {
std::iter::repeat_with(Default::default)
.take(capacity)
.collect::<Vec<_>>()
.into_boxed_slice()
}
}
impl<'vec, T> Iterator for Iter<'vec, T> {
type Item = &'vec T;
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.len {
None
} else {
let res = Some(&self.elements[self.pos]);
self.pos += 1;
res
}
}
}
fn main() {
let mut v = ToyVec::new();
v.push("ABC".to_string());
v.push("DEF".to_string());
let mut iter = v.iter();
// this will fail since v is borrowed as immutable
// cannot borrow `v` as mutable because it is also borrowed as immutable
// v.push("HIJ".to_string());
// Return value drops inside assert_eq, so ownership is returned to v
assert_eq!(iter.next(), Some(&"ABC".to_string()));
// borrow value from v
let e0 = v.get(1);
assert_eq!(e0, Some(&"DEF".to_string()));
let default_value = &"OTHER".to_string();
let e1 = v.get_or(10, default_value);
assert_eq!(e1, &"OTHER".to_string());
let e2 = v.pop();
assert_eq!(e2.unwrap(), "DEF".to_string());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment