From d0cde267b108dc7600ce9cc87dc0d398ba537862 Mon Sep 17 00:00:00 2001 From: Thomas Bahn Date: Thu, 22 Dec 2016 16:43:32 +0100 Subject: [PATCH 1/5] refactor: move extern crate core to lib.rs --- src/ascii_char.rs | 8 +++----- src/ascii_str.rs | 6 ++---- src/lib.rs | 2 ++ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/ascii_char.rs b/src/ascii_char.rs index 05a81b4..1bb281e 100644 --- a/src/ascii_char.rs +++ b/src/ascii_char.rs @@ -1,8 +1,6 @@ -extern crate core; - -use self::core::mem::transmute; -use self::core::cmp::Ordering; -use self::core::{fmt, char}; +use core::mem::transmute; +use core::cmp::Ordering; +use core::{fmt, char}; #[cfg(feature = "std")] use std::error::Error; #[cfg(feature = "std")] diff --git a/src/ascii_str.rs b/src/ascii_str.rs index ff2e0ed..7825d65 100644 --- a/src/ascii_str.rs +++ b/src/ascii_str.rs @@ -1,7 +1,5 @@ -extern crate core; - -use self::core::{fmt, mem}; -use self::core::ops::{Index, IndexMut, Range, RangeTo, RangeFrom, RangeFull}; +use core::{fmt, mem}; +use core::ops::{Index, IndexMut, Range, RangeTo, RangeFrom, RangeFull}; #[cfg(feature = "std")] use std::error::Error; #[cfg(feature = "std")] diff --git a/src/lib.rs b/src/lib.rs index 7ec55ae..b555a90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate core; + mod free_functions; mod ascii_char; mod ascii_str; From fd5df669930a7268256578223140456bfaaa7619 Mon Sep 17 00:00:00 2001 From: Thomas Bahn Date: Thu, 22 Dec 2016 18:23:13 +0100 Subject: [PATCH 2/5] feat: More uses for mutable ascii string slices --- src/ascii_str.rs | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/ascii_str.rs b/src/ascii_str.rs index 7825d65..9883c40 100644 --- a/src/ascii_str.rs +++ b/src/ascii_str.rs @@ -8,43 +8,56 @@ use std::ascii::AsciiExt; use ascii_char::AsciiChar; #[cfg(feature = "std")] use ascii_string::AsciiString; +use iterators::{Bytes, SplitWhitespace}; /// AsciiStr represents a byte or string slice that only contains ASCII characters. /// /// It wraps an `[AsciiChar]` and implements many of `str`s methods and traits. /// -/// It can be created by a checked conversion from a `str` or `[u8]`, -/// or borrowed from an `AsciiString`. +/// It can be created by a checked conversion from a `str` or `[u8]`, or borrowed from an +/// `AsciiString`. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AsciiStr { slice: [AsciiChar], } impl AsciiStr { - /// Coerces into an `AsciiStr` slice. + /// Coerces `s` into an `AsciiStr` slice. pub fn new + ?Sized>(s: &S) -> &AsciiStr { s.as_ref() } - /// Converts `&self` to a `&str` slice. + /// Converts the ascii string slice to a UTF-8 string slice. #[inline] pub fn as_str(&self) -> &str { unsafe { mem::transmute(&self.slice) } } - /// Converts `&self` into a byte slice. + /// Converts the ascii string slice to a mutable UTF-8 string slice. + #[inline] + pub fn as_mut_str(&mut self) -> &mut str { + unsafe { mem::transmute(&mut self.slice) } + } + + /// Converts the ascii string slice into a byte slice. #[inline] pub fn as_bytes(&self) -> &[u8] { unsafe { mem::transmute(&self.slice) } } - /// Returns the entire string as slice of `AsciiChar`s. + /// Converts the ascii string slice into a mutable byte slice. + #[inline] + pub fn as_mut_bytes(&mut self) -> &mut [u8] { + unsafe { mem::transmute(&mut self.slice) } + } + + /// Returns the entire ascii string slice as slice of `AsciiChar`s. #[inline] pub fn as_slice(&self) -> &[AsciiChar] { &self.slice } - /// Returns the entire string as mutable slice of `AsciiChar`s. + /// Returns the entire ascii string slice as mutable slice of `AsciiChar`s. #[inline] pub fn as_mut_slice(&mut self) -> &mut [AsciiChar] { &mut self.slice @@ -235,12 +248,24 @@ impl AsRef<[u8]> for AsciiStr { self.as_bytes() } } +impl AsMut<[u8]> for AsciiStr { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + self.as_mut_bytes() + } +} impl AsRef for AsciiStr { #[inline] fn as_ref(&self) -> &str { self.as_str() } } +impl AsMut for AsciiStr { + #[inline] + fn as_mut(&mut self) -> &mut str { + self.as_mut_str() + } +} impl AsRef<[AsciiChar]> for AsciiStr { #[inline] fn as_ref(&self) -> &[AsciiChar] { From 55aa5a4d7b6a07690b818048f97110a75ed90729 Mon Sep 17 00:00:00 2001 From: Thomas Bahn Date: Thu, 22 Dec 2016 18:23:59 +0100 Subject: [PATCH 3/5] feat: `split_at()` and `split_at_mut()` --- src/ascii_str.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/src/ascii_str.rs b/src/ascii_str.rs index 9883c40..842db2e 100644 --- a/src/ascii_str.rs +++ b/src/ascii_str.rs @@ -1,4 +1,4 @@ -use core::{fmt, mem}; +use core::{fmt, mem, slice}; use core::ops::{Index, IndexMut, Range, RangeTo, RangeFrom, RangeFull}; #[cfg(feature = "std")] use std::error::Error; @@ -150,6 +150,72 @@ impl AsciiStr { self.len() == 0 } + /// Divide one string slice into two at an index. + /// + /// The argument, `mid`, should be a byte offset from the start of the string. The two slices + /// returned go from the start of the string slice to `mid`, and from `mid` to the end of the + /// string slice. + /// + /// To get mutable string slices instead, see the `split_at_mut()` method. + /// + /// # Panics + /// + /// Panics if `mid` is beyond the end of the string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use ascii::AsciiStr; + /// let s = AsciiStr::from_ascii("Per Martin-Lof").unwrap(); + /// let (first, last) = s.split_at(3); + /// + /// assert_eq!("Per", first.as_str()); + /// assert_eq!(" Martin-Lof", last.as_str()); + /// ``` + pub fn split_at(&self, mid: usize) -> (&AsciiStr, &AsciiStr) { + assert!(mid <= self.len()); + (&self[..mid], &self[mid..]) + } + + /// Divide one mutable string slice into two at an index. + /// + /// The argument, `mid`, should be a byte offset from the start of the string. The two slices + /// returned go from the start of the string slice to `mid`, and from `mid` to the end of the + /// string slice. + /// + /// To get immutable string slices instead, see the `split_at()` method. + /// + /// # Panics + /// + /// Panics if `mid` is beyond the end of the string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use ascii::{AsMutAsciiStr, AsciiStr}; + /// let mut s = String::from("Per Martin-Lof"); + /// let (first, last) = s.as_mut_ascii_str().unwrap().split_at_mut(3); + /// + /// assert_eq!("Per", first.as_str()); + /// assert_eq!(" Martin-Lof", last.as_str()); + /// ``` + pub fn split_at_mut(&mut self, mid: usize) -> (&mut AsciiStr, &mut AsciiStr) { + let len = self.len(); + assert!(mid <= len); + unsafe { + let ptr = self.as_mut_ptr(); + // This now has three mutable references pointing at the same memory. `self`, the rvalue + // ret.0, and the rvalue ret.1. `self` is never used after `let ptr = ...`, and so one + // can treat it as "dead", and therefore, you only have two real mutable slices. + (slice::from_raw_parts_mut(ptr, mid).as_mut_ascii_str_unchecked(), + slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid).as_mut_ascii_str_unchecked()) + } + } + /// Returns an ASCII string slice with leading and trailing whitespace removed. /// /// # Examples From 71c4d482efc8a25bd3a7e2b95320b54ac3db338c Mon Sep 17 00:00:00 2001 From: Thomas Bahn Date: Thu, 22 Dec 2016 18:25:03 +0100 Subject: [PATCH 4/5] feat: Iterators over characters --- src/ascii_str.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/ascii_str.rs b/src/ascii_str.rs index 842db2e..2861e4c 100644 --- a/src/ascii_str.rs +++ b/src/ascii_str.rs @@ -1,4 +1,5 @@ use core::{fmt, mem, slice}; +use core::slice::{Iter, IterMut}; use core::ops::{Index, IndexMut, Range, RangeTo, RangeFrom, RangeFull}; #[cfg(feature = "std")] use std::error::Error; @@ -8,7 +9,6 @@ use std::ascii::AsciiExt; use ascii_char::AsciiChar; #[cfg(feature = "std")] use ascii_string::AsciiString; -use iterators::{Bytes, SplitWhitespace}; /// AsciiStr represents a byte or string slice that only contains ASCII characters. /// @@ -620,6 +620,25 @@ impl AsMutAsciiStr for str { } } +impl<'a> IntoIterator for &'a AsciiStr { + type Item = &'a AsciiChar; + type IntoIter = Iter<'a, AsciiChar>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.slice.iter() + } +} +impl<'a> IntoIterator for &'a mut AsciiStr { + type Item = &'a mut AsciiChar; + type IntoIter = IterMut<'a, AsciiChar>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.slice.iter_mut() + } +} + #[cfg(test)] mod tests { From a8c8548b5ba9a93ff3afff6f8e415a6840da9bcd Mon Sep 17 00:00:00 2001 From: Thomas Bahn Date: Thu, 22 Dec 2016 19:37:37 +0100 Subject: [PATCH 5/5] fix: Don't import core twice in `core` mode --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index b555a90..105abf7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "std")] extern crate core; mod free_functions;