1
Fork 0

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 * * digits - The number of significant digits
* * exact - Whether to enforce the exact 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 is_NaN(num) { return ~"NaN"; }
if num == infinity { return ~"inf"; } if num == infinity { return ~"inf"; }
if num == neg_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 // store the next digit
frac *= 10.0; frac *= 10.0;
let digit = frac as uint; let digit = frac as uint;
fractionalParts.push(digit); // Bleh: not really unsafe.
unsafe { fractionalParts.push(digit); }
// calculate the next frac // calculate the next frac
frac -= digit as float; frac -= digit as float;
@ -140,7 +141,8 @@ pub fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
// turn digits into string // turn digits into string
// using stack of digits // using stack of digits
while fractionalParts.is_not_empty() { 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 { if adjusted_digit == 10 {
carry = 1; carry = 1;
@ -196,7 +198,7 @@ pub fn test_to_str_exact_do_decimal() {
* * num - The float value * * num - The float value
* * digits - The number of significant digits * * 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) 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` * `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 base == 0u {
if pow == 0u { if pow == 0u {
return NaN as float; return NaN as float;

View file

@ -154,7 +154,7 @@ impl T : FromStr {
} }
/// Convert to a string in a given base /// 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 to_str_bytes(n, radix) |slice| {
do vec::as_imm_buf(slice) |p, len| { do vec::as_imm_buf(slice) |p, len| {
unsafe { str::raw::from_buf_len(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 { if n < 0 as T {
uint::to_str_bytes(true, -n as uint, radix, f) uint::to_str_bytes(true, -n as uint, radix, f)
} else { } 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 /// 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) // FIXME: Has alignment issues on windows and 32-bit linux (#2609)
#[test] #[test]

View file

@ -61,7 +61,7 @@ pub pure fn Path(s: &str) -> Path {
} }
impl PosixPath : ToStr { impl PosixPath : ToStr {
fn to_str() -> ~str { pure fn to_str() -> ~str {
let mut s = ~""; let mut s = ~"";
if self.is_absolute { if self.is_absolute {
s += "/"; s += "/";
@ -236,7 +236,7 @@ impl PosixPath : GenericPath {
impl WindowsPath : ToStr { impl WindowsPath : ToStr {
fn to_str() -> ~str { pure fn to_str() -> ~str {
let mut s = ~""; let mut s = ~"";
match self.host { match self.host {
Some(ref h) => { s += "\\\\"; s += *h; } 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 /// 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 { unsafe {
let code = ch as uint; let code = ch as uint;
let nb = if code < max_one_b { 1u } 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 /// Appends a string slice to the back of a string, without overallocating
#[inline(always)] #[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 { unsafe {
let llen = lhs.len(); let llen = lhs.len();
let rlen = rhs.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 /// Appends a string slice to the back of a string
#[inline(always)] #[inline(always)]
pub fn push_str(lhs: &const ~str, rhs: &str) { pub fn push_str(lhs: &mut ~str, rhs: &str) {
unsafe { unsafe {
let llen = lhs.len(); let llen = lhs.len();
let rlen = rhs.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 * 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); let end = len(*s);
assert end > 0u; assert end > 0u;
let {ch, prev} = char_range_at_reverse(*s, end); 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 * * s - A string
* * n - The number of bytes to reserve space for * * 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 { unsafe {
let v: *mut ~[u8] = cast::transmute(copy s); let v: *mut ~[u8] = cast::transmute(s);
vec::reserve(&mut *v, n + 1); vec::reserve(&mut *v, n + 1);
} }
} }
@ -1829,7 +1829,7 @@ pub fn reserve(s: &const ~str, n: uint) {
* * s - A string * * s - A string
* * n - The number of bytes to reserve space for * * 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) 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). /// 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); reserve_at_least(s, s.len() + 1);
do as_buf(*s) |buf, len| { do as_buf(*s) |buf, len| {
let buf: *mut u8 = ::cast::reinterpret_cast(&buf); 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). /// 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()); reserve_at_least(s, s.len() + bytes.len());
for vec::each(bytes) |byte| { push_byte(s, *byte); } for vec::each(bytes) |byte| { push_byte(s, *byte); }
} }
/// Removes the last byte from a string and returns it. (Not UTF-8 safe). /// 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); let len = len(*s);
assert (len > 0u); assert (len > 0u);
let b = s[len - 1u]; let b = s[len - 1u];
@ -2008,7 +2008,7 @@ pub mod raw {
} }
/// Sets the length of the string and adds the null terminator /// 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 v: **vec::raw::VecRepr = cast::transmute(copy v);
let repr: *vec::raw::VecRepr = *v; let repr: *vec::raw::VecRepr = *v;
(*repr).unboxed.fill = new_len + 1u; (*repr).unboxed.fill = new_len + 1u;

View file

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

View file

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

View file

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

View file

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

View file

@ -195,11 +195,11 @@ fn check_crate(tcx: ty::ctxt,
} }
impl LiveNode: to_str::ToStr { 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 { 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 { impl cat : ToStr {
fn to_str() -> ~str { self.name } pure fn to_str() -> ~str { self.name }
} }
priv impl cat { priv impl cat {

View file

@ -45,7 +45,7 @@ fn cat(in_x : uint, in_y : int, in_name: ~str) -> cat {
} }
impl cat: ToStr { 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) { fn print_out<T: ToStr>(thing: T, expected: ~str) {

View file

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