diff --git a/CHANGELOG.md b/CHANGELOG.md
index 63644e83bea9b5fee8572bdd27dbbbf734065bfa..90c05302f39ef98388d8ac5f7a2461446c45dacc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,8 +7,27 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 ## [Unreleased]
 
+## [v0.2.0] - 2017-11-22
+
+### Added
+
+- A single producer single consumer mode to `RingBuffer`.
+
+- A `truncate` method to `Vec`.
+
+### Changed
+
+- [breaking-change] Both `Vec::new` and `RingBuffer::new` no longer require an initial value. The
+  signature of `new` is now `const fn() -> Self`.
+
+- [breaking-change] The error type of all operations that may fail has changed from `()` to
+  `BufferFullError`.
+
+- Both `RingBuffer` and `Vec` now support arrays of *any* size for their backup storage.
+
 ## [v0.1.0] - 2017-04-27
 
 - Initial release
 
-[Unreleased]: https://github.com/japaric/heapless/compare/v0.1.0...HEAD
+[Unreleased]: https://github.com/japaric/heapless/compare/v0.2.0...HEAD
+[v0.2.0]: https://github.com/japaric/heapless/compare/v0.1.0...v0.2.0
diff --git a/src/ring_buffer/mod.rs b/src/ring_buffer/mod.rs
index 0ae68a7c909c67b0f5f044e8336d7a1da33196f9..faa5f0bbff6081c9d8434b054b347b28ebe6da2c 100644
--- a/src/ring_buffer/mod.rs
+++ b/src/ring_buffer/mod.rs
@@ -6,9 +6,8 @@ use core::{intrinsics, ptr};
 
 use untagged_option::UntaggedOption;
 
-use BufferFullError;
-
 pub use self::spsc::{Consumer, Producer};
+use BufferFullError;
 
 mod spsc;
 
diff --git a/src/ring_buffer/spsc.rs b/src/ring_buffer/spsc.rs
index 4260baec7b143a32f3a0f13c37c88f9cd1ac02fd..955d7744fdd6e32e8db302b570ae26581794e1c7 100644
--- a/src/ring_buffer/spsc.rs
+++ b/src/ring_buffer/spsc.rs
@@ -1,5 +1,5 @@
-use core::ptr::{self, Shared};
 use core::marker::{PhantomData, Unsize};
+use core::ptr::{self, Shared};
 
 use BufferFullError;
 use ring_buffer::RingBuffer;
@@ -89,6 +89,10 @@ where
         let buffer: &mut [T] = unsafe { rb.buffer.as_mut() };
 
         let tail = rb.tail.load_relaxed();
+        // NOTE we could replace this `load_acquire` with a `load_relaxed` and this method would be
+        // sound on most architectures but that change would result in UB according to the C++
+        // memory model, which is what Rust currently uses, so we err on the side of caution and
+        // stick to `load_acquire`. Check issue google#sanitizers#882 for more details.
         let head = rb.head.load_acquire();
         let next_tail = (tail + 1) % n;
         if next_tail != head {
diff --git a/src/vec.rs b/src/vec.rs
index 9140cde1d14caa18682e83de5a84e5a94d468465..e1b91ecb47b67618aff18a1c740ae961bd673dc3 100644
--- a/src/vec.rs
+++ b/src/vec.rs
@@ -37,6 +37,11 @@ where
         buffer.len()
     }
 
+    /// Clears the vector, removing all values.
+    pub fn clear(&mut self) {
+        self.truncate(0);
+    }
+
     /// Removes the last element from a vector and return it, or `None` if it's empty
     pub fn pop(&mut self) -> Option<T> {
         let buffer: &[T] = unsafe { self.buffer.as_ref() };
@@ -67,6 +72,20 @@ where
             Err(BufferFullError)
         }
     }
+
+    /// Shortens the vector, keeping the first `len` elements and dropping the rest.
+    pub fn truncate(&mut self, len: usize) {
+        unsafe {
+            // drop any extra elements
+            while len < self.len {
+                // decrement len before the drop_in_place(), so a panic on Drop
+                // doesn't re-drop the just-failed value.
+                self.len -= 1;
+                let len = self.len;
+                ptr::drop_in_place(self.get_unchecked_mut(len));
+            }
+        }
+    }
 }
 
 impl<T, A> Drop for Vec<T, A>