mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-09-28 13:00:26 +00:00
commit
94a8e50858
@ -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
|
||||
|
@ -77,6 +77,7 @@
|
||||
//! ```
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_unsafe_cell_new)]
|
||||
#![feature(core_intrinsics)]
|
||||
|
@ -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 ()>,
|
||||
}
|
||||
|
||||
|
131
src/string.rs
131
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]
|
||||
|
36
src/vec.rs
36
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() };
|
||||
|
Loading…
x
Reference in New Issue
Block a user