diff --git a/src/lib.rs b/src/lib.rs
index cf557092320b5facd328c7ad126967172b02eb30..c7b33ed8d44490aca9ef2cbdabfce64d5140b326 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -77,6 +77,7 @@
 //! ```
 
 #![deny(missing_docs)]
+#![deny(warnings)]
 #![feature(const_fn)]
 #![feature(const_unsafe_cell_new)]
 #![feature(core_intrinsics)]
diff --git a/src/ring_buffer/spsc.rs b/src/ring_buffer/spsc.rs
index 955d7744fdd6e32e8db302b570ae26581794e1c7..430dcd49a0df90c0f38df95267ab0d34394a22d2 100644
--- a/src/ring_buffer/spsc.rs
+++ b/src/ring_buffer/spsc.rs
@@ -1,5 +1,5 @@
 use core::marker::{PhantomData, Unsize};
-use core::ptr::{self, Shared};
+use core::ptr::{self, NonNull};
 
 use BufferFullError;
 use ring_buffer::RingBuffer;
@@ -12,11 +12,11 @@ where
     pub fn split(&mut self) -> (Producer<T, A>, Consumer<T, A>) {
         (
             Producer {
-                rb: unsafe { Shared::new_unchecked(self) },
+                rb: unsafe { NonNull::new_unchecked(self) },
                 _marker: PhantomData,
             },
             Consumer {
-                rb: unsafe { Shared::new_unchecked(self) },
+                rb: unsafe { NonNull::new_unchecked(self) },
                 _marker: PhantomData,
             },
         )
@@ -29,8 +29,8 @@ pub struct Consumer<'a, T, A>
 where
     A: Unsize<[T]>,
 {
-    // XXX do we need to use `Shared` (for soundness) here?
-    rb: Shared<RingBuffer<T, A>>,
+    // XXX do we need to use `NonNull` (for soundness) here?
+    rb: NonNull<RingBuffer<T, A>>,
     _marker: PhantomData<&'a ()>,
 }
 
@@ -70,8 +70,8 @@ pub struct Producer<'a, T, A>
 where
     A: Unsize<[T]>,
 {
-    // XXX do we need to use `Shared` (for soundness) here?
-    rb: Shared<RingBuffer<T, A>>,
+    // XXX do we need to use `NonNull` (for soundness) here?
+    rb: NonNull<RingBuffer<T, A>>,
     _marker: PhantomData<&'a ()>,
 }
 
diff --git a/src/string.rs b/src/string.rs
index cb616b983057de67d60954e36e99de99e5d193ce..4f8d07ba9746d988cc0ed00f50b0d360dfa4022d 100644
--- a/src/string.rs
+++ b/src/string.rs
@@ -3,9 +3,8 @@ use core::{fmt, ops, str};
 use core::str::Utf8Error;
 
 use {BufferFullError, Vec};
-//use core::ops::Deref;
 
-/// A String, backed by a fixed size array `heapless::Vec`
+/// A String backed by a fixed size `heapless::Vec`
 ///
 /// String: https://doc.rust-lang.org/std/string/struct.String.html
 
@@ -37,39 +36,6 @@ where
         String { vec: Vec::new() }
     }
 
-    /// Constructs a new, empty `String` backed by a `Vec<u8,[u8;N]>` from an `&str`.
-    ///
-    /// Cannot be called from a `static` context (not a `const fn`).
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use heapless::String;
-    ///
-    /// let s: String<[u8; 4]> = String::from("123");
-    /// assert!(s.len() == 3);
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics if capacity of the String would be exceeded.
-    ///
-    /// ``` should_panic
-    /// use heapless::String;
-    ///
-    /// let s: String<[_; 4]> = String::from("12345"); // <- Would `panic!`
-    /// ```
-    //
-    // Todo, Trait implementation?
-    #[inline]
-    pub fn from(s: &str) -> Self {
-        let mut new = String::new();
-        new.push_str(s).unwrap();
-        new
-    }
-
     /// Converts a vector of bytes to a `String`.
     ///
     /// A string slice ([`&str`]) is made of bytes ([`u8`]), and a vector of bytes
@@ -111,17 +77,16 @@ where
     /// ```
     #[inline]
     pub fn from_utf8(vec: Vec<u8, A>) -> Result<(String<A>), Utf8Error> {
-        {
-            let buffer: &[u8] = unsafe { vec.buffer.as_ref() };
-            str::from_utf8(&buffer[0..vec.len])?;
-        }
+        // validate input
+        str::from_utf8(&*vec)?;
+
         Ok(String { vec: vec })
     }
 
     /// Converts a vector of bytes to a `String` without checking that the
     /// string contains valid UTF-8.
     ///
-    /// See the safe version, [`from_utf8`], for more details.
+    /// See the safe version, `from_utf8`, for more details.
     #[inline]
     pub unsafe fn from_utf8_unchecked(vec: Vec<u8, A>) -> String<A> {
         String { vec: vec }
@@ -166,8 +131,7 @@ where
     /// ```
     #[inline]
     pub fn as_str(&self) -> &str {
-        let buffer: &[u8] = unsafe { self.vec.buffer.as_ref() };
-        unsafe { str::from_utf8_unchecked(&buffer[..self.vec.len]) }
+        unsafe { str::from_utf8_unchecked(&*self.vec) }
     }
 
     /// Converts a `String` into a mutable string slice.
@@ -185,12 +149,10 @@ where
     /// ```
     #[inline]
     pub fn as_mut_str(&mut self) -> &mut str {
-        let buffer: &mut [u8] = unsafe { self.vec.buffer.as_mut() };
-        unsafe { str::from_utf8_unchecked_mut(&mut buffer[..self.vec.len]) }
+        unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
     }
 
     /// Appends a given string slice onto the end of this `String`.
-    /// Returns with a Result<(), BufferFullError>.
     ///
     /// # Examples
     ///
@@ -207,23 +169,9 @@ where
     ///
     /// assert!(s.push_str("tender").is_err());
     /// ```
-    //
-    // TODO, should be implemented using `extend_from_slice` on Vec
-    // (this is not yet implemented in Vec, so we implement it here)
     #[inline]
-    pub fn push_str(&mut self, s: &str) -> Result<(), BufferFullError> {
-        let buffer: &mut [u8] = unsafe { self.vec.buffer.as_mut() };
-        let start = self.vec.len;
-        let new_len = start + s.len();
-        if new_len <= buffer.len() {
-            self.vec.len = new_len;
-            buffer[start..self.vec.len].copy_from_slice(
-                &s.as_bytes()[0..self.vec.len.saturating_sub(start)],
-            );
-            Ok(())
-        } else {
-            Err(BufferFullError)
-        }
+    pub fn push_str(&mut self, string: &str) -> Result<(), BufferFullError> {
+        self.vec.extend_from_slice(string.as_bytes())
     }
 
     /// Returns the maximum number of elements the String can hold
@@ -240,12 +188,10 @@ where
     /// ```
     #[inline]
     pub fn capacity(&self) -> usize {
-        let buffer: &[u8] = unsafe { self.vec.buffer.as_ref() };
-        buffer.len()
+        self.vec.capacity()
     }
 
     /// Appends the given [`char`] to the end of this `String`.
-    /// Assumes ch.len_utf8() == 1
     ///
     /// [`char`]: ../../std/primitive.char.html
     ///
@@ -268,7 +214,11 @@ where
     /// ```
     #[inline]
     pub fn push(&mut self, c: char) -> Result<(), BufferFullError> {
-        self.vec.push(c as u8)
+        match c.len_utf8() {
+            1 => self.vec.push(c as u8),
+            _ => self.vec
+                .extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()),
+        }
     }
 
     /// Returns a byte slice of this `String`'s contents.
@@ -350,8 +300,11 @@ where
     /// ```
     pub fn pop(&mut self) -> Option<char> {
         let ch = self.chars().rev().next()?;
-        let newlen = self.len() - ch.len_utf8();
-        self.vec.len = newlen;
+
+        // pop bytes that correspond to `ch`
+        for _ in 0..ch.len_utf8() {
+            self.vec.pop();
+        }
 
         Some(ch)
     }
@@ -376,7 +329,7 @@ where
     /// ```
     #[inline]
     pub fn is_empty(&self) -> bool {
-        self.vec.len == 0
+        self.len() == 0
     }
 
     /// Truncates this `String`, removing all contents.
@@ -418,7 +371,18 @@ where
     /// assert_eq!(a.len(), 3);
     /// ```
     pub fn len(&self) -> usize {
-        self.vec.len
+        self.vec.len()
+    }
+}
+
+impl<'a, A> From<&'a str> for String<A>
+where
+    A: Unsize<[u8]>,
+{
+    fn from(s: &'a str) -> Self {
+        let mut new = String::new();
+        new.push_str(s).unwrap();
+        new
     }
 }
 
@@ -437,14 +401,12 @@ where
     A: Unsize<[u8]>,
 {
     fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
-        self.push_str(s).unwrap();
-        Ok(())
+        self.push_str(s).map_err(|_| fmt::Error)
     }
 
-    // fn write_char(&mut self, c: char) -> Result<(), fmt::Error> {
-    //     self.push(c);
-    //     Ok(())
-    // }
+    fn write_char(&mut self, c: char) -> Result<(), fmt::Error> {
+        self.push(c).map_err(|_| fmt::Error)
+    }
 }
 
 impl<A> ops::Deref for String<A>
@@ -521,16 +483,18 @@ mod tests {
     use {String, Vec};
 
     #[test]
-
     fn debug() {
         extern crate std;
+
         use core::fmt::Write;
-        let mut s: String<[u8; 8]> = String::from("abcd");
+
+        let s: String<[u8; 8]> = String::from("abcd");
         let mut std_s = std::string::String::new();
-        write!(std_s, "{:?}", s);
+        write!(std_s, "{:?}", s).unwrap();
         assert_eq!("\"abcd\"", std_s);
     }
 
+    #[test]
     fn empty() {
         let s: String<[u8; 4]> = String::new();
         assert!(s.capacity() == 4);
@@ -587,12 +551,15 @@ mod tests {
     #[test]
     fn from_utf8_unchecked() {
         let mut v: Vec<u8, [u8; 8]> = Vec::new();
-        v.push(0).unwrap();
-        v.push(159).unwrap();
-        v.push(146).unwrap();
-        v.push(150).unwrap();
+        v.push(104).unwrap();
+        v.push(101).unwrap();
+        v.push(108).unwrap();
+        v.push(108).unwrap();
+        v.push(111).unwrap();
 
         let s = unsafe { String::from_utf8_unchecked(v) };
+
+        assert_eq!(s, "hello");
     }
 
     #[test]
diff --git a/src/vec.rs b/src/vec.rs
index 058b9765719bc59d09e53eb40fe1d3e5a5bf14a6..8dd4266e803167e4e256d0a89fd43af7d4a9a326 100644
--- a/src/vec.rs
+++ b/src/vec.rs
@@ -13,9 +13,9 @@ where
     // FIXME(rust-lang/rust#44580) use "const generics" instead of `Unsize`
     A: Unsize<[T]>,
 {
-    pub(crate) _marker: PhantomData<[T]>,
-    pub(crate) buffer: UntaggedOption<A>,
-    pub(crate) len: usize,
+    _marker: PhantomData<[T]>,
+    buffer: UntaggedOption<A>,
+    len: usize,
 }
 
 impl<T, A> Vec<T, A>
@@ -42,6 +42,36 @@ where
         self.truncate(0);
     }
 
+    /// Clones and appends all elements in a slice to the `Vec`.
+    ///
+    /// Iterates over the slice `other`, clones each element, and then appends
+    /// it to this `Vec`. The `other` vector is traversed in-order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use heapless::Vec;
+    ///
+    /// let mut vec = Vec::<u8, [u8; 8]>::new();
+    /// vec.push(1).unwrap();
+    /// vec.extend_from_slice(&[2, 3, 4]).unwrap();
+    /// assert_eq!(*vec, [1, 2, 3, 4]);
+    /// ```
+    pub fn extend_from_slice(&mut self, other: &[T]) -> Result<(), BufferFullError>
+    where
+        T: Clone,
+    {
+        if self.len() + other.len() > self.capacity() {
+            // won't fit in the `Vec`; don't modify anything and return an error
+            Err(BufferFullError)
+        } else {
+            for elem in other {
+                self.push(elem.clone())?
+            }
+            Ok(())
+        }
+    }
+
     /// 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() };