Make to_str pure and fix const parameters for str-mutating functions

Two separate changes that got intertwined (sorry):

Make to_str pure. Closes #3691

In str, change functions like push_char to take an &mut str instead of
an &str. Closes #3710
This commit is contained in:
Tim Chevalier 2012-10-11 14:12:50 -07:00
parent 41bce91cb8
commit 5a8ba073bc
14 changed files with 87 additions and 75 deletions

View File

@ -91,7 +91,7 @@ pub mod consts {
* * digits - The number of significant digits
* * exact - Whether to enforce the exact number of significant digits
*/
pub fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
pub pure fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
if is_NaN(num) { return ~"NaN"; }
if num == infinity { return ~"inf"; }
if num == neg_infinity { return ~"-inf"; }
@ -125,7 +125,8 @@ pub fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
// store the next digit
frac *= 10.0;
let digit = frac as uint;
fractionalParts.push(digit);
// Bleh: not really unsafe.
unsafe { fractionalParts.push(digit); }
// calculate the next frac
frac -= digit as float;
@ -140,7 +141,8 @@ pub fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
// turn digits into string
// using stack of digits
while fractionalParts.is_not_empty() {
let mut adjusted_digit = carry + fractionalParts.pop();
// Bleh; shouldn't need to be unsafe
let mut adjusted_digit = carry + unsafe { fractionalParts.pop() };
if adjusted_digit == 10 {
carry = 1;
@ -196,7 +198,7 @@ pub fn test_to_str_exact_do_decimal() {
* * num - The float value
* * digits - The number of significant digits
*/
pub fn to_str(num: float, digits: uint) -> ~str {
pub pure fn to_str(num: float, digits: uint) -> ~str {
to_str_common(num, digits, false)
}
@ -361,7 +363,7 @@ pub fn from_str(num: &str) -> Option<float> {
*
* `NaN` if both `x` and `pow` are `0u`, otherwise `x^pow`
*/
pub fn pow_with_uint(base: uint, pow: uint) -> float {
pub pure fn pow_with_uint(base: uint, pow: uint) -> float {
if base == 0u {
if pow == 0u {
return NaN as float;

View File

@ -154,7 +154,7 @@ impl T : FromStr {
}
/// Convert to a string in a given base
pub fn to_str(n: T, radix: uint) -> ~str {
pub pure fn to_str(n: T, radix: uint) -> ~str {
do to_str_bytes(n, radix) |slice| {
do vec::as_imm_buf(slice) |p, len| {
unsafe { str::raw::from_buf_len(p, len) }
@ -162,7 +162,7 @@ pub fn to_str(n: T, radix: uint) -> ~str {
}
}
pub fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
pub pure fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
if n < 0 as T {
uint::to_str_bytes(true, -n as uint, radix, f)
} else {
@ -171,7 +171,7 @@ pub fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
}
/// Convert to a string
pub fn str(i: T) -> ~str { return to_str(i, 10u); }
pub pure fn str(i: T) -> ~str { return to_str(i, 10u); }
// FIXME: Has alignment issues on windows and 32-bit linux (#2609)
#[test]

View File

@ -61,7 +61,7 @@ pub pure fn Path(s: &str) -> Path {
}
impl PosixPath : ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
let mut s = ~"";
if self.is_absolute {
s += "/";
@ -236,7 +236,7 @@ impl PosixPath : GenericPath {
impl WindowsPath : ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
let mut s = ~"";
match self.host {
Some(ref h) => { s += "\\\\"; s += *h; }

View File

@ -49,7 +49,7 @@ pub pure fn from_byte(b: u8) -> ~str {
}
/// Appends a character at the end of a string
pub fn push_char(s: &const ~str, ch: char) {
pub fn push_char(s: &mut ~str, ch: char) {
unsafe {
let code = ch as uint;
let nb = if code < max_one_b { 1u }
@ -140,7 +140,7 @@ pub pure fn from_chars(chs: &[char]) -> ~str {
/// Appends a string slice to the back of a string, without overallocating
#[inline(always)]
pub fn push_str_no_overallocate(lhs: &const ~str, rhs: &str) {
pub fn push_str_no_overallocate(lhs: &mut ~str, rhs: &str) {
unsafe {
let llen = lhs.len();
let rlen = rhs.len();
@ -157,7 +157,7 @@ pub fn push_str_no_overallocate(lhs: &const ~str, rhs: &str) {
}
/// Appends a string slice to the back of a string
#[inline(always)]
pub fn push_str(lhs: &const ~str, rhs: &str) {
pub fn push_str(lhs: &mut ~str, rhs: &str) {
unsafe {
let llen = lhs.len();
let rlen = rhs.len();
@ -214,7 +214,7 @@ Section: Adding to and removing from a string
*
* If the string does not contain any characters
*/
pub fn pop_char(s: &const ~str) -> char {
pub fn pop_char(s: &mut ~str) -> char {
let end = len(*s);
assert end > 0u;
let {ch, prev} = char_range_at_reverse(*s, end);
@ -1802,9 +1802,9 @@ pub pure fn as_buf<T>(s: &str, f: fn(*u8, uint) -> T) -> T {
* * s - A string
* * n - The number of bytes to reserve space for
*/
pub fn reserve(s: &const ~str, n: uint) {
pub fn reserve(s: &mut ~str, n: uint) {
unsafe {
let v: *mut ~[u8] = cast::transmute(copy s);
let v: *mut ~[u8] = cast::transmute(s);
vec::reserve(&mut *v, n + 1);
}
}
@ -1829,7 +1829,7 @@ pub fn reserve(s: &const ~str, n: uint) {
* * s - A string
* * n - The number of bytes to reserve space for
*/
pub fn reserve_at_least(s: &const ~str, n: uint) {
pub fn reserve_at_least(s: &mut ~str, n: uint) {
reserve(s, uint::next_power_of_two(n + 1u) - 1u)
}
@ -1974,7 +1974,7 @@ pub mod raw {
}
/// Appends a byte to a string. (Not UTF-8 safe).
pub unsafe fn push_byte(s: &const ~str, b: u8) {
pub unsafe fn push_byte(s: &mut ~str, b: u8) {
reserve_at_least(s, s.len() + 1);
do as_buf(*s) |buf, len| {
let buf: *mut u8 = ::cast::reinterpret_cast(&buf);
@ -1984,13 +1984,13 @@ pub mod raw {
}
/// Appends a vector of bytes to a string. (Not UTF-8 safe).
unsafe fn push_bytes(s: &const ~str, bytes: &[u8]) {
unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) {
reserve_at_least(s, s.len() + bytes.len());
for vec::each(bytes) |byte| { push_byte(s, *byte); }
}
/// Removes the last byte from a string and returns it. (Not UTF-8 safe).
pub unsafe fn pop_byte(s: &const ~str) -> u8 {
pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
let len = len(*s);
assert (len > 0u);
let b = s[len - 1u];
@ -2008,7 +2008,7 @@ pub mod raw {
}
/// Sets the length of the string and adds the null terminator
pub unsafe fn set_len(v: &const ~str, new_len: uint) {
pub unsafe fn set_len(v: &mut ~str, new_len: uint) {
let v: **vec::raw::VecRepr = cast::transmute(copy v);
let repr: *vec::raw::VecRepr = *v;
(*repr).unboxed.fill = new_len + 1u;

View File

@ -8,80 +8,82 @@ The `ToStr` trait for converting to strings
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
pub trait ToStr { fn to_str() -> ~str; }
pub trait ToStr { pure fn to_str() -> ~str; }
impl int: ToStr {
fn to_str() -> ~str { int::str(self) }
pure fn to_str() -> ~str { int::str(self) }
}
impl i8: ToStr {
fn to_str() -> ~str { i8::str(self) }
pure fn to_str() -> ~str { i8::str(self) }
}
impl i16: ToStr {
fn to_str() -> ~str { i16::str(self) }
pure fn to_str() -> ~str { i16::str(self) }
}
impl i32: ToStr {
fn to_str() -> ~str { i32::str(self) }
pure fn to_str() -> ~str { i32::str(self) }
}
impl i64: ToStr {
fn to_str() -> ~str { i64::str(self) }
pure fn to_str() -> ~str { i64::str(self) }
}
impl uint: ToStr {
fn to_str() -> ~str { uint::str(self) }
pure fn to_str() -> ~str { uint::str(self) }
}
impl u8: ToStr {
fn to_str() -> ~str { u8::str(self) }
pure fn to_str() -> ~str { u8::str(self) }
}
impl u16: ToStr {
fn to_str() -> ~str { u16::str(self) }
pure fn to_str() -> ~str { u16::str(self) }
}
impl u32: ToStr {
fn to_str() -> ~str { u32::str(self) }
pure fn to_str() -> ~str { u32::str(self) }
}
impl u64: ToStr {
fn to_str() -> ~str { u64::str(self) }
pure fn to_str() -> ~str { u64::str(self) }
}
impl float: ToStr {
fn to_str() -> ~str { float::to_str(self, 4u) }
pure fn to_str() -> ~str { float::to_str(self, 4u) }
}
impl f32: ToStr {
fn to_str() -> ~str { float::to_str(self as float, 4u) }
pure fn to_str() -> ~str { float::to_str(self as float, 4u) }
}
impl f64: ToStr {
fn to_str() -> ~str { float::to_str(self as float, 4u) }
pure fn to_str() -> ~str { float::to_str(self as float, 4u) }
}
impl bool: ToStr {
fn to_str() -> ~str { bool::to_str(self) }
pure fn to_str() -> ~str { bool::to_str(self) }
}
impl (): ToStr {
fn to_str() -> ~str { ~"()" }
pure fn to_str() -> ~str { ~"()" }
}
impl ~str: ToStr {
fn to_str() -> ~str { copy self }
pure fn to_str() -> ~str { copy self }
}
impl &str: ToStr {
fn to_str() -> ~str { str::from_slice(self) }
pure fn to_str() -> ~str { str::from_slice(self) }
}
impl @str: ToStr {
fn to_str() -> ~str { str::from_slice(self) }
pure fn to_str() -> ~str { str::from_slice(self) }
}
impl<A: ToStr Copy, B: ToStr Copy> (A, B): ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
let (a, b) = self;
~"(" + a.to_str() + ~", " + b.to_str() + ~")"
}
}
impl<A: ToStr Copy, B: ToStr Copy, C: ToStr Copy> (A, B, C): ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
let (a, b, c) = self;
~"(" + a.to_str() + ~", " + b.to_str() + ~", " + c.to_str() + ~")"
}
}
impl<A: ToStr> ~[A]: ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str unsafe {
// Bleh -- not really unsafe
// push_str and push_char
let mut acc = ~"[", first = true;
for vec::each(self) |elt| {
for vec::each(self) |elt| unsafe {
if first { first = false; }
else { str::push_str(&mut acc, ~", "); }
str::push_str(&mut acc, elt.to_str());
@ -92,10 +94,10 @@ impl<A: ToStr> ~[A]: ToStr {
}
impl<A: ToStr> @A: ToStr {
fn to_str() -> ~str { ~"@" + (*self).to_str() }
pure fn to_str() -> ~str { ~"@" + (*self).to_str() }
}
impl<A: ToStr> ~A: ToStr {
fn to_str() -> ~str { ~"~" + (*self).to_str() }
pure fn to_str() -> ~str { ~"~" + (*self).to_str() }
}
#[cfg(test)]

View File

@ -232,7 +232,7 @@ pub pure fn to_str_bytes<U>(neg: bool, num: T, radix: uint,
}
/// Convert to a string
pub fn str(i: T) -> ~str { return to_str(i, 10u); }
pub pure fn str(i: T) -> ~str { return to_str(i, 10u); }
#[test]
pub fn test_to_str() {

View File

@ -51,7 +51,7 @@ fn escape_str(s: &str) -> ~str {
fn spaces(n: uint) -> ~str {
let mut ss = ~"";
for n.times { str::push_str(&ss, " "); }
for n.times { str::push_str(&mut ss, " "); }
return ss;
}
@ -302,7 +302,8 @@ pub fn to_writer(wr: io::Writer, json: &Json) {
}
/// Serializes a json value into a string
pub fn to_str(json: &Json) -> ~str {
pub pure fn to_str(json: &Json) -> ~str unsafe {
// ugh, should be safe
io::with_str_writer(|wr| to_writer(wr, json))
}
@ -546,14 +547,14 @@ priv impl Parser {
if (escape) {
match self.ch {
'"' => str::push_char(&res, '"'),
'\\' => str::push_char(&res, '\\'),
'/' => str::push_char(&res, '/'),
'b' => str::push_char(&res, '\x08'),
'f' => str::push_char(&res, '\x0c'),
'n' => str::push_char(&res, '\n'),
'r' => str::push_char(&res, '\r'),
't' => str::push_char(&res, '\t'),
'"' => str::push_char(&mut res, '"'),
'\\' => str::push_char(&mut res, '\\'),
'/' => str::push_char(&mut res, '/'),
'b' => str::push_char(&mut res, '\x08'),
'f' => str::push_char(&mut res, '\x0c'),
'n' => str::push_char(&mut res, '\n'),
'r' => str::push_char(&mut res, '\r'),
't' => str::push_char(&mut res, '\t'),
'u' => {
// Parse \u1234.
let mut i = 0u;
@ -582,7 +583,7 @@ priv impl Parser {
~"invalid \\u escape (not four digits)");
}
str::push_char(&res, n as char);
str::push_char(&mut res, n as char);
}
_ => return self.error(~"invalid escape")
}
@ -594,7 +595,7 @@ priv impl Parser {
self.bump();
return Ok(res);
}
str::push_char(&res, self.ch);
str::push_char(&mut res, self.ch);
}
}
@ -1166,11 +1167,11 @@ impl <A: ToJson> Option<A>: ToJson {
}
impl Json: to_str::ToStr {
fn to_str() -> ~str { to_str(&self) }
pure fn to_str() -> ~str { to_str(&self) }
}
impl Error: to_str::ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
fmt!("%u:%u: %s", self.line, self.col, *self.msg)
}
}

View File

@ -341,7 +341,8 @@ pub mod chained {
wr.write_str(~" }");
}
fn to_str() -> ~str {
pure fn to_str() -> ~str unsafe {
// Meh -- this should be safe
do io::with_str_writer |wr| { self.to_writer(wr) }
}
}

View File

@ -94,7 +94,8 @@ pub fn encode(s: &str) -> ~str {
*
* This function is compliant with RFC 3986.
*/
pub fn encode_component(s: &str) -> ~str {
fn encode_component(s: &str) -> ~str {
encode_inner(s, false)
}
@ -297,7 +298,7 @@ fn userinfo_from_str(uinfo: &str) -> UserInfo {
return UserInfo(user, pass);
}
fn userinfo_to_str(userinfo: UserInfo) -> ~str {
pure fn userinfo_to_str(userinfo: UserInfo) -> ~str {
if option::is_some(&userinfo.pass) {
return str::concat(~[copy userinfo.user, ~":",
option::unwrap(copy userinfo.pass),
@ -325,11 +326,15 @@ fn query_from_str(rawquery: &str) -> Query {
return query;
}
pub fn query_to_str(query: Query) -> ~str {
pub pure fn query_to_str(query: Query) -> ~str {
let mut strvec = ~[];
for query.each |kv| {
let (k, v) = copy *kv;
strvec += ~[#fmt("%s=%s", encode_component(k), encode_component(v))];
// This is really safe...
unsafe {
strvec += ~[#fmt("%s=%s",
encode_component(k), encode_component(v))];
}
};
return str::connect(strvec, ~"&");
}
@ -672,7 +677,7 @@ impl Url : FromStr {
* result in just "http://somehost.com".
*
*/
pub fn to_str(url: Url) -> ~str {
pub pure fn to_str(url: Url) -> ~str {
let user = if url.user.is_some() {
userinfo_to_str(option::unwrap(copy url.user))
} else {
@ -688,7 +693,8 @@ pub fn to_str(url: Url) -> ~str {
} else {
str::concat(~[~"?", query_to_str(url.query)])
};
let fragment = if url.fragment.is_some() {
// ugh, this really is safe
let fragment = if url.fragment.is_some() unsafe {
str::concat(~[~"#", encode_component(
option::unwrap(copy url.fragment))])
} else {
@ -704,7 +710,7 @@ pub fn to_str(url: Url) -> ~str {
}
impl Url: to_str::ToStr {
pub fn to_str() -> ~str {
pub pure fn to_str() -> ~str {
to_str(self)
}
}

View File

@ -18,7 +18,7 @@ impl direction : cmp::Eq {
}
impl direction: ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
match self {
send => ~"Send",
recv => ~"Recv"

View File

@ -195,11 +195,11 @@ fn check_crate(tcx: ty::ctxt,
}
impl LiveNode: to_str::ToStr {
fn to_str() -> ~str { fmt!("ln(%u)", *self) }
pure fn to_str() -> ~str { fmt!("ln(%u)", *self) }
}
impl Variable: to_str::ToStr {
fn to_str() -> ~str { fmt!("v(%u)", *self) }
pure fn to_str() -> ~str { fmt!("v(%u)", *self) }
}
// ______________________________________________________________________

View File

@ -13,7 +13,7 @@ struct cat {
}
impl cat : ToStr {
fn to_str() -> ~str { self.name }
pure fn to_str() -> ~str { self.name }
}
priv impl cat {

View File

@ -45,7 +45,7 @@ fn cat(in_x : uint, in_y : int, in_name: ~str) -> cat {
}
impl cat: ToStr {
fn to_str() -> ~str { self.name }
pure fn to_str() -> ~str { self.name }
}
fn print_out<T: ToStr>(thing: T, expected: ~str) {

View File

@ -16,7 +16,7 @@ enum square {
}
impl square: to_str::ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
match self {
bot => { ~"R" }
wall => { ~"#" }