mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 06:51:58 +00:00
auto merge of #12098 : kballard/rust/from_utf8_lossy_tweak, r=huonw
MaybeOwned allows from_utf8_lossy to avoid allocation if there are no invalid bytes in the input. Before: ``` test str::bench::from_utf8_lossy_100_ascii ... bench: 183 ns/iter (+/- 5) test str::bench::from_utf8_lossy_100_invalid ... bench: 341 ns/iter (+/- 15) test str::bench::from_utf8_lossy_100_multibyte ... bench: 227 ns/iter (+/- 13) test str::bench::from_utf8_lossy_invalid ... bench: 102 ns/iter (+/- 4) test str::bench::is_utf8_100_ascii ... bench: 2 ns/iter (+/- 0) test str::bench::is_utf8_100_multibyte ... bench: 2 ns/iter (+/- 0) ``` Now: ``` test str::bench::from_utf8_lossy_100_ascii ... bench: 96 ns/iter (+/- 4) test str::bench::from_utf8_lossy_100_invalid ... bench: 318 ns/iter (+/- 10) test str::bench::from_utf8_lossy_100_multibyte ... bench: 105 ns/iter (+/- 2) test str::bench::from_utf8_lossy_invalid ... bench: 105 ns/iter (+/- 2) test str::bench::is_utf8_100_ascii ... bench: 2 ns/iter (+/- 0) test str::bench::is_utf8_100_multibyte ... bench: 2 ns/iter (+/- 0) ```
This commit is contained in:
commit
5acc998ed9
@ -442,9 +442,7 @@ fn check_error_patterns(props: &TestProps,
|
|||||||
testfile: &Path,
|
testfile: &Path,
|
||||||
ProcRes: &ProcRes) {
|
ProcRes: &ProcRes) {
|
||||||
if props.error_patterns.is_empty() {
|
if props.error_patterns.is_empty() {
|
||||||
testfile.display().with_str(|s| {
|
fatal(~"no error pattern specified in " + testfile.display().as_maybe_owned().as_slice());
|
||||||
fatal(~"no error pattern specified in " + s);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ProcRes.status.success() {
|
if ProcRes.status.success() {
|
||||||
|
@ -87,8 +87,7 @@ syn keyword rustTrait Primitive Int Float ToStrRadix ToPrimitive FromPrimitive
|
|||||||
syn keyword rustTrait GenericPath Path PosixPath WindowsPath
|
syn keyword rustTrait GenericPath Path PosixPath WindowsPath
|
||||||
syn keyword rustTrait RawPtr
|
syn keyword rustTrait RawPtr
|
||||||
syn keyword rustTrait Buffer Writer Reader Seek
|
syn keyword rustTrait Buffer Writer Reader Seek
|
||||||
syn keyword rustTrait SendStr SendStrOwned SendStrStatic IntoSendStr
|
syn keyword rustTrait Str StrVector StrSlice OwnedStr IntoMaybeOwned
|
||||||
syn keyword rustTrait Str StrVector StrSlice OwnedStr
|
|
||||||
syn keyword rustTrait IterBytes
|
syn keyword rustTrait IterBytes
|
||||||
syn keyword rustTrait ToStr IntoStr
|
syn keyword rustTrait ToStr IntoStr
|
||||||
syn keyword rustTrait CloneableTuple ImmutableTuple
|
syn keyword rustTrait CloneableTuple ImmutableTuple
|
||||||
|
@ -893,8 +893,8 @@ pub fn run_test(force_ignore: bool,
|
|||||||
spawn(proc() {
|
spawn(proc() {
|
||||||
let mut task = task::task();
|
let mut task = task::task();
|
||||||
task.name(match desc.name {
|
task.name(match desc.name {
|
||||||
DynTestName(ref name) => SendStrOwned(name.clone()),
|
DynTestName(ref name) => name.to_owned().into_maybe_owned(),
|
||||||
StaticTestName(name) => SendStrStatic(name),
|
StaticTestName(name) => name.into_maybe_owned()
|
||||||
});
|
});
|
||||||
let result_future = task.future_result();
|
let result_future = task.future_result();
|
||||||
task.spawn(testfn);
|
task.spawn(testfn);
|
||||||
|
@ -257,7 +257,7 @@ pub fn run(main: proc()) -> int {
|
|||||||
let (port, chan) = Chan::new();
|
let (port, chan) = Chan::new();
|
||||||
let mut opts = TaskOpts::new();
|
let mut opts = TaskOpts::new();
|
||||||
opts.notify_chan = Some(chan);
|
opts.notify_chan = Some(chan);
|
||||||
opts.name = Some(SendStrStatic("<main>"));
|
opts.name = Some("<main>".into_maybe_owned());
|
||||||
pool.spawn(opts, main);
|
pool.spawn(opts, main);
|
||||||
|
|
||||||
// Wait for the main task to return, and set the process error code
|
// Wait for the main task to return, and set the process error code
|
||||||
|
@ -510,7 +510,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn smoke_opts() {
|
fn smoke_opts() {
|
||||||
let mut opts = TaskOpts::new();
|
let mut opts = TaskOpts::new();
|
||||||
opts.name = Some(SendStrStatic("test"));
|
opts.name = Some("test".into_maybe_owned());
|
||||||
opts.stack_size = Some(20 * 4096);
|
opts.stack_size = Some(20 * 4096);
|
||||||
let (p, c) = Chan::new();
|
let (p, c) = Chan::new();
|
||||||
opts.notify_chan = Some(c);
|
opts.notify_chan = Some(c);
|
||||||
|
@ -294,7 +294,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn smoke_opts() {
|
fn smoke_opts() {
|
||||||
let mut opts = TaskOpts::new();
|
let mut opts = TaskOpts::new();
|
||||||
opts.name = Some(SendStrStatic("test"));
|
opts.name = Some("test".into_maybe_owned());
|
||||||
opts.stack_size = Some(20 * 4096);
|
opts.stack_size = Some(20 * 4096);
|
||||||
let (p, c) = Chan::new();
|
let (p, c) = Chan::new();
|
||||||
opts.notify_chan = Some(c);
|
opts.notify_chan = Some(c);
|
||||||
|
@ -436,7 +436,7 @@ impl<'a> SourceCollector<'a> {
|
|||||||
cur.push(p.filename().expect("source has no filename") + bytes!(".html"));
|
cur.push(p.filename().expect("source has no filename") + bytes!(".html"));
|
||||||
let mut w = BufferedWriter::new(if_ok!(File::create(&cur)));
|
let mut w = BufferedWriter::new(if_ok!(File::create(&cur)));
|
||||||
|
|
||||||
let title = cur.filename_display().with_str(|s| format!("{} -- source", s));
|
let title = format!("{} -- source", cur.filename_display());
|
||||||
let page = layout::Page {
|
let page = layout::Page {
|
||||||
title: title,
|
title: title,
|
||||||
ty: "source",
|
ty: "source",
|
||||||
|
@ -117,7 +117,6 @@ pub mod vec_ng;
|
|||||||
pub mod str;
|
pub mod str;
|
||||||
|
|
||||||
pub mod ascii;
|
pub mod ascii;
|
||||||
pub mod send_str;
|
|
||||||
|
|
||||||
pub mod ptr;
|
pub mod ptr;
|
||||||
pub mod owned;
|
pub mod owned;
|
||||||
|
@ -70,7 +70,7 @@ use fmt;
|
|||||||
use iter::Iterator;
|
use iter::Iterator;
|
||||||
use option::{Option, None, Some};
|
use option::{Option, None, Some};
|
||||||
use str;
|
use str;
|
||||||
use str::{OwnedStr, Str, StrSlice};
|
use str::{MaybeOwned, OwnedStr, Str, StrSlice, from_utf8_lossy};
|
||||||
use to_str::ToStr;
|
use to_str::ToStr;
|
||||||
use vec;
|
use vec;
|
||||||
use vec::{CloneableVector, OwnedCloneableVector, OwnedVector, Vector};
|
use vec::{CloneableVector, OwnedCloneableVector, OwnedVector, Vector};
|
||||||
@ -495,7 +495,7 @@ pub struct Display<'a, P> {
|
|||||||
|
|
||||||
impl<'a, P: GenericPath> fmt::Show for Display<'a, P> {
|
impl<'a, P: GenericPath> fmt::Show for Display<'a, P> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.with_str(|s| f.pad(s))
|
self.as_maybe_owned().as_slice().fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,33 +505,25 @@ impl<'a, P: GenericPath> ToStr for Display<'a, P> {
|
|||||||
/// If the path is not UTF-8, invalid sequences with be replaced with the
|
/// If the path is not UTF-8, invalid sequences with be replaced with the
|
||||||
/// unicode replacement char. This involves allocation.
|
/// unicode replacement char. This involves allocation.
|
||||||
fn to_str(&self) -> ~str {
|
fn to_str(&self) -> ~str {
|
||||||
if self.filename {
|
self.as_maybe_owned().into_owned()
|
||||||
match self.path.filename() {
|
|
||||||
None => ~"",
|
|
||||||
Some(v) => str::from_utf8_lossy(v)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
str::from_utf8_lossy(self.path.as_vec())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, P: GenericPath> Display<'a, P> {
|
impl<'a, P: GenericPath> Display<'a, P> {
|
||||||
/// Provides the path as a string to a closure
|
/// Returns the path as a possibly-owned string.
|
||||||
///
|
///
|
||||||
/// If the path is not UTF-8, invalid sequences will be replaced with the
|
/// If the path is not UTF-8, invalid sequences will be replaced with the
|
||||||
/// unicode replacement char. This involves allocation.
|
/// unicode replacement char. This involves allocation.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_str<T>(&self, f: |&str| -> T) -> T {
|
pub fn as_maybe_owned(&self) -> MaybeOwned<'a> {
|
||||||
let opt = if self.filename { self.path.filename_str() }
|
from_utf8_lossy(if self.filename {
|
||||||
else { self.path.as_str() };
|
match self.path.filename() {
|
||||||
match opt {
|
None => &[],
|
||||||
Some(s) => f(s),
|
Some(v) => v
|
||||||
None => {
|
|
||||||
let s = self.to_str();
|
|
||||||
f(s.as_slice())
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
self.path.as_vec()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,6 +583,23 @@ impl BytesContainer for CString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> BytesContainer for str::MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn container_as_bytes<'b>(&'b self) -> &'b [u8] {
|
||||||
|
self.as_slice().as_bytes()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn container_into_owned_bytes(self) -> ~[u8] {
|
||||||
|
self.into_owned().into_bytes()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn container_as_str<'b>(&'b self) -> Option<&'b str> {
|
||||||
|
Some(self.as_slice())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_str(_: Option<str::MaybeOwned>) -> bool { true }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn contains_nul(v: &[u8]) -> bool {
|
fn contains_nul(v: &[u8]) -> bool {
|
||||||
v.iter().any(|&x| x == 0)
|
v.iter().any(|&x| x == 0)
|
||||||
|
@ -564,24 +564,16 @@ mod tests {
|
|||||||
macro_rules! t(
|
macro_rules! t(
|
||||||
($path:expr, $exp:expr) => (
|
($path:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let mut called = false;
|
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
path.display().with_str(|s| {
|
let mo = path.display().as_maybe_owned();
|
||||||
assert_eq!(s, $exp);
|
assert_eq!(mo.as_slice(), $exp);
|
||||||
called = true;
|
|
||||||
});
|
|
||||||
assert!(called);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
($path:expr, $exp:expr, filename) => (
|
($path:expr, $exp:expr, filename) => (
|
||||||
{
|
{
|
||||||
let mut called = false;
|
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
path.filename_display().with_str(|s| {
|
let mo = path.filename_display().as_maybe_owned();
|
||||||
assert_eq!(s, $exp);
|
assert_eq!(mo.as_slice(), $exp);
|
||||||
called = true;
|
|
||||||
});
|
|
||||||
assert!(called);
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1278,20 +1278,12 @@ mod tests {
|
|||||||
let path = Path::new(b!("\\"));
|
let path = Path::new(b!("\\"));
|
||||||
assert_eq!(path.filename_display().to_str(), ~"");
|
assert_eq!(path.filename_display().to_str(), ~"");
|
||||||
|
|
||||||
let mut called = false;
|
|
||||||
let path = Path::new("foo");
|
let path = Path::new("foo");
|
||||||
path.display().with_str(|s| {
|
let mo = path.display().as_maybe_owned();
|
||||||
assert_eq!(s, "foo");
|
assert_eq!(mo.as_slice(), "foo");
|
||||||
called = true;
|
|
||||||
});
|
|
||||||
assert!(called);
|
|
||||||
called = false;
|
|
||||||
let path = Path::new(b!("\\"));
|
let path = Path::new(b!("\\"));
|
||||||
path.filename_display().with_str(|s| {
|
let mo = path.filename_display().as_maybe_owned();
|
||||||
assert_eq!(s, "");
|
assert_eq!(mo.as_slice(), "");
|
||||||
called = true;
|
|
||||||
});
|
|
||||||
assert!(called);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -63,8 +63,7 @@ pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive};
|
|||||||
pub use path::{GenericPath, Path, PosixPath, WindowsPath};
|
pub use path::{GenericPath, Path, PosixPath, WindowsPath};
|
||||||
pub use ptr::RawPtr;
|
pub use ptr::RawPtr;
|
||||||
pub use io::{Buffer, Writer, Reader, Seek};
|
pub use io::{Buffer, Writer, Reader, Seek};
|
||||||
pub use send_str::{SendStr, SendStrOwned, SendStrStatic, IntoSendStr};
|
pub use str::{Str, StrVector, StrSlice, OwnedStr, IntoMaybeOwned};
|
||||||
pub use str::{Str, StrVector, StrSlice, OwnedStr};
|
|
||||||
pub use to_bytes::IterBytes;
|
pub use to_bytes::IterBytes;
|
||||||
pub use to_str::{ToStr, IntoStr};
|
pub use to_str::{ToStr, IntoStr};
|
||||||
pub use tuple::{CloneableTuple, ImmutableTuple};
|
pub use tuple::{CloneableTuple, ImmutableTuple};
|
||||||
|
@ -30,7 +30,7 @@ use rt::local::Local;
|
|||||||
use rt::local_heap::LocalHeap;
|
use rt::local_heap::LocalHeap;
|
||||||
use rt::rtio::LocalIo;
|
use rt::rtio::LocalIo;
|
||||||
use rt::unwind::Unwinder;
|
use rt::unwind::Unwinder;
|
||||||
use send_str::SendStr;
|
use str::SendStr;
|
||||||
use sync::arc::UnsafeArc;
|
use sync::arc::UnsafeArc;
|
||||||
use sync::atomics::{AtomicUint, SeqCst};
|
use sync::atomics::{AtomicUint, SeqCst};
|
||||||
use task::{TaskResult, TaskOpts};
|
use task::{TaskResult, TaskOpts};
|
||||||
|
@ -1,246 +0,0 @@
|
|||||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! The `SendStr` trait for optionally static strings
|
|
||||||
|
|
||||||
use clone::{Clone, DeepClone};
|
|
||||||
use cmp::{Eq, TotalEq, Ord, TotalOrd, Equiv};
|
|
||||||
use cmp::Ordering;
|
|
||||||
use container::Container;
|
|
||||||
use default::Default;
|
|
||||||
use str::{Str, StrSlice};
|
|
||||||
use to_str::ToStr;
|
|
||||||
use to_bytes::{IterBytes, Cb};
|
|
||||||
|
|
||||||
/// A SendStr is a string that can hold either a ~str or a &'static str.
|
|
||||||
/// This can be useful as an optimization when an allocation is sometimes
|
|
||||||
/// needed but the common case is statically known.
|
|
||||||
#[allow(missing_doc)]
|
|
||||||
pub enum SendStr {
|
|
||||||
SendStrOwned(~str),
|
|
||||||
SendStrStatic(&'static str)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendStr {
|
|
||||||
/// Returns `true` if this `SendStr` wraps an owned string
|
|
||||||
#[inline]
|
|
||||||
pub fn is_owned(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
SendStrOwned(_) => true,
|
|
||||||
SendStrStatic(_) => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if this `SendStr` wraps a static string
|
|
||||||
#[inline]
|
|
||||||
pub fn is_static(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
SendStrOwned(_) => false,
|
|
||||||
SendStrStatic(_) => true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait for moving into an `SendStr`
|
|
||||||
pub trait IntoSendStr {
|
|
||||||
/// Moves self into an `SendStr`
|
|
||||||
fn into_send_str(self) -> SendStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSendStr for ~str {
|
|
||||||
#[inline]
|
|
||||||
fn into_send_str(self) -> SendStr { SendStrOwned(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSendStr for &'static str {
|
|
||||||
#[inline]
|
|
||||||
fn into_send_str(self) -> SendStr { SendStrStatic(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSendStr for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn into_send_str(self) -> SendStr { self }
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Section: String trait impls.
|
|
||||||
`SendStr` should behave like a normal string, so we don't derive.
|
|
||||||
*/
|
|
||||||
|
|
||||||
impl ToStr for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn to_str(&self) -> ~str { self.as_slice().to_owned() }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &SendStr) -> bool {
|
|
||||||
self.as_slice().equals(&other.as_slice())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TotalEq for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn equals(&self, other: &SendStr) -> bool {
|
|
||||||
self.as_slice().equals(&other.as_slice())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn lt(&self, other: &SendStr) -> bool {
|
|
||||||
self.as_slice().lt(&other.as_slice())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TotalOrd for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn cmp(&self, other: &SendStr) -> Ordering {
|
|
||||||
self.as_slice().cmp(&other.as_slice())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, S: Str> Equiv<S> for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn equiv(&self, other: &S) -> bool {
|
|
||||||
self.as_slice().equals(&other.as_slice())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Str for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn as_slice<'r>(&'r self) -> &'r str {
|
|
||||||
match *self {
|
|
||||||
SendStrOwned(ref s) => s.as_slice(),
|
|
||||||
// FIXME: Borrowchecker doesn't recognize lifetime as static unless prompted
|
|
||||||
// SendStrStatic(s) => s.as_slice()
|
|
||||||
SendStrStatic(s) => {let tmp: &'static str = s; tmp}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn into_owned(self) -> ~str {
|
|
||||||
match self {
|
|
||||||
SendStrOwned(s) => s,
|
|
||||||
SendStrStatic(s) => s.to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Container for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn len(&self) -> uint { self.as_slice().len() }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn clone(&self) -> SendStr {
|
|
||||||
match *self {
|
|
||||||
SendStrOwned(ref s) => SendStrOwned(s.to_owned()),
|
|
||||||
SendStrStatic(s) => SendStrStatic(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeepClone for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn deep_clone(&self) -> SendStr {
|
|
||||||
match *self {
|
|
||||||
SendStrOwned(ref s) => SendStrOwned(s.to_owned()),
|
|
||||||
SendStrStatic(s) => SendStrStatic(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn default() -> SendStr { SendStrStatic("") }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IterBytes for SendStr {
|
|
||||||
#[inline]
|
|
||||||
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
|
|
||||||
match *self {
|
|
||||||
SendStrOwned(ref s) => s.iter_bytes(lsb0, f),
|
|
||||||
SendStrStatic(s) => s.iter_bytes(lsb0, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use prelude::*;
|
|
||||||
use send_str::{SendStrOwned, SendStrStatic};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_send_str_traits() {
|
|
||||||
let s = SendStrStatic("abcde");
|
|
||||||
assert_eq!(s.len(), 5);
|
|
||||||
assert_eq!(s.as_slice(), "abcde");
|
|
||||||
assert_eq!(s.to_str(), ~"abcde");
|
|
||||||
assert!(s.lt(&SendStrOwned(~"bcdef")));
|
|
||||||
assert_eq!(SendStrStatic(""), Default::default());
|
|
||||||
|
|
||||||
let o = SendStrOwned(~"abcde");
|
|
||||||
assert_eq!(o.len(), 5);
|
|
||||||
assert_eq!(o.as_slice(), "abcde");
|
|
||||||
assert_eq!(o.to_str(), ~"abcde");
|
|
||||||
assert!(o.lt(&SendStrStatic("bcdef")));
|
|
||||||
assert_eq!(SendStrOwned(~""), Default::default());
|
|
||||||
|
|
||||||
assert_eq!(s.cmp(&o), Equal);
|
|
||||||
assert!(s.equals(&o));
|
|
||||||
assert!(s.equiv(&o));
|
|
||||||
|
|
||||||
assert_eq!(o.cmp(&s), Equal);
|
|
||||||
assert!(o.equals(&s));
|
|
||||||
assert!(o.equiv(&s));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_send_str_methods() {
|
|
||||||
let s = SendStrStatic("abcde");
|
|
||||||
assert!(s.is_static());
|
|
||||||
assert!(!s.is_owned());
|
|
||||||
|
|
||||||
let o = SendStrOwned(~"abcde");
|
|
||||||
assert!(!o.is_static());
|
|
||||||
assert!(o.is_owned());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_send_str_clone() {
|
|
||||||
assert_eq!(SendStrOwned(~"abcde"), SendStrStatic("abcde").clone());
|
|
||||||
assert_eq!(SendStrOwned(~"abcde"), SendStrStatic("abcde").deep_clone());
|
|
||||||
|
|
||||||
assert_eq!(SendStrOwned(~"abcde"), SendStrOwned(~"abcde").clone());
|
|
||||||
assert_eq!(SendStrOwned(~"abcde"), SendStrOwned(~"abcde").deep_clone());
|
|
||||||
|
|
||||||
assert_eq!(SendStrStatic("abcde"), SendStrStatic("abcde").clone());
|
|
||||||
assert_eq!(SendStrStatic("abcde"), SendStrStatic("abcde").deep_clone());
|
|
||||||
|
|
||||||
assert_eq!(SendStrStatic("abcde"), SendStrOwned(~"abcde").clone());
|
|
||||||
assert_eq!(SendStrStatic("abcde"), SendStrOwned(~"abcde").deep_clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_send_str_into_owned() {
|
|
||||||
assert_eq!(SendStrStatic("abcde").into_owned(), ~"abcde");
|
|
||||||
assert_eq!(SendStrOwned(~"abcde").into_owned(), ~"abcde");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_into_send_str() {
|
|
||||||
assert_eq!("abcde".into_send_str(), SendStrStatic("abcde"));
|
|
||||||
assert_eq!((~"abcde").into_send_str(), SendStrStatic("abcde"));
|
|
||||||
assert_eq!("abcde".into_send_str(), SendStrOwned(~"abcde"));
|
|
||||||
assert_eq!((~"abcde").into_send_str(), SendStrOwned(~"abcde"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -86,7 +86,9 @@ use cast::transmute;
|
|||||||
use char;
|
use char;
|
||||||
use char::Char;
|
use char::Char;
|
||||||
use clone::{Clone, DeepClone};
|
use clone::{Clone, DeepClone};
|
||||||
|
use cmp::{Eq, TotalEq, Ord, TotalOrd, Equiv, Ordering};
|
||||||
use container::{Container, Mutable};
|
use container::{Container, Mutable};
|
||||||
|
use fmt;
|
||||||
use iter::{Iterator, FromIterator, Extendable, range};
|
use iter::{Iterator, FromIterator, Extendable, range};
|
||||||
use iter::{Filter, AdditiveIterator, Map};
|
use iter::{Filter, AdditiveIterator, Map};
|
||||||
use iter::{Rev, DoubleEndedIterator, ExactSize};
|
use iter::{Rev, DoubleEndedIterator, ExactSize};
|
||||||
@ -100,7 +102,7 @@ use from_str::FromStr;
|
|||||||
use vec;
|
use vec;
|
||||||
use vec::{OwnedVector, OwnedCloneableVector, ImmutableVector, MutableVector};
|
use vec::{OwnedVector, OwnedCloneableVector, ImmutableVector, MutableVector};
|
||||||
use default::Default;
|
use default::Default;
|
||||||
use send_str::{SendStr, SendStrOwned};
|
use to_bytes::{IterBytes, Cb};
|
||||||
use unstable::raw::Repr;
|
use unstable::raw::Repr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -729,6 +731,11 @@ Section: Misc
|
|||||||
|
|
||||||
/// Determines if a vector of bytes contains valid UTF-8
|
/// Determines if a vector of bytes contains valid UTF-8
|
||||||
pub fn is_utf8(v: &[u8]) -> bool {
|
pub fn is_utf8(v: &[u8]) -> bool {
|
||||||
|
first_non_utf8_index(v).is_none()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn first_non_utf8_index(v: &[u8]) -> Option<uint> {
|
||||||
let mut i = 0u;
|
let mut i = 0u;
|
||||||
let total = v.len();
|
let total = v.len();
|
||||||
fn unsafe_get(xs: &[u8], i: uint) -> u8 {
|
fn unsafe_get(xs: &[u8], i: uint) -> u8 {
|
||||||
@ -740,10 +747,10 @@ pub fn is_utf8(v: &[u8]) -> bool {
|
|||||||
i += 1u;
|
i += 1u;
|
||||||
} else {
|
} else {
|
||||||
let w = utf8_char_width(v_i);
|
let w = utf8_char_width(v_i);
|
||||||
if w == 0u { return false; }
|
if w == 0u { return Some(i); }
|
||||||
|
|
||||||
let nexti = i + w;
|
let nexti = i + w;
|
||||||
if nexti > total { return false; }
|
if nexti > total { return Some(i); }
|
||||||
|
|
||||||
// 2-byte encoding is for codepoints \u0080 to \u07ff
|
// 2-byte encoding is for codepoints \u0080 to \u07ff
|
||||||
// first C2 80 last DF BF
|
// first C2 80 last DF BF
|
||||||
@ -766,7 +773,7 @@ pub fn is_utf8(v: &[u8]) -> bool {
|
|||||||
// UTF8-tail = %x80-BF
|
// UTF8-tail = %x80-BF
|
||||||
match w {
|
match w {
|
||||||
2 => if unsafe_get(v, i + 1) & 192u8 != TAG_CONT_U8 {
|
2 => if unsafe_get(v, i + 1) & 192u8 != TAG_CONT_U8 {
|
||||||
return false
|
return Some(i)
|
||||||
},
|
},
|
||||||
3 => match (v_i,
|
3 => match (v_i,
|
||||||
unsafe_get(v, i + 1),
|
unsafe_get(v, i + 1),
|
||||||
@ -775,7 +782,7 @@ pub fn is_utf8(v: &[u8]) -> bool {
|
|||||||
(0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) => (),
|
(0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) => (),
|
||||||
(0xED , 0x80 .. 0x9F, TAG_CONT_U8) => (),
|
(0xED , 0x80 .. 0x9F, TAG_CONT_U8) => (),
|
||||||
(0xEE .. 0xEF, 0x80 .. 0xBF, TAG_CONT_U8) => (),
|
(0xEE .. 0xEF, 0x80 .. 0xBF, TAG_CONT_U8) => (),
|
||||||
_ => return false,
|
_ => return Some(i),
|
||||||
},
|
},
|
||||||
_ => match (v_i,
|
_ => match (v_i,
|
||||||
unsafe_get(v, i + 1),
|
unsafe_get(v, i + 1),
|
||||||
@ -784,14 +791,14 @@ pub fn is_utf8(v: &[u8]) -> bool {
|
|||||||
(0xF0 , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) => (),
|
(0xF0 , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) => (),
|
||||||
(0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) => (),
|
(0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) => (),
|
||||||
(0xF4 , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => (),
|
(0xF4 , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => (),
|
||||||
_ => return false,
|
_ => return Some(i)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
i = nexti;
|
i = nexti;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if a vector of `u16` contains valid UTF-16
|
/// Determines if a vector of `u16` contains valid UTF-16
|
||||||
@ -918,12 +925,16 @@ static TAG_CONT_U8: u8 = 128u8;
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// let input = bytes!("Hello ", 0xF0, 0x90, 0x80, "World");
|
/// let input = bytes!("Hello ", 0xF0, 0x90, 0x80, "World");
|
||||||
/// let output = std::str::from_utf8_lossy(input);
|
/// let output = std::str::from_utf8_lossy(input);
|
||||||
/// assert_eq!(output, ~"Hello \uFFFDWorld");
|
/// assert_eq!(output.as_slice(), "Hello \uFFFDWorld");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_utf8_lossy(v: &[u8]) -> ~str {
|
pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> MaybeOwned<'a> {
|
||||||
|
let firstbad = match first_non_utf8_index(v) {
|
||||||
|
None => return Slice(unsafe { cast::transmute(v) }),
|
||||||
|
Some(i) => i
|
||||||
|
};
|
||||||
|
|
||||||
static REPLACEMENT: &'static [u8] = bytes!(0xEF, 0xBF, 0xBD); // U+FFFD in UTF-8
|
static REPLACEMENT: &'static [u8] = bytes!(0xEF, 0xBF, 0xBD); // U+FFFD in UTF-8
|
||||||
let mut i = 0u;
|
let mut i = firstbad;
|
||||||
let mut lastgood = 0u;
|
|
||||||
let total = v.len();
|
let total = v.len();
|
||||||
fn unsafe_get(xs: &[u8], i: uint) -> u8 {
|
fn unsafe_get(xs: &[u8], i: uint) -> u8 {
|
||||||
unsafe { *xs.unsafe_ref(i) }
|
unsafe { *xs.unsafe_ref(i) }
|
||||||
@ -937,23 +948,32 @@ pub fn from_utf8_lossy(v: &[u8]) -> ~str {
|
|||||||
}
|
}
|
||||||
let mut res = with_capacity(total);
|
let mut res = with_capacity(total);
|
||||||
|
|
||||||
|
if i > 0 {
|
||||||
|
unsafe { raw::push_bytes(&mut res, v.slice_to(i)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// subseqidx is the index of the first byte of the subsequence we're looking at.
|
||||||
|
// It's used to copy a bunch of contiguous good codepoints at once instead of copying
|
||||||
|
// them one by one.
|
||||||
|
let mut subseqidx = firstbad;
|
||||||
|
|
||||||
while i < total {
|
while i < total {
|
||||||
let i_ = i;
|
let i_ = i;
|
||||||
let byte = unsafe_get(v, i);
|
let byte = unsafe_get(v, i);
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
macro_rules! error(() => {
|
macro_rules! error(() => ({
|
||||||
unsafe {
|
unsafe {
|
||||||
if lastgood != i_ {
|
if subseqidx != i_ {
|
||||||
raw::push_bytes(&mut res, v.slice(lastgood, i_));
|
raw::push_bytes(&mut res, v.slice(subseqidx, i_));
|
||||||
}
|
}
|
||||||
lastgood = i;
|
subseqidx = i;
|
||||||
raw::push_bytes(&mut res, REPLACEMENT);
|
raw::push_bytes(&mut res, REPLACEMENT);
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
|
|
||||||
if byte < 128u8 {
|
if byte < 128u8 {
|
||||||
// lastgood handles this
|
// subseqidx handles this
|
||||||
} else {
|
} else {
|
||||||
let w = utf8_char_width(byte);
|
let w = utf8_char_width(byte);
|
||||||
|
|
||||||
@ -1012,8 +1032,176 @@ pub fn from_utf8_lossy(v: &[u8]) -> ~str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { raw::push_bytes(&mut res, v.slice(lastgood, total)) };
|
if subseqidx < total {
|
||||||
res
|
unsafe { raw::push_bytes(&mut res, v.slice(subseqidx, total)) };
|
||||||
|
}
|
||||||
|
Owned(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Section: MaybeOwned
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// A MaybeOwned is a string that can hold either a ~str or a &str.
|
||||||
|
/// This can be useful as an optimization when an allocation is sometimes
|
||||||
|
/// needed but not always.
|
||||||
|
pub enum MaybeOwned<'a> {
|
||||||
|
/// A borrowed string
|
||||||
|
Slice(&'a str),
|
||||||
|
/// An owned string
|
||||||
|
Owned(~str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SendStr is a specialization of `MaybeOwned` to be sendable
|
||||||
|
pub type SendStr = MaybeOwned<'static>;
|
||||||
|
|
||||||
|
impl<'a> MaybeOwned<'a> {
|
||||||
|
/// Returns `true` if this `MaybeOwned` wraps an owned string
|
||||||
|
#[inline]
|
||||||
|
pub fn is_owned(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Slice(_) => false,
|
||||||
|
Owned(_) => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this `MaybeOwned` wraps a borrowed string
|
||||||
|
#[inline]
|
||||||
|
pub fn is_slice(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Slice(_) => true,
|
||||||
|
Owned(_) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for moving into a `MaybeOwned`
|
||||||
|
pub trait IntoMaybeOwned<'a> {
|
||||||
|
/// Moves self into a `MaybeOwned`
|
||||||
|
fn into_maybe_owned(self) -> MaybeOwned<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoMaybeOwned<'a> for ~str {
|
||||||
|
#[inline]
|
||||||
|
fn into_maybe_owned(self) -> MaybeOwned<'a> { Owned(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoMaybeOwned<'a> for &'a str {
|
||||||
|
#[inline]
|
||||||
|
fn into_maybe_owned(self) -> MaybeOwned<'a> { Slice(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoMaybeOwned<'a> for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn into_maybe_owned(self) -> MaybeOwned<'a> { self }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToStr for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn to_str(&self) -> ~str { self.as_slice().to_owned() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Eq for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &MaybeOwned) -> bool {
|
||||||
|
self.as_slice().equals(&other.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TotalEq for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn equals(&self, other: &MaybeOwned) -> bool {
|
||||||
|
self.as_slice().equals(&other.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Ord for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn lt(&self, other: &MaybeOwned) -> bool {
|
||||||
|
self.as_slice().lt(&other.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TotalOrd for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn cmp(&self, other: &MaybeOwned) -> Ordering {
|
||||||
|
self.as_slice().cmp(&other.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, S: Str> Equiv<S> for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn equiv(&self, other: &S) -> bool {
|
||||||
|
self.as_slice().equals(&other.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Str for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn as_slice<'b>(&'b self) -> &'b str {
|
||||||
|
match *self {
|
||||||
|
Slice(s) => s,
|
||||||
|
Owned(ref s) => s.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_owned(self) -> ~str {
|
||||||
|
match self {
|
||||||
|
Slice(s) => s.to_owned(),
|
||||||
|
Owned(s) => s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Container for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> uint { self.as_slice().len() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Clone for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> MaybeOwned<'a> {
|
||||||
|
match *self {
|
||||||
|
Slice(s) => Slice(s),
|
||||||
|
Owned(ref s) => Owned(s.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DeepClone for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn deep_clone(&self) -> MaybeOwned<'a> {
|
||||||
|
match *self {
|
||||||
|
Slice(s) => Slice(s),
|
||||||
|
Owned(ref s) => Owned(s.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Default for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> MaybeOwned<'a> { Slice("") }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IterBytes for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
|
||||||
|
match *self {
|
||||||
|
Slice(s) => s.iter_bytes(lsb0, f),
|
||||||
|
Owned(ref s) => s.iter_bytes(lsb0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Show for MaybeOwned<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Slice(ref s) => s.fmt(f),
|
||||||
|
Owned(ref s) => s.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unsafe operations
|
/// Unsafe operations
|
||||||
@ -1770,9 +1958,6 @@ pub trait StrSlice<'a> {
|
|||||||
/// Converts to a vector of `u16` encoded as UTF-16.
|
/// Converts to a vector of `u16` encoded as UTF-16.
|
||||||
fn to_utf16(&self) -> ~[u16];
|
fn to_utf16(&self) -> ~[u16];
|
||||||
|
|
||||||
/// Copy a slice into a new `SendStr`.
|
|
||||||
fn to_send_str(&self) -> SendStr;
|
|
||||||
|
|
||||||
/// Check that `index`-th byte lies at the start and/or end of a
|
/// Check that `index`-th byte lies at the start and/or end of a
|
||||||
/// UTF-8 code point sequence.
|
/// UTF-8 code point sequence.
|
||||||
///
|
///
|
||||||
@ -2297,11 +2482,6 @@ impl<'a> StrSlice<'a> for &'a str {
|
|||||||
u
|
u
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_send_str(&self) -> SendStr {
|
|
||||||
SendStrOwned(self.to_owned())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_char_boundary(&self, index: uint) -> bool {
|
fn is_char_boundary(&self, index: uint) -> bool {
|
||||||
if index == self.len() { return true; }
|
if index == self.len() { return true; }
|
||||||
@ -2741,7 +2921,6 @@ mod tests {
|
|||||||
use prelude::*;
|
use prelude::*;
|
||||||
use ptr;
|
use ptr;
|
||||||
use str::*;
|
use str::*;
|
||||||
use send_str::{SendStrOwned, SendStrStatic};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eq() {
|
fn test_eq() {
|
||||||
@ -3943,38 +4122,32 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_str_from_utf8_lossy() {
|
fn test_str_from_utf8_lossy() {
|
||||||
let xs = bytes!("hello");
|
let xs = bytes!("hello");
|
||||||
assert_eq!(from_utf8_lossy(xs), ~"hello");
|
assert_eq!(from_utf8_lossy(xs), Slice("hello"));
|
||||||
|
|
||||||
let xs = bytes!("ศไทย中华Việt Nam");
|
let xs = bytes!("ศไทย中华Việt Nam");
|
||||||
assert_eq!(from_utf8_lossy(xs), ~"ศไทย中华Việt Nam");
|
assert_eq!(from_utf8_lossy(xs), Slice("ศไทย中华Việt Nam"));
|
||||||
|
|
||||||
let xs = bytes!("Hello", 0xC2, " There", 0xFF, " Goodbye");
|
let xs = bytes!("Hello", 0xC2, " There", 0xFF, " Goodbye");
|
||||||
assert_eq!(from_utf8_lossy(xs), ~"Hello\uFFFD There\uFFFD Goodbye");
|
assert_eq!(from_utf8_lossy(xs), Owned(~"Hello\uFFFD There\uFFFD Goodbye"));
|
||||||
|
|
||||||
let xs = bytes!("Hello", 0xC0, 0x80, " There", 0xE6, 0x83, " Goodbye");
|
let xs = bytes!("Hello", 0xC0, 0x80, " There", 0xE6, 0x83, " Goodbye");
|
||||||
assert_eq!(from_utf8_lossy(xs), ~"Hello\uFFFD\uFFFD There\uFFFD Goodbye");
|
assert_eq!(from_utf8_lossy(xs), Owned(~"Hello\uFFFD\uFFFD There\uFFFD Goodbye"));
|
||||||
|
|
||||||
let xs = bytes!(0xF5, "foo", 0xF5, 0x80, "bar");
|
let xs = bytes!(0xF5, "foo", 0xF5, 0x80, "bar");
|
||||||
assert_eq!(from_utf8_lossy(xs), ~"\uFFFDfoo\uFFFD\uFFFDbar");
|
assert_eq!(from_utf8_lossy(xs), Owned(~"\uFFFDfoo\uFFFD\uFFFDbar"));
|
||||||
|
|
||||||
let xs = bytes!(0xF1, "foo", 0xF1, 0x80, "bar", 0xF1, 0x80, 0x80, "baz");
|
let xs = bytes!(0xF1, "foo", 0xF1, 0x80, "bar", 0xF1, 0x80, 0x80, "baz");
|
||||||
assert_eq!(from_utf8_lossy(xs), ~"\uFFFDfoo\uFFFDbar\uFFFDbaz");
|
assert_eq!(from_utf8_lossy(xs), Owned(~"\uFFFDfoo\uFFFDbar\uFFFDbaz"));
|
||||||
|
|
||||||
let xs = bytes!(0xF4, "foo", 0xF4, 0x80, "bar", 0xF4, 0xBF, "baz");
|
let xs = bytes!(0xF4, "foo", 0xF4, 0x80, "bar", 0xF4, 0xBF, "baz");
|
||||||
assert_eq!(from_utf8_lossy(xs), ~"\uFFFDfoo\uFFFDbar\uFFFD\uFFFDbaz");
|
assert_eq!(from_utf8_lossy(xs), Owned(~"\uFFFDfoo\uFFFDbar\uFFFD\uFFFDbaz"));
|
||||||
|
|
||||||
let xs = bytes!(0xF0, 0x80, 0x80, 0x80, "foo", 0xF0, 0x90, 0x80, 0x80, "bar");
|
let xs = bytes!(0xF0, 0x80, 0x80, 0x80, "foo", 0xF0, 0x90, 0x80, 0x80, "bar");
|
||||||
assert_eq!(from_utf8_lossy(xs), ~"\uFFFD\uFFFD\uFFFD\uFFFDfoo\U00010000bar");
|
assert_eq!(from_utf8_lossy(xs), Owned(~"\uFFFD\uFFFD\uFFFD\uFFFDfoo\U00010000bar"));
|
||||||
|
|
||||||
// surrogates
|
// surrogates
|
||||||
let xs = bytes!(0xED, 0xA0, 0x80, "foo", 0xED, 0xBF, 0xBF, "bar");
|
let xs = bytes!(0xED, 0xA0, 0x80, "foo", 0xED, 0xBF, 0xBF, "bar");
|
||||||
assert_eq!(from_utf8_lossy(xs), ~"\uFFFD\uFFFD\uFFFDfoo\uFFFD\uFFFD\uFFFDbar");
|
assert_eq!(from_utf8_lossy(xs), Owned(~"\uFFFD\uFFFD\uFFFDfoo\uFFFD\uFFFD\uFFFDbar"));
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_send_str() {
|
|
||||||
assert_eq!("abcde".to_send_str(), SendStrStatic("abcde"));
|
|
||||||
assert_eq!("abcde".to_send_str(), SendStrOwned(~"abcde"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -3982,6 +4155,71 @@ mod tests {
|
|||||||
let owned: Option<~str> = from_str(&"string");
|
let owned: Option<~str> = from_str(&"string");
|
||||||
assert_eq!(owned, Some(~"string"));
|
assert_eq!(owned, Some(~"string"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_maybe_owned_traits() {
|
||||||
|
let s = Slice("abcde");
|
||||||
|
assert_eq!(s.len(), 5);
|
||||||
|
assert_eq!(s.as_slice(), "abcde");
|
||||||
|
assert_eq!(s.to_str(), ~"abcde");
|
||||||
|
assert!(s.lt(&Owned(~"bcdef")));
|
||||||
|
assert_eq!(Slice(""), Default::default());
|
||||||
|
|
||||||
|
let o = Owned(~"abcde");
|
||||||
|
assert_eq!(o.len(), 5);
|
||||||
|
assert_eq!(o.as_slice(), "abcde");
|
||||||
|
assert_eq!(o.to_str(), ~"abcde");
|
||||||
|
assert!(o.lt(&Slice("bcdef")));
|
||||||
|
assert_eq!(Owned(~""), Default::default());
|
||||||
|
|
||||||
|
assert_eq!(s.cmp(&o), Equal);
|
||||||
|
assert!(s.equals(&o));
|
||||||
|
assert!(s.equiv(&o));
|
||||||
|
|
||||||
|
assert_eq!(o.cmp(&s), Equal);
|
||||||
|
assert!(o.equals(&s));
|
||||||
|
assert!(o.equiv(&s));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_maybe_owned_methods() {
|
||||||
|
let s = Slice("abcde");
|
||||||
|
assert!(s.is_slice());
|
||||||
|
assert!(!s.is_owned());
|
||||||
|
|
||||||
|
let o = Owned(~"abcde");
|
||||||
|
assert!(!o.is_slice());
|
||||||
|
assert!(o.is_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_maybe_owned_clone() {
|
||||||
|
assert_eq!(Owned(~"abcde"), Slice("abcde").clone());
|
||||||
|
assert_eq!(Owned(~"abcde"), Slice("abcde").deep_clone());
|
||||||
|
|
||||||
|
assert_eq!(Owned(~"abcde"), Owned(~"abcde").clone());
|
||||||
|
assert_eq!(Owned(~"abcde"), Owned(~"abcde").deep_clone());
|
||||||
|
|
||||||
|
assert_eq!(Slice("abcde"), Slice("abcde").clone());
|
||||||
|
assert_eq!(Slice("abcde"), Slice("abcde").deep_clone());
|
||||||
|
|
||||||
|
assert_eq!(Slice("abcde"), Owned(~"abcde").clone());
|
||||||
|
assert_eq!(Slice("abcde"), Owned(~"abcde").deep_clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_maybe_owned_into_owned() {
|
||||||
|
assert_eq!(Slice("abcde").into_owned(), ~"abcde");
|
||||||
|
assert_eq!(Owned(~"abcde").into_owned(), ~"abcde");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_into_maybe_owned() {
|
||||||
|
assert_eq!("abcde".into_maybe_owned(), Slice("abcde"));
|
||||||
|
assert_eq!((~"abcde").into_maybe_owned(), Slice("abcde"));
|
||||||
|
assert_eq!("abcde".into_maybe_owned(), Owned(~"abcde"));
|
||||||
|
assert_eq!((~"abcde").into_maybe_owned(), Owned(~"abcde"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -62,8 +62,7 @@ use option::{None, Some, Option};
|
|||||||
use result::{Result, Ok, Err};
|
use result::{Result, Ok, Err};
|
||||||
use rt::local::Local;
|
use rt::local::Local;
|
||||||
use rt::task::Task;
|
use rt::task::Task;
|
||||||
use send_str::{SendStr, IntoSendStr};
|
use str::{Str, SendStr, IntoMaybeOwned};
|
||||||
use str::Str;
|
|
||||||
|
|
||||||
#[cfg(test)] use any::{AnyOwnExt, AnyRefExt};
|
#[cfg(test)] use any::{AnyOwnExt, AnyRefExt};
|
||||||
#[cfg(test)] use comm::SharedChan;
|
#[cfg(test)] use comm::SharedChan;
|
||||||
@ -190,8 +189,8 @@ impl TaskBuilder {
|
|||||||
|
|
||||||
/// Name the task-to-be. Currently the name is used for identification
|
/// Name the task-to-be. Currently the name is used for identification
|
||||||
/// only in failure messages.
|
/// only in failure messages.
|
||||||
pub fn name<S: IntoSendStr>(&mut self, name: S) {
|
pub fn name<S: IntoMaybeOwned<'static>>(&mut self, name: S) {
|
||||||
self.opts.name = Some(name.into_send_str());
|
self.opts.name = Some(name.into_maybe_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -396,7 +395,7 @@ fn test_static_named_task() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_send_named_task() {
|
fn test_send_named_task() {
|
||||||
let mut t = task();
|
let mut t = task();
|
||||||
t.name("ada lovelace".into_send_str());
|
t.name("ada lovelace".into_maybe_owned());
|
||||||
t.spawn(proc() {
|
t.spawn(proc() {
|
||||||
with_task_name(|name| {
|
with_task_name(|name| {
|
||||||
assert!(name.unwrap() == "ada lovelace");
|
assert!(name.unwrap() == "ada lovelace");
|
||||||
|
@ -4200,10 +4200,10 @@ impl Parser {
|
|||||||
let mut err = ~"circular modules: ";
|
let mut err = ~"circular modules: ";
|
||||||
let len = included_mod_stack.get().len();
|
let len = included_mod_stack.get().len();
|
||||||
for p in included_mod_stack.get().slice(i, len).iter() {
|
for p in included_mod_stack.get().slice(i, len).iter() {
|
||||||
p.display().with_str(|s| err.push_str(s));
|
err.push_str(p.display().as_maybe_owned().as_slice());
|
||||||
err.push_str(" -> ");
|
err.push_str(" -> ");
|
||||||
}
|
}
|
||||||
path.display().with_str(|s| err.push_str(s));
|
err.push_str(path.display().as_maybe_owned().as_slice());
|
||||||
self.span_fatal(id_sp, err);
|
self.span_fatal(id_sp, err);
|
||||||
}
|
}
|
||||||
None => ()
|
None => ()
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut t = ::std::task::task();
|
let mut t = ::std::task::task();
|
||||||
t.name("send name".to_send_str());
|
t.name("send name".into_maybe_owned());
|
||||||
t.try(proc() {
|
t.try(proc() {
|
||||||
fail!("test");
|
fail!("test");
|
||||||
3
|
3
|
||||||
|
@ -13,45 +13,44 @@ use std::cmp::{TotalEq, Ord, TotalOrd, Equiv};
|
|||||||
use std::cmp::Equal;
|
use std::cmp::Equal;
|
||||||
use std::container::{Container, Map, MutableMap};
|
use std::container::{Container, Map, MutableMap};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::send_str::{SendStr, SendStrOwned, SendStrStatic};
|
use std::str::{Str, SendStr, Owned, Slice};
|
||||||
use std::str::Str;
|
|
||||||
use std::to_str::ToStr;
|
use std::to_str::ToStr;
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
use std::option::Some;
|
use std::option::Some;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let mut map: HashMap<SendStr, uint> = HashMap::new();
|
let mut map: HashMap<SendStr, uint> = HashMap::new();
|
||||||
assert!(map.insert(SendStrStatic("foo"), 42));
|
assert!(map.insert(Slice("foo"), 42));
|
||||||
assert!(!map.insert(SendStrOwned(~"foo"), 42));
|
assert!(!map.insert(Owned(~"foo"), 42));
|
||||||
assert!(!map.insert(SendStrStatic("foo"), 42));
|
assert!(!map.insert(Slice("foo"), 42));
|
||||||
assert!(!map.insert(SendStrOwned(~"foo"), 42));
|
assert!(!map.insert(Owned(~"foo"), 42));
|
||||||
|
|
||||||
assert!(!map.insert(SendStrStatic("foo"), 43));
|
assert!(!map.insert(Slice("foo"), 43));
|
||||||
assert!(!map.insert(SendStrOwned(~"foo"), 44));
|
assert!(!map.insert(Owned(~"foo"), 44));
|
||||||
assert!(!map.insert(SendStrStatic("foo"), 45));
|
assert!(!map.insert(Slice("foo"), 45));
|
||||||
assert!(!map.insert(SendStrOwned(~"foo"), 46));
|
assert!(!map.insert(Owned(~"foo"), 46));
|
||||||
|
|
||||||
let v = 46;
|
let v = 46;
|
||||||
|
|
||||||
assert_eq!(map.find(&SendStrOwned(~"foo")), Some(&v));
|
assert_eq!(map.find(&Owned(~"foo")), Some(&v));
|
||||||
assert_eq!(map.find(&SendStrStatic("foo")), Some(&v));
|
assert_eq!(map.find(&Slice("foo")), Some(&v));
|
||||||
|
|
||||||
let (a, b, c, d) = (50, 51, 52, 53);
|
let (a, b, c, d) = (50, 51, 52, 53);
|
||||||
|
|
||||||
assert!(map.insert(SendStrStatic("abc"), a));
|
assert!(map.insert(Slice("abc"), a));
|
||||||
assert!(map.insert(SendStrOwned(~"bcd"), b));
|
assert!(map.insert(Owned(~"bcd"), b));
|
||||||
assert!(map.insert(SendStrStatic("cde"), c));
|
assert!(map.insert(Slice("cde"), c));
|
||||||
assert!(map.insert(SendStrOwned(~"def"), d));
|
assert!(map.insert(Owned(~"def"), d));
|
||||||
|
|
||||||
assert!(!map.insert(SendStrStatic("abc"), a));
|
assert!(!map.insert(Slice("abc"), a));
|
||||||
assert!(!map.insert(SendStrOwned(~"bcd"), b));
|
assert!(!map.insert(Owned(~"bcd"), b));
|
||||||
assert!(!map.insert(SendStrStatic("cde"), c));
|
assert!(!map.insert(Slice("cde"), c));
|
||||||
assert!(!map.insert(SendStrOwned(~"def"), d));
|
assert!(!map.insert(Owned(~"def"), d));
|
||||||
|
|
||||||
assert!(!map.insert(SendStrOwned(~"abc"), a));
|
assert!(!map.insert(Owned(~"abc"), a));
|
||||||
assert!(!map.insert(SendStrStatic("bcd"), b));
|
assert!(!map.insert(Slice("bcd"), b));
|
||||||
assert!(!map.insert(SendStrOwned(~"cde"), c));
|
assert!(!map.insert(Owned(~"cde"), c));
|
||||||
assert!(!map.insert(SendStrStatic("def"), d));
|
assert!(!map.insert(Slice("def"), d));
|
||||||
|
|
||||||
assert_eq!(map.find_equiv(&("abc")), Some(&a));
|
assert_eq!(map.find_equiv(&("abc")), Some(&a));
|
||||||
assert_eq!(map.find_equiv(&("bcd")), Some(&b));
|
assert_eq!(map.find_equiv(&("bcd")), Some(&b));
|
||||||
@ -63,13 +62,13 @@ pub fn main() {
|
|||||||
assert_eq!(map.find_equiv(&(~"cde")), Some(&c));
|
assert_eq!(map.find_equiv(&(~"cde")), Some(&c));
|
||||||
assert_eq!(map.find_equiv(&(~"def")), Some(&d));
|
assert_eq!(map.find_equiv(&(~"def")), Some(&d));
|
||||||
|
|
||||||
assert_eq!(map.find_equiv(&SendStrStatic("abc")), Some(&a));
|
assert_eq!(map.find_equiv(&Slice("abc")), Some(&a));
|
||||||
assert_eq!(map.find_equiv(&SendStrStatic("bcd")), Some(&b));
|
assert_eq!(map.find_equiv(&Slice("bcd")), Some(&b));
|
||||||
assert_eq!(map.find_equiv(&SendStrStatic("cde")), Some(&c));
|
assert_eq!(map.find_equiv(&Slice("cde")), Some(&c));
|
||||||
assert_eq!(map.find_equiv(&SendStrStatic("def")), Some(&d));
|
assert_eq!(map.find_equiv(&Slice("def")), Some(&d));
|
||||||
|
|
||||||
assert_eq!(map.find_equiv(&SendStrOwned(~"abc")), Some(&a));
|
assert_eq!(map.find_equiv(&Owned(~"abc")), Some(&a));
|
||||||
assert_eq!(map.find_equiv(&SendStrOwned(~"bcd")), Some(&b));
|
assert_eq!(map.find_equiv(&Owned(~"bcd")), Some(&b));
|
||||||
assert_eq!(map.find_equiv(&SendStrOwned(~"cde")), Some(&c));
|
assert_eq!(map.find_equiv(&Owned(~"cde")), Some(&c));
|
||||||
assert_eq!(map.find_equiv(&SendStrOwned(~"def")), Some(&d));
|
assert_eq!(map.find_equiv(&Owned(~"def")), Some(&d));
|
||||||
}
|
}
|
||||||
|
@ -15,57 +15,56 @@ use std::cmp::{TotalEq, Ord, TotalOrd, Equiv};
|
|||||||
use std::cmp::Equal;
|
use std::cmp::Equal;
|
||||||
use std::container::{Container, Map, MutableMap};
|
use std::container::{Container, Map, MutableMap};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::send_str::{SendStr, SendStrOwned, SendStrStatic};
|
use std::str::{Str, SendStr, Owned, Slice};
|
||||||
use std::str::Str;
|
|
||||||
use std::to_str::ToStr;
|
use std::to_str::ToStr;
|
||||||
use self::collections::TreeMap;
|
use self::collections::TreeMap;
|
||||||
use std::option::Some;
|
use std::option::Some;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let mut map: TreeMap<SendStr, uint> = TreeMap::new();
|
let mut map: TreeMap<SendStr, uint> = TreeMap::new();
|
||||||
assert!(map.insert(SendStrStatic("foo"), 42));
|
assert!(map.insert(Slice("foo"), 42));
|
||||||
assert!(!map.insert(SendStrOwned(~"foo"), 42));
|
assert!(!map.insert(Owned(~"foo"), 42));
|
||||||
assert!(!map.insert(SendStrStatic("foo"), 42));
|
assert!(!map.insert(Slice("foo"), 42));
|
||||||
assert!(!map.insert(SendStrOwned(~"foo"), 42));
|
assert!(!map.insert(Owned(~"foo"), 42));
|
||||||
|
|
||||||
assert!(!map.insert(SendStrStatic("foo"), 43));
|
assert!(!map.insert(Slice("foo"), 43));
|
||||||
assert!(!map.insert(SendStrOwned(~"foo"), 44));
|
assert!(!map.insert(Owned(~"foo"), 44));
|
||||||
assert!(!map.insert(SendStrStatic("foo"), 45));
|
assert!(!map.insert(Slice("foo"), 45));
|
||||||
assert!(!map.insert(SendStrOwned(~"foo"), 46));
|
assert!(!map.insert(Owned(~"foo"), 46));
|
||||||
|
|
||||||
let v = 46;
|
let v = 46;
|
||||||
|
|
||||||
assert_eq!(map.find(&SendStrOwned(~"foo")), Some(&v));
|
assert_eq!(map.find(&Owned(~"foo")), Some(&v));
|
||||||
assert_eq!(map.find(&SendStrStatic("foo")), Some(&v));
|
assert_eq!(map.find(&Slice("foo")), Some(&v));
|
||||||
|
|
||||||
let (a, b, c, d) = (50, 51, 52, 53);
|
let (a, b, c, d) = (50, 51, 52, 53);
|
||||||
|
|
||||||
assert!(map.insert(SendStrStatic("abc"), a));
|
assert!(map.insert(Slice("abc"), a));
|
||||||
assert!(map.insert(SendStrOwned(~"bcd"), b));
|
assert!(map.insert(Owned(~"bcd"), b));
|
||||||
assert!(map.insert(SendStrStatic("cde"), c));
|
assert!(map.insert(Slice("cde"), c));
|
||||||
assert!(map.insert(SendStrOwned(~"def"), d));
|
assert!(map.insert(Owned(~"def"), d));
|
||||||
|
|
||||||
assert!(!map.insert(SendStrStatic("abc"), a));
|
assert!(!map.insert(Slice("abc"), a));
|
||||||
assert!(!map.insert(SendStrOwned(~"bcd"), b));
|
assert!(!map.insert(Owned(~"bcd"), b));
|
||||||
assert!(!map.insert(SendStrStatic("cde"), c));
|
assert!(!map.insert(Slice("cde"), c));
|
||||||
assert!(!map.insert(SendStrOwned(~"def"), d));
|
assert!(!map.insert(Owned(~"def"), d));
|
||||||
|
|
||||||
assert!(!map.insert(SendStrOwned(~"abc"), a));
|
assert!(!map.insert(Owned(~"abc"), a));
|
||||||
assert!(!map.insert(SendStrStatic("bcd"), b));
|
assert!(!map.insert(Slice("bcd"), b));
|
||||||
assert!(!map.insert(SendStrOwned(~"cde"), c));
|
assert!(!map.insert(Owned(~"cde"), c));
|
||||||
assert!(!map.insert(SendStrStatic("def"), d));
|
assert!(!map.insert(Slice("def"), d));
|
||||||
|
|
||||||
assert_eq!(map.find(&SendStrStatic("abc")), Some(&a));
|
assert_eq!(map.find(&Slice("abc")), Some(&a));
|
||||||
assert_eq!(map.find(&SendStrStatic("bcd")), Some(&b));
|
assert_eq!(map.find(&Slice("bcd")), Some(&b));
|
||||||
assert_eq!(map.find(&SendStrStatic("cde")), Some(&c));
|
assert_eq!(map.find(&Slice("cde")), Some(&c));
|
||||||
assert_eq!(map.find(&SendStrStatic("def")), Some(&d));
|
assert_eq!(map.find(&Slice("def")), Some(&d));
|
||||||
|
|
||||||
assert_eq!(map.find(&SendStrOwned(~"abc")), Some(&a));
|
assert_eq!(map.find(&Owned(~"abc")), Some(&a));
|
||||||
assert_eq!(map.find(&SendStrOwned(~"bcd")), Some(&b));
|
assert_eq!(map.find(&Owned(~"bcd")), Some(&b));
|
||||||
assert_eq!(map.find(&SendStrOwned(~"cde")), Some(&c));
|
assert_eq!(map.find(&Owned(~"cde")), Some(&c));
|
||||||
assert_eq!(map.find(&SendStrOwned(~"def")), Some(&d));
|
assert_eq!(map.find(&Owned(~"def")), Some(&d));
|
||||||
|
|
||||||
assert!(map.pop(&SendStrStatic("foo")).is_some());
|
assert!(map.pop(&Slice("foo")).is_some());
|
||||||
assert_eq!(map.move_iter().map(|(k, v)| k.to_str() + v.to_str())
|
assert_eq!(map.move_iter().map(|(k, v)| k.to_str() + v.to_str())
|
||||||
.to_owned_vec()
|
.to_owned_vec()
|
||||||
.concat(),
|
.concat(),
|
||||||
|
Loading…
Reference in New Issue
Block a user