libstd: Remove all uses of `~str` from `libstd`

This commit is contained in:
Patrick Walton 2014-05-19 17:23:26 -07:00
parent a9dd903d79
commit 5633d4641f
30 changed files with 238 additions and 262 deletions

View File

@ -538,7 +538,7 @@ impl Bitv {
* The resulting string has the same length as `self`, and each * The resulting string has the same length as `self`, and each
* character is either '0' or '1'. * character is either '0' or '1'.
*/ */
pub fn to_str(&self) -> ~str { pub fn to_str(&self) -> StrBuf {
let mut rs = StrBuf::new(); let mut rs = StrBuf::new();
for i in self.iter() { for i in self.iter() {
if i { if i {
@ -547,7 +547,7 @@ impl Bitv {
rs.push_char('0'); rs.push_char('0');
} }
}; };
rs.into_owned() rs
} }

View File

@ -661,7 +661,7 @@ pub fn getopts(args: &[StrBuf], optgrps: &[OptGroup]) -> Result {
/// Derive a usage message from a set of long options. /// Derive a usage message from a set of long options.
pub fn usage(brief: &str, opts: &[OptGroup]) -> StrBuf { pub fn usage(brief: &str, opts: &[OptGroup]) -> StrBuf {
let desc_sep = "\n" + " ".repeat(24); let desc_sep = format!("\n{}", " ".repeat(24));
let mut rows = opts.iter().map(|optref| { let mut rows = opts.iter().map(|optref| {
let OptGroup{short_name: short_name, let OptGroup{short_name: short_name,
@ -713,7 +713,7 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> StrBuf {
row.push_char(' '); row.push_char(' ');
} }
} else { } else {
row.push_str(desc_sep) row.push_str(desc_sep.as_slice())
} }
// Normalize desc to contain words separated by one space character // Normalize desc to contain words separated by one space character
@ -734,7 +734,7 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> StrBuf {
// FIXME: #5516 should be graphemes not codepoints // FIXME: #5516 should be graphemes not codepoints
// wrapped description // wrapped description
row.push_str(desc_rows.connect(desc_sep)); row.push_str(desc_rows.connect(desc_sep.as_slice()).as_slice());
row row
}); });
@ -784,7 +784,11 @@ fn format_option(opt: &OptGroup) -> StrBuf {
/// Derive a short one-line usage summary from a set of long options. /// Derive a short one-line usage summary from a set of long options.
pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> StrBuf { pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> StrBuf {
let mut line = format_strbuf!("Usage: {} ", program_name); let mut line = format_strbuf!("Usage: {} ", program_name);
line.push_str(opts.iter().map(format_option).collect::<Vec<StrBuf>>().connect(" ")); line.push_str(opts.iter()
.map(format_option)
.collect::<Vec<StrBuf>>()
.connect(" ")
.as_slice());
line line
} }

View File

@ -369,7 +369,8 @@ pub mod write {
sess.note(format!("{}", &cmd).as_slice()); sess.note(format!("{}", &cmd).as_slice());
let mut note = prog.error.clone(); let mut note = prog.error.clone();
note.push_all(prog.output.as_slice()); note.push_all(prog.output.as_slice());
sess.note(str::from_utf8(note.as_slice()).unwrap().to_owned()); sess.note(str::from_utf8(note.as_slice()).unwrap()
.as_slice());
sess.abort_if_errors(); sess.abort_if_errors();
} }
}, },
@ -538,8 +539,8 @@ pub fn find_crate_id(attrs: &[ast::Attribute], out_filestem: &str) -> CrateId {
match attr::find_crateid(attrs) { match attr::find_crateid(attrs) {
None => from_str(out_filestem).unwrap_or_else(|| { None => from_str(out_filestem).unwrap_or_else(|| {
let mut s = out_filestem.chars().filter(|c| c.is_XID_continue()); let mut s = out_filestem.chars().filter(|c| c.is_XID_continue());
from_str(s.collect::<StrBuf>() from_str(s.collect::<StrBuf>().as_slice())
.to_owned()).or(from_str("rust-out")).unwrap() .or(from_str("rust-out")).unwrap()
}), }),
Some(s) => s, Some(s) => s,
} }
@ -698,7 +699,7 @@ pub fn exported_name(path: PathElems, hash: &str, vers: &str) -> StrBuf {
// The version will get mangled to have a leading '_', but it makes more // The version will get mangled to have a leading '_', but it makes more
// sense to lead with a 'v' b/c this is a version... // sense to lead with a 'v' b/c this is a version...
let vers = if vers.len() > 0 && !char::is_XID_start(vers.char_at(0)) { let vers = if vers.len() > 0 && !char::is_XID_start(vers.char_at(0)) {
"v" + vers format!("v{}", vers)
} else { } else {
vers.to_owned() vers.to_owned()
}; };
@ -1075,7 +1076,8 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
sess.note(format!("{}", &cmd).as_slice()); sess.note(format!("{}", &cmd).as_slice());
let mut output = prog.error.clone(); let mut output = prog.error.clone();
output.push_all(prog.output.as_slice()); output.push_all(prog.output.as_slice());
sess.note(str::from_utf8(output.as_slice()).unwrap().to_owned()); sess.note(str::from_utf8(output.as_slice()).unwrap()
.as_slice());
sess.abort_if_errors(); sess.abort_if_errors();
} }
}, },

View File

@ -143,8 +143,8 @@ Available lint options:
for &(_, name) in lint_dict.iter() { for &(_, name) in lint_dict.iter() {
max_key = cmp::max(name.len(), max_key); max_key = cmp::max(name.len(), max_key);
} }
fn padded(max: uint, s: &str) -> ~str { fn padded(max: uint, s: &str) -> StrBuf {
" ".repeat(max - s.len()) + s format!("{}{}", " ".repeat(max - s.len()), s)
} }
println!("\nAvailable lint checks:\n"); println!("\nAvailable lint checks:\n");
println!(" {} {:7.7s} {}", println!(" {} {:7.7s} {}",
@ -154,7 +154,7 @@ Available lint options:
for (spec, name) in lint_dict.move_iter() { for (spec, name) in lint_dict.move_iter() {
let name = name.replace("_", "-"); let name = name.replace("_", "-");
println!(" {} {:7.7s} {}", println!(" {} {:7.7s} {}",
padded(max_key, name), padded(max_key, name.as_slice()),
lint::level_to_str(spec.default), lint::level_to_str(spec.default),
spec.desc); spec.desc);
} }
@ -400,11 +400,12 @@ fn monitor(f: proc():Send) {
let xs = [ let xs = [
"the compiler hit an unexpected failure path. this is a bug.".to_owned(), "the compiler hit an unexpected failure path. this is a bug.".to_owned(),
"we would appreciate a bug report: " + BUG_REPORT_URL, format!("we would appreciate a bug report: {}",
BUG_REPORT_URL),
"run with `RUST_BACKTRACE=1` for a backtrace".to_owned(), "run with `RUST_BACKTRACE=1` for a backtrace".to_owned(),
]; ];
for note in xs.iter() { for note in xs.iter() {
emitter.emit(None, *note, diagnostic::Note) emitter.emit(None, note.as_slice(), diagnostic::Note)
} }
match r.read_to_str() { match r.read_to_str() {

View File

@ -602,7 +602,7 @@ fn encode_visibility(ebml_w: &mut Encoder, visibility: Visibility) {
Public => 'y', Public => 'y',
Inherited => 'i', Inherited => 'i',
}; };
ebml_w.wr_str(str::from_char(ch)); ebml_w.wr_str(str::from_char(ch).as_slice());
ebml_w.end_tag(); ebml_w.end_tag();
} }
@ -848,7 +848,7 @@ fn encode_sized(ebml_w: &mut Encoder, sized: Sized) {
DynSize => 'd', DynSize => 'd',
StaticSize => 's', StaticSize => 's',
}; };
ebml_w.wr_str(str::from_char(ch)); ebml_w.wr_str(str::from_char(ch).as_slice());
ebml_w.end_tag(); ebml_w.end_tag();
} }
@ -1885,5 +1885,5 @@ pub fn encoded_ty(tcx: &ty::ctxt, t: ty::t) -> StrBuf {
tcx: tcx, tcx: tcx,
abbrevs: &RefCell::new(HashMap::new()) abbrevs: &RefCell::new(HashMap::new())
}, t); }, t);
str::from_utf8_owned(wr.get_ref().to_owned()).unwrap().to_strbuf() str::from_utf8_owned(Vec::from_slice(wr.get_ref())).unwrap().to_strbuf()
} }

View File

@ -552,7 +552,7 @@ fn get_metadata_section_imp(os: Os, filename: &Path) -> Result<MetadataBlob, Str
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
let name = str::raw::from_buf_len(name_buf as *u8, name_len as uint); let name = str::raw::from_buf_len(name_buf as *u8, name_len as uint);
debug!("get_metadata_section: name {}", name); debug!("get_metadata_section: name {}", name);
if read_meta_section_name(os) == name { if read_meta_section_name(os).as_slice() == name.as_slice() {
let cbuf = llvm::LLVMGetSectionContents(si.llsi); let cbuf = llvm::LLVMGetSectionContents(si.llsi);
let csz = llvm::LLVMGetSectionSize(si.llsi) as uint; let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
let mut found = let mut found =

View File

@ -452,7 +452,7 @@ fn parse_abi_set(st: &mut PState) -> abi::Abi {
assert_eq!(next(st), '['); assert_eq!(next(st), '[');
scan(st, |c| c == ']', |bytes| { scan(st, |c| c == ']', |bytes| {
let abi_str = str::from_utf8(bytes).unwrap().to_owned(); let abi_str = str::from_utf8(bytes).unwrap().to_owned();
abi::lookup(abi_str).expect(abi_str) abi::lookup(abi_str.as_slice()).expect(abi_str)
}) })
} }

View File

@ -37,7 +37,8 @@ fn replace_newline_with_backslash_l(s: StrBuf) -> StrBuf {
// \l, not the line that follows; so, add \l at end of string // \l, not the line that follows; so, add \l at end of string
// if not already present, ensuring last line gets left-aligned // if not already present, ensuring last line gets left-aligned
// as well. // as well.
let mut last_two : Vec<_> = s.chars().rev().take(2).collect(); let mut last_two: Vec<_> =
s.as_slice().chars().rev().take(2).collect();
last_two.reverse(); last_two.reverse();
if last_two.as_slice() != ['\\', 'l'] { if last_two.as_slice() != ['\\', 'l'] {
s = s.append("\\l"); s = s.append("\\l");

View File

@ -67,7 +67,8 @@ pub fn trans_inline_asm<'a>(bcx: &'a Block<'a>, ia: &ast::InlineAsm)
StrBuf::from_str(constraints.iter() StrBuf::from_str(constraints.iter()
.map(|s| s.get().to_strbuf()) .map(|s| s.get().to_strbuf())
.collect::<Vec<StrBuf>>() .collect::<Vec<StrBuf>>()
.connect(",")); .connect(",")
.as_slice());
let mut clobbers = getClobbers(); let mut clobbers = getClobbers();
if !ia.clobbers.get().is_empty() && !clobbers.is_empty() { if !ia.clobbers.get().is_empty() && !clobbers.is_empty() {

View File

@ -454,7 +454,10 @@ pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> tydesc_info {
fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type, fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type,
name: &str) -> ValueRef { name: &str) -> ValueRef {
let _icx = push_ctxt("declare_generic_glue"); let _icx = push_ctxt("declare_generic_glue");
let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, "glue_".to_owned() + name); let fn_nm = mangle_internal_name_by_type_and_seq(
ccx,
t,
format!("glue_{}", name).as_slice());
debug!("{} is for type {}", fn_nm, ppaux::ty_to_str(ccx.tcx(), t)); debug!("{} is for type {}", fn_nm, ppaux::ty_to_str(ccx.tcx(), t));
let llfn = decl_cdecl_fn(ccx.llmod, let llfn = decl_cdecl_fn(ccx.llmod,
fn_nm.as_slice(), fn_nm.as_slice(),

View File

@ -87,7 +87,8 @@ impl<'a, 'b> Reflector<'a, 'b> {
pub fn visit(&mut self, ty_name: &str, args: &[ValueRef]) { pub fn visit(&mut self, ty_name: &str, args: &[ValueRef]) {
let fcx = self.bcx.fcx; let fcx = self.bcx.fcx;
let tcx = self.bcx.tcx(); let tcx = self.bcx.tcx();
let mth_idx = ty::method_idx(token::str_to_ident("visit_".to_owned() + ty_name), let mth_idx = ty::method_idx(token::str_to_ident(format!(
"visit_{}", ty_name).as_slice()),
self.visitor_methods.as_slice()).expect( self.visitor_methods.as_slice()).expect(
format!("couldn't find visit method for {}", ty_name)); format!("couldn't find visit method for {}", ty_name));
let mth_ty = let mth_ty =
@ -154,7 +155,7 @@ impl<'a, 'b> Reflector<'a, 'b> {
ty::ty_vec(ref mt, Some(sz)) => { ty::ty_vec(ref mt, Some(sz)) => {
let extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice()); let extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice());
let extra = extra.append(self.c_mt(mt).as_slice()); let extra = extra.append(self.c_mt(mt).as_slice());
self.visit("evec_fixed".to_owned(), extra.as_slice()) self.visit("evec_fixed", extra.as_slice())
} }
ty::ty_vec(..) | ty::ty_str => fail!("unexpected unsized type"), ty::ty_vec(..) | ty::ty_str => fail!("unexpected unsized type"),
// Should remove mt from box and uniq. // Should remove mt from box and uniq.
@ -170,9 +171,9 @@ impl<'a, 'b> Reflector<'a, 'b> {
ty::ty_vec(ref mt, None) => { ty::ty_vec(ref mt, None) => {
let extra = Vec::new(); let extra = Vec::new();
let extra = extra.append(self.c_mt(mt).as_slice()); let extra = extra.append(self.c_mt(mt).as_slice());
self.visit("evec_uniq".to_owned(), extra.as_slice()) self.visit("evec_uniq", extra.as_slice())
} }
ty::ty_str => self.visit("estr_uniq".to_owned(), &[]), ty::ty_str => self.visit("estr_uniq", &[]),
_ => { _ => {
let extra = self.c_mt(&ty::mt { let extra = self.c_mt(&ty::mt {
ty: typ, ty: typ,
@ -191,9 +192,10 @@ impl<'a, 'b> Reflector<'a, 'b> {
ty::ty_vec(ref mt, None) => { ty::ty_vec(ref mt, None) => {
let (name, extra) = ("slice".to_owned(), Vec::new()); let (name, extra) = ("slice".to_owned(), Vec::new());
let extra = extra.append(self.c_mt(mt).as_slice()); let extra = extra.append(self.c_mt(mt).as_slice());
self.visit("evec_".to_owned() + name, extra.as_slice()) self.visit(format!("evec_{}", name).as_slice(),
extra.as_slice())
} }
ty::ty_str => self.visit("estr_slice".to_owned(), &[]), ty::ty_str => self.visit("estr_slice", &[]),
_ => { _ => {
let extra = self.c_mt(mt); let extra = self.c_mt(mt);
self.visit("rptr", extra.as_slice()) self.visit("rptr", extra.as_slice())

View File

@ -327,7 +327,7 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> StrBuf {
sig: &ty::FnSig) { sig: &ty::FnSig) {
s.push_char(bra); s.push_char(bra);
let strs: Vec<StrBuf> = sig.inputs.iter().map(|a| fn_input_to_str(cx, *a)).collect(); let strs: Vec<StrBuf> = sig.inputs.iter().map(|a| fn_input_to_str(cx, *a)).collect();
s.push_str(strs.connect(", ")); s.push_str(strs.connect(", ").as_slice());
if sig.variadic { if sig.variadic {
s.push_str(", ..."); s.push_str(", ...");
} }

View File

@ -425,7 +425,9 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
} }
fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) } fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) }
fn emit_char(&mut self, v: char) -> EncodeResult { self.emit_str(str::from_char(v)) } fn emit_char(&mut self, v: char) -> EncodeResult {
self.emit_str(str::from_char(v).as_slice())
}
fn emit_str(&mut self, v: &str) -> EncodeResult { fn emit_str(&mut self, v: &str) -> EncodeResult {
write!(self.wr, "{}", escape_str(v)) write!(self.wr, "{}", escape_str(v))
} }
@ -614,9 +616,13 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
fn emit_f64(&mut self, v: f64) -> EncodeResult { fn emit_f64(&mut self, v: f64) -> EncodeResult {
write!(self.wr, "{}", f64::to_str_digits(v, 6u)) write!(self.wr, "{}", f64::to_str_digits(v, 6u))
} }
fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) } fn emit_f32(&mut self, v: f32) -> EncodeResult {
self.emit_f64(v as f64)
}
fn emit_char(&mut self, v: char) -> EncodeResult { self.emit_str(str::from_char(v)) } fn emit_char(&mut self, v: char) -> EncodeResult {
self.emit_str(str::from_char(v).as_slice())
}
fn emit_str(&mut self, v: &str) -> EncodeResult { fn emit_str(&mut self, v: &str) -> EncodeResult {
write!(self.wr, "{}", escape_str(v)) write!(self.wr, "{}", escape_str(v))
} }

View File

@ -419,8 +419,8 @@ unsafe fn str_map_bytes(string: StrBuf, map: &'static [u8]) -> StrBuf {
#[inline] #[inline]
unsafe fn str_copy_map_bytes(string: &str, map: &'static [u8]) -> StrBuf { unsafe fn str_copy_map_bytes(string: &str, map: &'static [u8]) -> StrBuf {
let mut s = string.to_owned(); let mut s = string.to_strbuf();
for b in str::raw::as_owned_vec(&mut s).mut_iter() { for b in s.as_mut_bytes().mut_iter() {
*b = map[*b as uint]; *b = map[*b as uint];
} }
s.into_strbuf() s.into_strbuf()

View File

@ -323,29 +323,6 @@ impl<'a> ToCStr for &'a str {
} }
} }
impl ToCStr for ~str {
#[inline]
fn to_c_str(&self) -> CString {
self.as_bytes().to_c_str()
}
#[inline]
unsafe fn to_c_str_unchecked(&self) -> CString {
self.as_bytes().to_c_str_unchecked()
}
#[inline]
fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
self.as_bytes().with_c_str(f)
}
#[inline]
unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
self.as_bytes().with_c_str_unchecked(f)
}
}
impl ToCStr for StrBuf { impl ToCStr for StrBuf {
#[inline] #[inline]
fn to_c_str(&self) -> CString { fn to_c_str(&self) -> CString {

View File

@ -47,9 +47,9 @@
//! for which the [`slice`](slice/index.html) module defines many //! for which the [`slice`](slice/index.html) module defines many
//! methods. //! methods.
//! //!
//! UTF-8 strings, `~str` and `&str`, are built-in types, and the //! `&str`, a UTF-8 string, is a built-in type, and the standard library
//! standard library defines methods for them on a variety of traits //! defines methods for it on a variety of traits in the
//! in the [`str`](str/index.html) module. Rust strings are immutable; //! [`str`](str/index.html) module. Rust strings are immutable;
//! use the `StrBuf` type defined in [`strbuf`](strbuf/index.html) //! use the `StrBuf` type defined in [`strbuf`](strbuf/index.html)
//! for a mutable string builder. //! for a mutable string builder.
//! //!

View File

@ -17,37 +17,29 @@ Unicode string manipulation (`str` type)
Rust's string type is one of the core primitive types of the language. While Rust's string type is one of the core primitive types of the language. While
represented by the name `str`, the name `str` is not actually a valid type in represented by the name `str`, the name `str` is not actually a valid type in
Rust. Each string must also be decorated with its ownership. This means that Rust. Each string must also be decorated with its ownership. This means that
there are two common kinds of strings in Rust: there is one common kind of string in Rust:
* `~str` - This is an owned string. This type obeys all of the normal semantics
of the `Box<T>` types, meaning that it has one, and only one,
owner. This type cannot be implicitly copied, and is moved out of
when passed to other functions.
* `&str` - This is the borrowed string type. This type of string can only be * `&str` - This is the borrowed string type. This type of string can only be
created from the other kind of string. As the name "borrowed" created from the other kind of string. As the name "borrowed"
implies, this type of string is owned elsewhere, and this string implies, this type of string is owned elsewhere, and this string
cannot be moved out of. cannot be moved out of.
As an example, here's a few different kinds of strings. As an example, here's the one kind of string.
```rust ```rust
fn main() { fn main() {
let owned_string = "I am an owned string".to_owned(); let borrowed_string = "This string is borrowed with the 'static lifetime";
let borrowed_string1 = "This string is borrowed with the 'static lifetime";
let borrowed_string2: &str = owned_string; // owned strings can be borrowed
} }
``` ```
From the example above, you can see that Rust has 2 different kinds of string From the example above, you can see that Rust has 1 different kind of string
literals. The owned literals correspond to the owned string types, but the literal. The "borrowed literal" is akin to C's concept of a static string.
"borrowed literal" is actually more akin to C's concept of a static string.
When a string is declared without a `~` sigil, then the string is allocated String literals are allocated statically in the rodata of the
statically in the rodata of the executable/library. The string then has the executable/library. The string then has the type `&'static str` meaning that
type `&'static str` meaning that the string is valid for the `'static` the string is valid for the `'static` lifetime, otherwise known as the
lifetime, otherwise known as the lifetime of the entire program. As can be lifetime of the entire program. As can be inferred from the type, these static
inferred from the type, these static strings are not mutable. strings are not mutable.
# Mutability # Mutability
@ -67,10 +59,8 @@ stream of UTF-8 bytes. All safely-created strings are guaranteed to be validly
encoded UTF-8 sequences. Additionally, strings are not null-terminated encoded UTF-8 sequences. Additionally, strings are not null-terminated
and can contain null codepoints. and can contain null codepoints.
The actual representation of strings have direct mappings to vectors: The actual representation of strings have direct mappings to vectors: `&str`
is the same as `&[u8]`.
* `~str` is the same as `~[u8]`
* `&str` is the same as `&[u8]`
*/ */
@ -81,13 +71,12 @@ use cmp::{Eq, TotalEq, Ord, TotalOrd, Equiv, Ordering};
use container::Container; use container::Container;
use default::Default; use default::Default;
use fmt; use fmt;
use from_str::FromStr;
use io::Writer; use io::Writer;
use iter::{Iterator, range, AdditiveIterator}; use iter::{Iterator, range, AdditiveIterator};
use mem::transmute; use mem::transmute;
use mem; use mem;
use option::{None, Option, Some}; use option::{None, Option, Some};
use result::{Result, Ok, Err}; use result::Result;
use slice::Vector; use slice::Vector;
use slice::{ImmutableVector, MutableVector, CloneableVector}; use slice::{ImmutableVector, MutableVector, CloneableVector};
use strbuf::StrBuf; use strbuf::StrBuf;
@ -109,17 +98,8 @@ Section: Creating a string
/// ///
/// Returns `Err` with the original vector if the vector contains invalid /// Returns `Err` with the original vector if the vector contains invalid
/// UTF-8. /// UTF-8.
pub fn from_utf8_owned(vv: ~[u8]) -> Result<~str, ~[u8]> { pub fn from_utf8_owned(vv: Vec<u8>) -> Result<StrBuf, Vec<u8>> {
if is_utf8(vv) { StrBuf::from_utf8(vv)
Ok(unsafe { raw::from_utf8_owned(vv) })
} else {
Err(vv)
}
}
impl FromStr for ~str {
#[inline]
fn from_str(s: &str) -> Option<~str> { Some(s.to_owned()) }
} }
/// Convert a byte to a UTF-8 string /// Convert a byte to a UTF-8 string
@ -127,35 +107,37 @@ impl FromStr for ~str {
/// # Failure /// # Failure
/// ///
/// Fails if invalid UTF-8 /// Fails if invalid UTF-8
pub fn from_byte(b: u8) -> ~str { pub fn from_byte(b: u8) -> StrBuf {
assert!(b < 128u8); assert!(b < 128u8);
unsafe { ::mem::transmute(box [b]) } StrBuf::from_char(1, b as char)
} }
/// Convert a char to a string /// Convert a char to a string
pub fn from_char(ch: char) -> ~str { pub fn from_char(ch: char) -> StrBuf {
let mut buf = StrBuf::new(); let mut buf = StrBuf::new();
buf.push_char(ch); buf.push_char(ch);
buf.into_owned() buf
} }
/// Convert a vector of chars to a string /// Convert a vector of chars to a string
pub fn from_chars(chs: &[char]) -> ~str { pub fn from_chars(chs: &[char]) -> StrBuf {
chs.iter().map(|c| *c).collect() chs.iter().map(|c| *c).collect()
} }
/// Methods for vectors of strings /// Methods for vectors of strings
pub trait StrVector { pub trait StrVector {
/// Concatenate a vector of strings. /// Concatenate a vector of strings.
fn concat(&self) -> ~str; fn concat(&self) -> StrBuf;
/// Concatenate a vector of strings, placing a given separator between each. /// Concatenate a vector of strings, placing a given separator between each.
fn connect(&self, sep: &str) -> ~str; fn connect(&self, sep: &str) -> StrBuf;
} }
impl<'a, S: Str> StrVector for &'a [S] { impl<'a, S: Str> StrVector for &'a [S] {
fn concat(&self) -> ~str { fn concat(&self) -> StrBuf {
if self.is_empty() { return "".to_owned(); } if self.is_empty() {
return StrBuf::new();
}
// `len` calculation may overflow but push_str but will check boundaries // `len` calculation may overflow but push_str but will check boundaries
let len = self.iter().map(|s| s.as_slice().len()).sum(); let len = self.iter().map(|s| s.as_slice().len()).sum();
@ -166,14 +148,18 @@ impl<'a, S: Str> StrVector for &'a [S] {
result.push_str(s.as_slice()) result.push_str(s.as_slice())
} }
result.into_owned() result
} }
fn connect(&self, sep: &str) -> ~str { fn connect(&self, sep: &str) -> StrBuf {
if self.is_empty() { return "".to_owned(); } if self.is_empty() {
return StrBuf::new();
}
// concat is faster // concat is faster
if sep.is_empty() { return self.concat(); } if sep.is_empty() {
return self.concat();
}
// this is wrong without the guarantee that `self` is non-empty // this is wrong without the guarantee that `self` is non-empty
// `len` calculation may overflow but push_str but will check boundaries // `len` calculation may overflow but push_str but will check boundaries
@ -190,18 +176,18 @@ impl<'a, S: Str> StrVector for &'a [S] {
} }
result.push_str(s.as_slice()); result.push_str(s.as_slice());
} }
result.into_owned() result
} }
} }
impl<'a, S: Str> StrVector for Vec<S> { impl<'a, S: Str> StrVector for Vec<S> {
#[inline] #[inline]
fn concat(&self) -> ~str { fn concat(&self) -> StrBuf {
self.as_slice().concat() self.as_slice().concat()
} }
#[inline] #[inline]
fn connect(&self, sep: &str) -> ~str { fn connect(&self, sep: &str) -> StrBuf {
self.as_slice().connect(sep) self.as_slice().connect(sep)
} }
} }
@ -317,7 +303,7 @@ impl<'a> Iterator<char> for Decompositions<'a> {
/// # Return value /// # Return value
/// ///
/// The original string with all occurrences of `from` replaced with `to` /// The original string with all occurrences of `from` replaced with `to`
pub fn replace(s: &str, from: &str, to: &str) -> ~str { pub fn replace(s: &str, from: &str, to: &str) -> StrBuf {
let mut result = StrBuf::new(); let mut result = StrBuf::new();
let mut last_end = 0; let mut last_end = 0;
for (start, end) in s.match_indices(from) { for (start, end) in s.match_indices(from) {
@ -326,7 +312,7 @@ pub fn replace(s: &str, from: &str, to: &str) -> ~str {
last_end = end; last_end = end;
} }
result.push_str(unsafe{raw::slice_bytes(s, last_end, s.len())}); result.push_str(unsafe{raw::slice_bytes(s, last_end, s.len())});
result.into_owned() result
} }
/* /*
@ -350,7 +336,7 @@ Section: Misc
/// v[4] = 0xD800; /// v[4] = 0xD800;
/// assert_eq!(str::from_utf16(v), None); /// assert_eq!(str::from_utf16(v), None);
/// ``` /// ```
pub fn from_utf16(v: &[u16]) -> Option<~str> { pub fn from_utf16(v: &[u16]) -> Option<StrBuf> {
let mut s = StrBuf::with_capacity(v.len() / 2); let mut s = StrBuf::with_capacity(v.len() / 2);
for c in utf16_items(v) { for c in utf16_items(v) {
match c { match c {
@ -358,7 +344,7 @@ pub fn from_utf16(v: &[u16]) -> Option<~str> {
LoneSurrogate(_) => return None LoneSurrogate(_) => return None
} }
} }
Some(s.into_owned()) Some(s)
} }
/// Decode a UTF-16 encoded vector `v` into a string, replacing /// Decode a UTF-16 encoded vector `v` into a string, replacing
@ -376,7 +362,7 @@ pub fn from_utf16(v: &[u16]) -> Option<~str> {
/// assert_eq!(str::from_utf16_lossy(v), /// assert_eq!(str::from_utf16_lossy(v),
/// "𝄞mus\uFFFDic\uFFFD".to_owned()); /// "𝄞mus\uFFFDic\uFFFD".to_owned());
/// ``` /// ```
pub fn from_utf16_lossy(v: &[u16]) -> ~str { pub fn from_utf16_lossy(v: &[u16]) -> StrBuf {
utf16_items(v).map(|c| c.to_char_lossy()).collect() utf16_items(v).map(|c| c.to_char_lossy()).collect()
} }
@ -523,14 +509,14 @@ pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> MaybeOwned<'a> {
Section: MaybeOwned Section: MaybeOwned
*/ */
/// A MaybeOwned is a string that can hold either a ~str or a &str. /// A MaybeOwned is a string that can hold either a StrBuf or a &str.
/// This can be useful as an optimization when an allocation is sometimes /// This can be useful as an optimization when an allocation is sometimes
/// needed but not always. /// needed but not always.
pub enum MaybeOwned<'a> { pub enum MaybeOwned<'a> {
/// A borrowed string /// A borrowed string
Slice(&'a str), Slice(&'a str),
/// An owned string /// An owned string
Owned(~str) Owned(StrBuf)
} }
/// SendStr is a specialization of `MaybeOwned` to be sendable /// SendStr is a specialization of `MaybeOwned` to be sendable
@ -562,15 +548,10 @@ pub trait IntoMaybeOwned<'a> {
fn into_maybe_owned(self) -> MaybeOwned<'a>; 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 StrBuf { impl<'a> IntoMaybeOwned<'a> for StrBuf {
#[inline] #[inline]
fn into_maybe_owned(self) -> MaybeOwned<'a> { fn into_maybe_owned(self) -> MaybeOwned<'a> {
Owned(self.into_owned()) Owned(self)
} }
} }
@ -626,7 +607,7 @@ impl<'a> Str for MaybeOwned<'a> {
impl<'a> StrAllocating for MaybeOwned<'a> { impl<'a> StrAllocating for MaybeOwned<'a> {
#[inline] #[inline]
fn into_owned(self) -> ~str { fn into_owned(self) -> StrBuf {
match self { match self {
Slice(s) => s.to_owned(), Slice(s) => s.to_owned(),
Owned(s) => s Owned(s) => s
@ -676,58 +657,37 @@ impl<'a> fmt::Show for MaybeOwned<'a> {
/// Unsafe operations /// Unsafe operations
pub mod raw { pub mod raw {
use c_str::CString;
use libc; use libc;
use mem; use mem;
use ptr::RawPtr; use strbuf::StrBuf;
use raw::Slice; use vec::Vec;
use slice::CloneableVector;
use str::{is_utf8, StrAllocating};
pub use core::str::raw::{from_utf8, c_str_to_static_slice, slice_bytes}; pub use core::str::raw::{from_utf8, c_str_to_static_slice, slice_bytes};
pub use core::str::raw::{slice_unchecked}; pub use core::str::raw::{slice_unchecked};
/// Create a Rust string from a *u8 buffer of the given length /// Create a Rust string from a *u8 buffer of the given length
pub unsafe fn from_buf_len(buf: *u8, len: uint) -> ~str { pub unsafe fn from_buf_len(buf: *u8, len: uint) -> StrBuf {
let v = Slice { data: buf, len: len }; StrBuf::from_raw_parts(len, len, mem::transmute(buf))
let bytes: &[u8] = ::mem::transmute(v);
assert!(is_utf8(bytes));
let s: &str = ::mem::transmute(bytes);
s.to_owned()
}
#[lang="strdup_uniq"]
#[cfg(not(test))]
#[inline]
unsafe fn strdup_uniq(ptr: *u8, len: uint) -> ~str {
from_buf_len(ptr, len)
} }
/// Create a Rust string from a null-terminated C string /// Create a Rust string from a null-terminated C string
pub unsafe fn from_c_str(buf: *libc::c_char) -> ~str { pub unsafe fn from_c_str(c_string: *libc::c_char) -> StrBuf {
let mut curr = buf; let mut buf = StrBuf::new();
let mut i = 0; buf.push_bytes(CString::new(c_string, false).as_bytes_no_nul());
while *curr != 0 { buf
i += 1;
curr = buf.offset(i);
}
from_buf_len(buf as *u8, i as uint)
} }
/// Converts an owned vector of bytes to a new owned string. This assumes /// Converts an owned vector of bytes to a new owned string. This assumes
/// that the utf-8-ness of the vector has already been validated /// that the utf-8-ness of the vector has already been validated
#[inline] #[inline]
pub unsafe fn from_utf8_owned(v: ~[u8]) -> ~str { pub unsafe fn from_utf8_owned(v: Vec<u8>) -> StrBuf {
mem::transmute(v) mem::transmute(v)
} }
/// Converts a byte to a string. /// Converts a byte to a string.
pub unsafe fn from_byte(u: u8) -> ~str { from_utf8_owned(box [u]) } pub unsafe fn from_byte(u: u8) -> StrBuf {
from_utf8_owned(vec![u])
/// Access the str in its vector representation.
/// The caller must preserve the valid UTF-8 property when modifying.
#[inline]
pub unsafe fn as_owned_vec<'a>(s: &'a mut ~str) -> &'a mut ~[u8] {
mem::transmute(s)
} }
/// Sets the length of a string /// Sets the length of a string
@ -755,8 +715,8 @@ Section: Trait implementations
/// Any string that can be represented as a slice /// Any string that can be represented as a slice
pub trait StrAllocating: Str { pub trait StrAllocating: Str {
/// Convert `self` into a ~str, not making a copy if possible. /// Convert `self` into a `StrBuf`, not making a copy if possible.
fn into_owned(self) -> ~str; fn into_owned(self) -> StrBuf;
/// Convert `self` into a `StrBuf`. /// Convert `self` into a `StrBuf`.
#[inline] #[inline]
@ -767,27 +727,27 @@ pub trait StrAllocating: Str {
/// Convert `self` into a `StrBuf`, not making a copy if possible. /// Convert `self` into a `StrBuf`, not making a copy if possible.
#[inline] #[inline]
fn into_strbuf(self) -> StrBuf { fn into_strbuf(self) -> StrBuf {
StrBuf::from_owned_str(self.into_owned()) self.into_owned()
} }
/// Escape each char in `s` with `char::escape_default`. /// Escape each char in `s` with `char::escape_default`.
fn escape_default(&self) -> ~str { fn escape_default(&self) -> StrBuf {
let me = self.as_slice(); let me = self.as_slice();
let mut out = StrBuf::with_capacity(me.len()); let mut out = StrBuf::with_capacity(me.len());
for c in me.chars() { for c in me.chars() {
c.escape_default(|c| out.push_char(c)); c.escape_default(|c| out.push_char(c));
} }
out.into_owned() out
} }
/// Escape each char in `s` with `char::escape_unicode`. /// Escape each char in `s` with `char::escape_unicode`.
fn escape_unicode(&self) -> ~str { fn escape_unicode(&self) -> StrBuf {
let me = self.as_slice(); let me = self.as_slice();
let mut out = StrBuf::with_capacity(me.len()); let mut out = StrBuf::with_capacity(me.len());
for c in me.chars() { for c in me.chars() {
c.escape_unicode(|c| out.push_char(c)); c.escape_unicode(|c| out.push_char(c));
} }
out.into_owned() out
} }
/// Replace all occurrences of one string with another. /// Replace all occurrences of one string with another.
@ -814,7 +774,7 @@ pub trait StrAllocating: Str {
/// // not found, so no change. /// // not found, so no change.
/// assert_eq!(s.replace("cookie monster", "little lamb"), s); /// assert_eq!(s.replace("cookie monster", "little lamb"), s);
/// ``` /// ```
fn replace(&self, from: &str, to: &str) -> ~str { fn replace(&self, from: &str, to: &str) -> StrBuf {
let me = self.as_slice(); let me = self.as_slice();
let mut result = StrBuf::new(); let mut result = StrBuf::new();
let mut last_end = 0; let mut last_end = 0;
@ -824,16 +784,16 @@ pub trait StrAllocating: Str {
last_end = end; last_end = end;
} }
result.push_str(unsafe{raw::slice_bytes(me, last_end, me.len())}); result.push_str(unsafe{raw::slice_bytes(me, last_end, me.len())});
result.into_owned() result
} }
/// Copy a slice into a new owned str. /// Copy a slice into a new `StrBuf`.
#[inline] #[inline]
fn to_owned(&self) -> ~str { fn to_owned(&self) -> StrBuf {
use slice::Vector; use slice::Vector;
unsafe { unsafe {
::mem::transmute(self.as_slice().as_bytes().to_owned()) ::mem::transmute(Vec::from_slice(self.as_slice().as_bytes()))
} }
} }
@ -850,13 +810,13 @@ pub trait StrAllocating: Str {
} }
/// Given a string, make a new string with repeated copies of it. /// Given a string, make a new string with repeated copies of it.
fn repeat(&self, nn: uint) -> ~str { fn repeat(&self, nn: uint) -> StrBuf {
let me = self.as_slice(); let me = self.as_slice();
let mut ret = StrBuf::with_capacity(nn * me.len()); let mut ret = StrBuf::with_capacity(nn * me.len());
for _ in range(0, nn) { for _ in range(0, nn) {
ret.push_str(me); ret.push_str(me);
} }
ret.into_owned() ret
} }
/// Levenshtein Distance between two strings. /// Levenshtein Distance between two strings.
@ -921,12 +881,9 @@ pub trait StrAllocating: Str {
impl<'a> StrAllocating for &'a str { impl<'a> StrAllocating for &'a str {
#[inline] #[inline]
fn into_owned(self) -> ~str { self.to_owned() } fn into_owned(self) -> StrBuf {
} self.to_owned()
}
impl<'a> StrAllocating for ~str {
#[inline]
fn into_owned(self) -> ~str { self }
} }
/// Methods for owned strings /// Methods for owned strings
@ -934,23 +891,23 @@ pub trait OwnedStr {
/// Consumes the string, returning the underlying byte buffer. /// Consumes the string, returning the underlying byte buffer.
/// ///
/// The buffer does not have a null terminator. /// The buffer does not have a null terminator.
fn into_bytes(self) -> ~[u8]; fn into_bytes(self) -> Vec<u8>;
/// Pushes the given string onto this string, returning the concatenation of the two strings. /// Pushes the given string onto this string, returning the concatenation of the two strings.
fn append(self, rhs: &str) -> ~str; fn append(self, rhs: &str) -> StrBuf;
} }
impl OwnedStr for ~str { impl OwnedStr for StrBuf {
#[inline] #[inline]
fn into_bytes(self) -> ~[u8] { fn into_bytes(self) -> Vec<u8> {
unsafe { mem::transmute(self) } unsafe { mem::transmute(self) }
} }
#[inline] #[inline]
fn append(self, rhs: &str) -> ~str { fn append(self, rhs: &str) -> StrBuf {
let mut new_str = StrBuf::from_owned_str(self); let mut new_str = StrBuf::from_owned_str(self);
new_str.push_str(rhs); new_str.push_str(rhs);
new_str.into_owned() new_str
} }
} }
@ -1027,10 +984,10 @@ mod tests {
#[test] #[test]
fn test_collect() { fn test_collect() {
let empty = "".to_owned(); let empty = "".to_owned();
let s: ~str = empty.chars().collect(); let s: StrBuf = empty.chars().collect();
assert_eq!(empty, s); assert_eq!(empty, s);
let data = "ประเทศไทย中".to_owned(); let data = "ประเทศไทย中".to_owned();
let s: ~str = data.chars().collect(); let s: StrBuf = data.chars().collect();
assert_eq!(data, s); assert_eq!(data, s);
} }
@ -1086,25 +1043,25 @@ mod tests {
#[test] #[test]
fn test_concat() { fn test_concat() {
fn t(v: &[~str], s: &str) { fn t(v: &[StrBuf], s: &str) {
assert_eq!(v.concat(), s.to_str().into_owned()); assert_eq!(v.concat(), s.to_str().into_owned());
} }
t(["you".to_owned(), "know".to_owned(), "I'm".to_owned(), t(["you".to_owned(), "know".to_owned(), "I'm".to_owned(),
"no".to_owned(), "good".to_owned()], "youknowI'mnogood"); "no".to_owned(), "good".to_owned()], "youknowI'mnogood");
let v: &[~str] = []; let v: &[StrBuf] = [];
t(v, ""); t(v, "");
t(["hi".to_owned()], "hi"); t(["hi".to_owned()], "hi");
} }
#[test] #[test]
fn test_connect() { fn test_connect() {
fn t(v: &[~str], sep: &str, s: &str) { fn t(v: &[StrBuf], sep: &str, s: &str) {
assert_eq!(v.connect(sep), s.to_str().into_owned()); assert_eq!(v.connect(sep), s.to_str().into_owned());
} }
t(["you".to_owned(), "know".to_owned(), "I'm".to_owned(), t(["you".to_owned(), "know".to_owned(), "I'm".to_owned(),
"no".to_owned(), "good".to_owned()], "no".to_owned(), "good".to_owned()],
" ", "you know I'm no good"); " ", "you know I'm no good");
let v: &[~str] = []; let v: &[StrBuf] = [];
t(v, " ", ""); t(v, " ", "");
t(["hi".to_owned()], " ", "hi"); t(["hi".to_owned()], " ", "hi");
} }
@ -1145,23 +1102,23 @@ mod tests {
assert_eq!("ab", unsafe {raw::slice_bytes("abc", 0, 2)}); assert_eq!("ab", unsafe {raw::slice_bytes("abc", 0, 2)});
assert_eq!("bc", unsafe {raw::slice_bytes("abc", 1, 3)}); assert_eq!("bc", unsafe {raw::slice_bytes("abc", 1, 3)});
assert_eq!("", unsafe {raw::slice_bytes("abc", 1, 1)}); assert_eq!("", unsafe {raw::slice_bytes("abc", 1, 1)});
fn a_million_letter_a() -> ~str { fn a_million_letter_a() -> StrBuf {
let mut i = 0; let mut i = 0;
let mut rs = StrBuf::new(); let mut rs = StrBuf::new();
while i < 100000 { while i < 100000 {
rs.push_str("aaaaaaaaaa"); rs.push_str("aaaaaaaaaa");
i += 1; i += 1;
} }
rs.into_owned() rs
} }
fn half_a_million_letter_a() -> ~str { fn half_a_million_letter_a() -> StrBuf {
let mut i = 0; let mut i = 0;
let mut rs = StrBuf::new(); let mut rs = StrBuf::new();
while i < 100000 { while i < 100000 {
rs.push_str("aaaaa"); rs.push_str("aaaaa");
i += 1; i += 1;
} }
rs.into_owned() rs
} }
let letters = a_million_letter_a(); let letters = a_million_letter_a();
assert!(half_a_million_letter_a() == assert!(half_a_million_letter_a() ==
@ -1260,23 +1217,23 @@ mod tests {
assert_eq!("", data.slice(3, 3)); assert_eq!("", data.slice(3, 3));
assert_eq!("", data.slice(30, 33)); assert_eq!("", data.slice(30, 33));
fn a_million_letter_X() -> ~str { fn a_million_letter_X() -> StrBuf {
let mut i = 0; let mut i = 0;
let mut rs = StrBuf::new(); let mut rs = StrBuf::new();
while i < 100000 { while i < 100000 {
rs.push_str("华华华华华华华华华华"); rs.push_str("华华华华华华华华华华");
i += 1; i += 1;
} }
rs.into_owned() rs
} }
fn half_a_million_letter_X() -> ~str { fn half_a_million_letter_X() -> StrBuf {
let mut i = 0; let mut i = 0;
let mut rs = StrBuf::new(); let mut rs = StrBuf::new();
while i < 100000 { while i < 100000 {
rs.push_str("华华华华华"); rs.push_str("华华华华华");
i += 1; i += 1;
} }
rs.into_owned() rs
} }
let letters = a_million_letter_X(); let letters = a_million_letter_X();
assert!(half_a_million_letter_X() == assert!(half_a_million_letter_X() ==
@ -1573,10 +1530,10 @@ mod tests {
#[test] #[test]
fn vec_str_conversions() { fn vec_str_conversions() {
let s1: ~str = "All mimsy were the borogoves".to_owned(); let s1: StrBuf = "All mimsy were the borogoves".to_strbuf();
let v: ~[u8] = s1.as_bytes().to_owned(); let v: Vec<u8> = Vec::from_slice(s1.as_bytes());
let s2: ~str = from_utf8(v).unwrap().to_owned(); let s2: StrBuf = from_utf8(v).unwrap().to_strbuf();
let mut i: uint = 0u; let mut i: uint = 0u;
let n1: uint = s1.len(); let n1: uint = s1.len();
let n2: uint = v.len(); let n2: uint = v.len();
@ -2027,30 +1984,30 @@ mod tests {
#[test] #[test]
fn test_nfd_chars() { fn test_nfd_chars() {
assert_eq!("abc".nfd_chars().collect::<~str>(), "abc".to_owned()); assert_eq!("abc".nfd_chars().collect::<StrBuf>(), "abc".to_strbuf());
assert_eq!("\u1e0b\u01c4".nfd_chars().collect::<~str>(), "d\u0307\u01c4".to_owned()); assert_eq!("\u1e0b\u01c4".nfd_chars().collect::<StrBuf>(), "d\u0307\u01c4".to_strbuf());
assert_eq!("\u2026".nfd_chars().collect::<~str>(), "\u2026".to_owned()); assert_eq!("\u2026".nfd_chars().collect::<StrBuf>(), "\u2026".to_strbuf());
assert_eq!("\u2126".nfd_chars().collect::<~str>(), "\u03a9".to_owned()); assert_eq!("\u2126".nfd_chars().collect::<StrBuf>(), "\u03a9".to_strbuf());
assert_eq!("\u1e0b\u0323".nfd_chars().collect::<~str>(), "d\u0323\u0307".to_owned()); assert_eq!("\u1e0b\u0323".nfd_chars().collect::<StrBuf>(), "d\u0323\u0307".to_strbuf());
assert_eq!("\u1e0d\u0307".nfd_chars().collect::<~str>(), "d\u0323\u0307".to_owned()); assert_eq!("\u1e0d\u0307".nfd_chars().collect::<StrBuf>(), "d\u0323\u0307".to_strbuf());
assert_eq!("a\u0301".nfd_chars().collect::<~str>(), "a\u0301".to_owned()); assert_eq!("a\u0301".nfd_chars().collect::<StrBuf>(), "a\u0301".to_strbuf());
assert_eq!("\u0301a".nfd_chars().collect::<~str>(), "\u0301a".to_owned()); assert_eq!("\u0301a".nfd_chars().collect::<StrBuf>(), "\u0301a".to_strbuf());
assert_eq!("\ud4db".nfd_chars().collect::<~str>(), "\u1111\u1171\u11b6".to_owned()); assert_eq!("\ud4db".nfd_chars().collect::<StrBuf>(), "\u1111\u1171\u11b6".to_strbuf());
assert_eq!("\uac1c".nfd_chars().collect::<~str>(), "\u1100\u1162".to_owned()); assert_eq!("\uac1c".nfd_chars().collect::<StrBuf>(), "\u1100\u1162".to_strbuf());
} }
#[test] #[test]
fn test_nfkd_chars() { fn test_nfkd_chars() {
assert_eq!("abc".nfkd_chars().collect::<~str>(), "abc".to_owned()); assert_eq!("abc".nfkd_chars().collect::<StrBuf>(), "abc".to_strbuf());
assert_eq!("\u1e0b\u01c4".nfkd_chars().collect::<~str>(), "d\u0307DZ\u030c".to_owned()); assert_eq!("\u1e0b\u01c4".nfkd_chars().collect::<StrBuf>(), "d\u0307DZ\u030c".to_strbuf());
assert_eq!("\u2026".nfkd_chars().collect::<~str>(), "...".to_owned()); assert_eq!("\u2026".nfkd_chars().collect::<StrBuf>(), "...".to_strbuf());
assert_eq!("\u2126".nfkd_chars().collect::<~str>(), "\u03a9".to_owned()); assert_eq!("\u2126".nfkd_chars().collect::<StrBuf>(), "\u03a9".to_strbuf());
assert_eq!("\u1e0b\u0323".nfkd_chars().collect::<~str>(), "d\u0323\u0307".to_owned()); assert_eq!("\u1e0b\u0323".nfkd_chars().collect::<StrBuf>(), "d\u0323\u0307".to_strbuf());
assert_eq!("\u1e0d\u0307".nfkd_chars().collect::<~str>(), "d\u0323\u0307".to_owned()); assert_eq!("\u1e0d\u0307".nfkd_chars().collect::<StrBuf>(), "d\u0323\u0307".to_strbuf());
assert_eq!("a\u0301".nfkd_chars().collect::<~str>(), "a\u0301".to_owned()); assert_eq!("a\u0301".nfkd_chars().collect::<StrBuf>(), "a\u0301".to_strbuf());
assert_eq!("\u0301a".nfkd_chars().collect::<~str>(), "\u0301a".to_owned()); assert_eq!("\u0301a".nfkd_chars().collect::<StrBuf>(), "\u0301a".to_strbuf());
assert_eq!("\ud4db".nfkd_chars().collect::<~str>(), "\u1111\u1171\u11b6".to_owned()); assert_eq!("\ud4db".nfkd_chars().collect::<StrBuf>(), "\u1111\u1171\u11b6".to_strbuf());
assert_eq!("\uac1c".nfkd_chars().collect::<~str>(), "\u1100\u1162".to_owned()); assert_eq!("\uac1c".nfkd_chars().collect::<StrBuf>(), "\u1100\u1162".to_strbuf());
} }
#[test] #[test]
@ -2095,7 +2052,7 @@ mod tests {
} }
t::<&str>(); t::<&str>();
t::<~str>(); t::<StrBuf>();
} }
#[test] #[test]
@ -2169,8 +2126,8 @@ mod tests {
#[test] #[test]
fn test_from_str() { fn test_from_str() {
let owned: Option<~str> = from_str("string"); let owned: Option<StrBuf> = from_str("string");
assert_eq!(owned, Some("string".to_owned())); assert_eq!(owned, Some("string".to_strbuf()));
} }
#[test] #[test]

View File

@ -15,6 +15,7 @@ use char::Char;
use cmp::Equiv; use cmp::Equiv;
use container::{Container, Mutable}; use container::{Container, Mutable};
use fmt; use fmt;
use from_str::FromStr;
use io::Writer; use io::Writer;
use iter::{Extendable, FromIterator, Iterator, range}; use iter::{Extendable, FromIterator, Iterator, range};
use mem; use mem;
@ -22,8 +23,8 @@ use option::{None, Option, Some};
use ptr::RawPtr; use ptr::RawPtr;
use ptr; use ptr;
use result::{Result, Ok, Err}; use result::{Result, Ok, Err};
use slice::{OwnedVector, Vector, CloneableVector}; use slice::Vector;
use str::{CharRange, OwnedStr, Str, StrSlice, StrAllocating}; use str::{CharRange, Str, StrSlice, StrAllocating};
use str; use str;
use vec::Vec; use vec::Vec;
@ -68,10 +69,8 @@ impl StrBuf {
/// Creates a new string buffer from the given owned string, taking care not to copy it. /// Creates a new string buffer from the given owned string, taking care not to copy it.
#[inline] #[inline]
pub fn from_owned_str(string: ~str) -> StrBuf { pub fn from_owned_str(string: StrBuf) -> StrBuf {
StrBuf { string
vec: string.into_bytes().move_iter().collect(),
}
} }
/// Returns the vector as a string buffer, if possible, taking care not to /// Returns the vector as a string buffer, if possible, taking care not to
@ -192,6 +191,13 @@ impl StrBuf {
self.vec.as_slice() self.vec.as_slice()
} }
/// Works with the underlying buffer as a mutable byte slice. Unsafe
/// because this can be used to violate the UTF-8 property.
#[inline]
pub unsafe fn as_mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
self.vec.as_mut_slice()
}
/// Shorten a string to the specified length (which must be <= the current length) /// Shorten a string to the specified length (which must be <= the current length)
#[inline] #[inline]
pub fn truncate(&mut self, len: uint) { pub fn truncate(&mut self, len: uint) {
@ -315,14 +321,14 @@ impl Str for StrBuf {
impl StrAllocating for StrBuf { impl StrAllocating for StrBuf {
#[inline] #[inline]
fn into_owned(self) -> ~str { fn into_owned(self) -> StrBuf {
unsafe { self
mem::transmute(self.vec.as_slice().to_owned())
}
} }
#[inline] #[inline]
fn into_strbuf(self) -> StrBuf { self } fn into_strbuf(self) -> StrBuf {
self
}
} }
impl fmt::Show for StrBuf { impl fmt::Show for StrBuf {
@ -345,6 +351,13 @@ impl<'a, S: Str> Equiv<S> for StrBuf {
} }
} }
impl FromStr for StrBuf {
#[inline]
fn from_str(s: &str) -> Option<StrBuf> {
Some(s.to_strbuf())
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
extern crate test; extern crate test;

View File

@ -54,12 +54,14 @@ impl FromStr for CrateId {
let pieces: Vec<&str> = s.splitn('#', 1).collect(); let pieces: Vec<&str> = s.splitn('#', 1).collect();
let path = pieces.get(0).to_owned(); let path = pieces.get(0).to_owned();
if path.starts_with("/") || path.ends_with("/") || if path.as_slice().starts_with("/") || path.as_slice().ends_with("/") ||
path.starts_with(".") || path.is_empty() { path.as_slice().starts_with(".") || path.is_empty() {
return None; return None;
} }
let path_pieces: Vec<&str> = path.rsplitn('/', 1).collect(); let path_pieces: Vec<&str> = path.as_slice()
.rsplitn('/', 1)
.collect();
let inferred_name = *path_pieces.get(0); let inferred_name = *path_pieces.get(0);
let (name, version) = if pieces.len() == 1 { let (name, version) = if pieces.len() == 1 {

View File

@ -106,7 +106,7 @@ impl SpanHandler {
fail!(ExplicitBug); fail!(ExplicitBug);
} }
pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
self.span_bug(sp, "unimplemented ".to_owned() + msg); self.span_bug(sp, format!("unimplemented {}", msg).as_slice());
} }
pub fn handler<'a>(&'a self) -> &'a Handler { pub fn handler<'a>(&'a self) -> &'a Handler {
&self.handler &self.handler
@ -162,7 +162,7 @@ impl Handler {
fail!(ExplicitBug); fail!(ExplicitBug);
} }
pub fn unimpl(&self, msg: &str) -> ! { pub fn unimpl(&self, msg: &str) -> ! {
self.bug("unimplemented ".to_owned() + msg); self.bug(format!("unimplemented {}", msg).as_slice());
} }
pub fn emit(&self, pub fn emit(&self,
cmsp: Option<(&codemap::CodeMap, Span)>, cmsp: Option<(&codemap::CodeMap, Span)>,
@ -434,7 +434,8 @@ fn highlight_lines(err: &mut EmitterWriter,
s.push_char('~'); s.push_char('~');
} }
} }
try!(print_maybe_styled(err, s.into_owned() + "\n", try!(print_maybe_styled(err,
format!("{}\n", s).as_slice(),
term::attr::ForegroundColor(lvl.color()))); term::attr::ForegroundColor(lvl.color())));
} }
Ok(()) Ok(())
@ -479,7 +480,7 @@ fn custom_highlight_lines(w: &mut EmitterWriter,
s.push_char('^'); s.push_char('^');
s.push_char('\n'); s.push_char('\n');
print_maybe_styled(w, print_maybe_styled(w,
s.into_owned(), s.as_slice(),
term::attr::ForegroundColor(lvl.color())) term::attr::ForegroundColor(lvl.color()))
} }

View File

@ -217,7 +217,7 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
node: ast::ExprInlineAsm(ast::InlineAsm { node: ast::ExprInlineAsm(ast::InlineAsm {
asm: token::intern_and_get_ident(asm.get()), asm: token::intern_and_get_ident(asm.get()),
asm_str_style: asm_str_style.unwrap(), asm_str_style: asm_str_style.unwrap(),
clobbers: token::intern_and_get_ident(cons), clobbers: token::intern_and_get_ident(cons.as_slice()),
inputs: inputs, inputs: inputs,
outputs: outputs, outputs: outputs,
volatile: volatile, volatile: volatile,

View File

@ -59,5 +59,5 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
} }
base::MacExpr::new(cx.expr_str( base::MacExpr::new(cx.expr_str(
sp, sp,
token::intern_and_get_ident(accumulator.into_owned()))) token::intern_and_get_ident(accumulator.as_slice())))
} }

View File

@ -42,7 +42,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
} }
} }
} }
let res = str_to_ident(res_str.into_owned()); let res = str_to_ident(res_str.as_slice());
let e = @ast::Expr { let e = @ast::Expr {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,

View File

@ -436,7 +436,7 @@ fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> @ast::Expr {
ast::TyI32 => "TyI32".to_owned(), ast::TyI32 => "TyI32".to_owned(),
ast::TyI64 => "TyI64".to_owned() ast::TyI64 => "TyI64".to_owned()
}; };
let e_ity = cx.expr_ident(sp, id_ext(s_ity)); let e_ity = cx.expr_ident(sp, id_ext(s_ity.as_slice()));
let e_i64 = cx.expr_lit(sp, ast::LitInt(i, ast::TyI64)); let e_i64 = cx.expr_lit(sp, ast::LitInt(i, ast::TyI64));
@ -453,7 +453,7 @@ fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> @ast::Expr {
ast::TyU32 => "TyU32".to_owned(), ast::TyU32 => "TyU32".to_owned(),
ast::TyU64 => "TyU64".to_owned() ast::TyU64 => "TyU64".to_owned()
}; };
let e_uty = cx.expr_ident(sp, id_ext(s_uty)); let e_uty = cx.expr_ident(sp, id_ext(s_uty.as_slice()));
let e_u64 = cx.expr_lit(sp, ast::LitUint(u, ast::TyU64)); let e_u64 = cx.expr_lit(sp, ast::LitUint(u, ast::TyU64));
@ -476,7 +476,7 @@ fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> @ast::Expr {
ast::TyF64 => "TyF64".to_owned(), ast::TyF64 => "TyF64".to_owned(),
ast::TyF128 => "TyF128".to_owned() ast::TyF128 => "TyF128".to_owned()
}; };
let e_fty = cx.expr_ident(sp, id_ext(s_fty)); let e_fty = cx.expr_ident(sp, id_ext(s_fty.as_slice()));
let e_fident = mk_ident(cx, sp, fident); let e_fident = mk_ident(cx, sp, fident);

View File

@ -76,7 +76,9 @@ pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
.map(|x| token::get_ident(*x).get().to_strbuf()) .map(|x| token::get_ident(*x).get().to_strbuf())
.collect::<Vec<StrBuf>>() .collect::<Vec<StrBuf>>()
.connect("::"); .connect("::");
base::MacExpr::new(cx.expr_str(sp, token::intern_and_get_ident(string))) base::MacExpr::new(cx.expr_str(
sp,
token::intern_and_get_ident(string.as_slice())))
} }
// include! : parse the given file as an expr // include! : parse the given file as an expr

View File

@ -455,6 +455,9 @@ pub fn parse_nt(p: &mut Parser, name: &str) -> Nonterminal {
res res
} }
"matchers" => token::NtMatchers(p.parse_matchers()), "matchers" => token::NtMatchers(p.parse_matchers()),
_ => p.fatal("unsupported builtin nonterminal parser: ".to_owned() + name) _ => {
p.fatal(format!("unsupported builtin nonterminal parser: {}",
name).as_slice())
}
} }
} }

View File

@ -589,13 +589,13 @@ fn scan_number(c: char, rdr: &mut StringReader) -> token::Token {
bump(rdr); bump(rdr);
bump(rdr); bump(rdr);
check_float_base(rdr, start_bpos, rdr.last_pos, base); check_float_base(rdr, start_bpos, rdr.last_pos, base);
return token::LIT_FLOAT(str_to_ident(num_str.into_owned()), return token::LIT_FLOAT(str_to_ident(num_str.as_slice()),
ast::TyF32); ast::TyF32);
} else if c == '6' && n == '4' { } else if c == '6' && n == '4' {
bump(rdr); bump(rdr);
bump(rdr); bump(rdr);
check_float_base(rdr, start_bpos, rdr.last_pos, base); check_float_base(rdr, start_bpos, rdr.last_pos, base);
return token::LIT_FLOAT(str_to_ident(num_str.into_owned()), return token::LIT_FLOAT(str_to_ident(num_str.as_slice()),
ast::TyF64); ast::TyF64);
/* FIXME (#2252): if this is out of range for either a /* FIXME (#2252): if this is out of range for either a
32-bit or 64-bit float, it won't be noticed till the 32-bit or 64-bit float, it won't be noticed till the
@ -612,8 +612,7 @@ fn scan_number(c: char, rdr: &mut StringReader) -> token::Token {
} }
if is_float { if is_float {
check_float_base(rdr, start_bpos, rdr.last_pos, base); check_float_base(rdr, start_bpos, rdr.last_pos, base);
return token::LIT_FLOAT_UNSUFFIXED(str_to_ident( return token::LIT_FLOAT_UNSUFFIXED(str_to_ident(num_str.as_slice()));
num_str.into_owned()));
} else { } else {
if num_str.len() == 0u { if num_str.len() == 0u {
fatal_span(rdr, start_bpos, rdr.last_pos, fatal_span(rdr, start_bpos, rdr.last_pos,

View File

@ -4242,8 +4242,8 @@ impl<'a> Parser<'a> {
Some(d) => (dir_path.join(d), true), Some(d) => (dir_path.join(d), true),
None => { None => {
let mod_name = mod_string.get().to_owned(); let mod_name = mod_string.get().to_owned();
let default_path_str = mod_name + ".rs"; let default_path_str = format!("{}.rs", mod_name);
let secondary_path_str = mod_name + "/mod.rs"; let secondary_path_str = format!("{}/mod.rs", mod_name);
let default_path = dir_path.join(default_path_str.as_slice()); let default_path = dir_path.join(default_path_str.as_slice());
let secondary_path = dir_path.join(secondary_path_str.as_slice()); let secondary_path = dir_path.join(secondary_path_str.as_slice());
let default_exists = default_path.exists(); let default_exists = default_path.exists();
@ -4310,7 +4310,7 @@ impl<'a> Parser<'a> {
err.push_str(" -> "); err.push_str(" -> ");
} }
err.push_str(path.display().as_maybe_owned().as_slice()); err.push_str(path.display().as_maybe_owned().as_slice());
self.span_fatal(id_sp, err.into_owned()); self.span_fatal(id_sp, err.as_slice());
} }
None => () None => ()
} }

View File

@ -141,7 +141,8 @@ pub fn to_str(f: |&mut State| -> IoResult<()>) -> StrBuf {
// that we "know" to be a `MemWriter` that works around the lack of checked // that we "know" to be a `MemWriter` that works around the lack of checked
// downcasts. // downcasts.
let (_, wr): (uint, Box<MemWriter>) = mem::transmute_copy(&s.s.out); let (_, wr): (uint, Box<MemWriter>) = mem::transmute_copy(&s.s.out);
let result = str::from_utf8_owned(wr.get_ref().to_owned()).unwrap(); let result =
str::from_utf8_owned(Vec::from_slice(wr.get_ref())).unwrap();
mem::forget(wr); mem::forget(wr);
result.to_strbuf() result.to_strbuf()
} }
@ -2234,7 +2235,7 @@ impl<'a> State<'a> {
let mut res = StrBuf::from_str("'"); let mut res = StrBuf::from_str("'");
ch.escape_default(|c| res.push_char(c)); ch.escape_default(|c| res.push_char(c));
res.push_char('\''); res.push_char('\'');
word(&mut self.s, res.into_owned()) word(&mut self.s, res.as_slice())
} }
ast::LitInt(i, t) => { ast::LitInt(i, t) => {
word(&mut self.s, word(&mut self.s,

View File

@ -221,7 +221,8 @@ pub fn parse(file: &mut io::Reader, longnames: bool)
None => return Err("input not utf-8".to_strbuf()), None => return Err("input not utf-8".to_strbuf()),
}; };
let term_names: Vec<StrBuf> = names_str.split('|') let term_names: Vec<StrBuf> = names_str.as_slice()
.split('|')
.map(|s| s.to_strbuf()) .map(|s| s.to_strbuf())
.collect(); .collect();