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() };