17: refactor String impl r=japaric a=japaric
This commit is contained in:
bors[bot] 2018-03-01 19:25:06 +00:00
commit 94a8e50858
5 changed files with 104 additions and 108 deletions

View File

@ -1,23 +1,21 @@
set -euxo pipefail
main() {
case $TARGET in
thumb*m-none-eabi)
local vers=0.3.8
# install latest Xargo
local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/xargo \
| cut -d/ -f3 \
| grep -E '^v[0-9.]+$' \
| sort --version-sort \
| tail -n1)
curl -LSfs https://japaric.github.io/trust/install.sh | \
sh -s -- \
--force \
--git japaric/xargo \
--target x86_64-unknown-linux-musl \
--tag $tag
cargo install --list | grep "xargo v$vers" || \
( cd .. && cargo install xargo -f --vers $vers )
rustup component list | grep 'rust-src.*installed' || \
rustup component add rust-src
;;
x86_64-unknown-linux-gnu)
;;
*)
# unhandled case
exit 1
;;
esac
rustup component list | grep 'rust-src.*installed' || \
rustup component add rust-src
}
main

View File

@ -77,6 +77,7 @@
//! ```
#![deny(missing_docs)]
#![deny(warnings)]
#![feature(const_fn)]
#![feature(const_unsafe_cell_new)]
#![feature(core_intrinsics)]

View File

@ -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 ()>,
}

View File

@ -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]

View File

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