提交 ee2f3d96 编写于 作者: M Marvin Löbel

Switched over substr and trim functions in str to be non-allocating, temporary...

Switched over substr and trim functions in str to be non-allocating, temporary renamed them to better track use-sites
上级 ed25a674
......@@ -1363,11 +1363,11 @@ let crayon_names = crayons.map(|v| crayon_to_str(*v));
let favorite_crayon_name = crayon_names[0];
// Remove whitespace from before and after the string
let new_favorite_crayon_name = favorite_crayon_name.trim();
let new_favorite_crayon_name = favorite_crayon_name.trim_DBGBRWD();
if favorite_crayon_name.len() > 5 {
// Create a substring
println(favorite_crayon_name.substr(0, 5));
println(favorite_crayon_name.substr_DBGBRWD(0, 5));
}
~~~
......
......@@ -268,7 +268,7 @@ fn debugger() -> ~str { ~"gdb" }
// output (in order)
let mut i = 0u;
for str::lines(ProcRes.stdout).each |line| {
if props.check_lines[i].trim() == line.trim() {
if props.check_lines[i].trim_DBGBRWD() == line.trim_DBGBRWD() {
i += 1u;
}
if i == num_check_lines {
......
......@@ -198,7 +198,7 @@ pub use path::WindowsPath;
pub use path::PosixPath;
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use str::{StrSlice, Trimmable};
pub use str::{StrSlice};
pub use container::{Container, Mutable};
pub use vec::{CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
......
......@@ -36,7 +36,7 @@
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::Ptr;
pub use str::{StrSlice, Trimmable, OwnedStr};
pub use str::{StrSlice, OwnedStr};
pub use to_bytes::IterBytes;
pub use to_str::ToStr;
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
......
......@@ -29,6 +29,7 @@
use u8;
use uint;
use vec;
use to_str::ToStr;
#[cfg(notest)] use cmp::{Eq, Ord};
......@@ -53,6 +54,19 @@
unsafe { raw::slice_bytes_unique(s, 0, len(s)) }
}
impl ToStr for ~str {
#[inline(always)]
pure fn to_str(&self) -> ~str { copy *self }
}
impl ToStr for &'self str {
#[inline(always)]
pure fn to_str(&self) -> ~str { ::str::from_slice(*self) }
}
impl ToStr for @str {
#[inline(always)]
pure fn to_str(&self) -> ~str { ::str::from_slice(*self) }
}
/**
* Convert a byte to a UTF-8 string
*
......@@ -299,12 +313,12 @@ pub fn unshift_char(s: &mut ~str, ch: char) {
* * chars_to_trim - A vector of chars
*
*/
pub pure fn trim_left_chars(s: &str, chars_to_trim: &[char]) -> ~str {
if chars_to_trim.is_empty() { return from_slice(s); }
pub pure fn trim_left_chars_DBGBRWD(s: &'a str, chars_to_trim: &[char]) -> &'a str {
if chars_to_trim.is_empty() { return s; }
match find(s, |c| !chars_to_trim.contains(&c)) {
None => ~"",
Some(first) => unsafe { raw::slice_bytes_unique(s, first, s.len()) }
None => "",
Some(first) => unsafe { raw::slice_bytes(s, first, s.len()) }
}
}
......@@ -317,14 +331,14 @@ pub fn unshift_char(s: &mut ~str, ch: char) {
* * chars_to_trim - A vector of chars
*
*/
pub pure fn trim_right_chars(s: &str, chars_to_trim: &[char]) -> ~str {
if chars_to_trim.is_empty() { return str::from_slice(s); }
pub pure fn trim_right_chars_DBGBRWD(s: &'a str, chars_to_trim: &[char]) -> &'a str {
if chars_to_trim.is_empty() { return s; }
match rfind(s, |c| !chars_to_trim.contains(&c)) {
None => ~"",
None => "",
Some(last) => {
let next = char_range_at(s, last).next;
unsafe { raw::slice_bytes_unique(s, 0u, next) }
unsafe { raw::slice_bytes(s, 0u, next) }
}
}
}
......@@ -338,31 +352,31 @@ pub fn unshift_char(s: &mut ~str, ch: char) {
* * chars_to_trim - A vector of chars
*
*/
pub pure fn trim_chars(s: &str, chars_to_trim: &[char]) -> ~str {
trim_left_chars(trim_right_chars(s, chars_to_trim), chars_to_trim)
pub pure fn trim_chars_DBGBRWD(s: &'a str, chars_to_trim: &[char]) -> &'a str {
trim_left_chars_DBGBRWD(trim_right_chars_DBGBRWD(s, chars_to_trim), chars_to_trim)
}
/// Returns a string with leading whitespace removed
pub pure fn trim_left(s: &str) -> ~str {
pub pure fn trim_left_DBGBRWD(s: &'a str) -> &'a str {
match find(s, |c| !char::is_whitespace(c)) {
None => ~"",
Some(first) => unsafe { raw::slice_bytes_unique(s, first, len(s)) }
None => "",
Some(first) => unsafe { raw::slice_bytes(s, first, len(s)) }
}
}
/// Returns a string with trailing whitespace removed
pub pure fn trim_right(s: &str) -> ~str {
pub pure fn trim_right_DBGBRWD(s: &'a str) -> &'a str {
match rfind(s, |c| !char::is_whitespace(c)) {
None => ~"",
None => "",
Some(last) => {
let next = char_range_at(s, last).next;
unsafe { raw::slice_bytes_unique(s, 0u, next) }
unsafe { raw::slice_bytes(s, 0u, next) }
}
}
}
/// Returns a string with leading and trailing whitespace removed
pub pure fn trim(s: &str) -> ~str { trim_left(trim_right(s)) }
pub pure fn trim_DBGBRWD(s: &'a str) -> &'a str { trim_left_DBGBRWD(trim_right_DBGBRWD(s)) }
/*
Section: Transforming strings
......@@ -407,8 +421,8 @@ pub fn unshift_char(s: &mut ~str, ch: char) {
* Returns a string containing `n` characters starting at byte offset
* `begin`.
*/
pub pure fn substr(s: &str, begin: uint, n: uint) -> ~str {
slice(s, begin, begin + count_bytes(s, begin, n)).to_owned()
pub pure fn substr_DBGBRWD(s: &'a str, begin: uint, n: uint) -> &'a str {
slice(s, begin, begin + count_bytes(s, begin, n))
}
/**
......@@ -2221,25 +2235,6 @@ fn test_from_buf_len() {
}
pub trait Trimmable {
pure fn trim(&self) -> Self;
pure fn trim_left(&self) -> Self;
pure fn trim_right(&self) -> Self;
}
/// Extension methods for strings
impl Trimmable for ~str {
/// Returns a string with leading and trailing whitespace removed
#[inline]
pure fn trim(&self) -> ~str { trim(*self) }
/// Returns a string with leading whitespace removed
#[inline]
pure fn trim_left(&self) -> ~str { trim_left(*self) }
/// Returns a string with trailing whitespace removed
#[inline]
pure fn trim_right(&self) -> ~str { trim_right(*self) }
}
#[cfg(notest)]
pub mod traits {
use ops::Add;
......@@ -2280,14 +2275,17 @@ pub trait StrSlice {
pure fn split_char(&self, sep: char) -> ~[~str];
pure fn split_str(&self, sep: &'a str) -> ~[~str];
pure fn starts_with(&self, needle: &'a str) -> bool;
pure fn substr(&self, begin: uint, n: uint) -> ~str;
pure fn substr_DBGBRWD(&self, begin: uint, n: uint) -> &'self str;
pure fn to_lower(&self) -> ~str;
pure fn to_upper(&self) -> ~str;
pure fn escape_default(&self) -> ~str;
pure fn escape_unicode(&self) -> ~str;
pure fn trim(&self) -> ~str;
pure fn trim_left(&self) -> ~str;
pure fn trim_right(&self) -> ~str;
pure fn trim_DBGBRWD(&self) -> &'self str;
pure fn trim_left_DBGBRWD(&self) -> &'self str;
pure fn trim_right_DBGBRWD(&self) -> &'self str;
pure fn trim_chars_DBGBRWD(&self, chars_to_trim: &[char]) -> &'self str;
pure fn trim_left_chars_DBGBRWD(&self, chars_to_trim: &[char]) -> &'self str;
pure fn trim_right_chars_DBGBRWD(&self, chars_to_trim: &[char]) -> &'self str;
pure fn to_owned(&self) -> ~str;
pure fn to_managed(&self) -> @str;
pure fn char_at(&self, i: uint) -> char;
......@@ -2421,8 +2419,8 @@ impl StrSlice for &'self str {
* `begin`.
*/
#[inline]
pure fn substr(&self, begin: uint, n: uint) -> ~str {
substr(*self, begin, n)
pure fn substr_DBGBRWD(&self, begin: uint, n: uint) -> &'self str {
substr_DBGBRWD(*self, begin, n)
}
/// Convert a string to lowercase
#[inline]
......@@ -2439,13 +2437,27 @@ impl StrSlice for &'self str {
/// Returns a string with leading and trailing whitespace removed
#[inline]
pure fn trim(&self) -> ~str { trim(*self) }
pure fn trim_DBGBRWD(&self) -> &'self str { trim_DBGBRWD(*self) }
/// Returns a string with leading whitespace removed
#[inline]
pure fn trim_left(&self) -> ~str { trim_left(*self) }
pure fn trim_left_DBGBRWD(&self) -> &'self str { trim_left_DBGBRWD(*self) }
/// Returns a string with trailing whitespace removed
#[inline]
pure fn trim_right(&self) -> ~str { trim_right(*self) }
pure fn trim_right_DBGBRWD(&self) -> &'self str { trim_right_DBGBRWD(*self) }
#[inline]
pure fn trim_chars_DBGBRWD(&self, chars_to_trim: &[char]) -> &'self str {
trim_chars_DBGBRWD(*self, chars_to_trim)
}
#[inline]
pure fn trim_left_chars_DBGBRWD(&self, chars_to_trim: &[char]) -> &'self str {
trim_left_chars_DBGBRWD(*self, chars_to_trim)
}
#[inline]
pure fn trim_right_chars_DBGBRWD(&self, chars_to_trim: &[char]) -> &'self str {
trim_right_chars_DBGBRWD(*self, chars_to_trim)
}
#[inline]
pure fn to_owned(&self) -> ~str { from_slice(*self) }
......@@ -2805,11 +2817,11 @@ fn test_find_str_between() {
#[test]
fn test_substr() {
fn t(a: &str, b: &str, start: int) {
fail_unless!(substr(a, start as uint, len(b)) == b.to_str());
fail_unless!(substr_DBGBRWD(a, start as uint, len(b)) == b);
}
t(~"hello", ~"llo", 2);
t(~"hello", ~"el", 1);
fail_unless!(~"ะเทศไท" == substr(~"ประเทศไทย中华Việt Nam", 6u, 6u));
t("hello", "llo", 2);
t("hello", "el", 1);
fail_unless!("ะเทศไท" == substr_DBGBRWD("ประเทศไทย中华Việt Nam", 6u, 6u));
}
#[test]
......@@ -3042,62 +3054,62 @@ fn test_slice_fail() {
#[test]
fn test_trim_left_chars() {
fail_unless!(trim_left_chars(~" *** foo *** ", ~[]) ==
~" *** foo *** ");
fail_unless!(trim_left_chars(~" *** foo *** ", ~['*', ' ']) ==
~"foo *** ");
fail_unless!(trim_left_chars(~" *** *** ", ~['*', ' ']) == ~"");
fail_unless!(trim_left_chars(~"foo *** ", ~['*', ' ']) ==
~"foo *** ");
fail_unless!(trim_left_chars_DBGBRWD(" *** foo *** ", ~[]) ==
" *** foo *** ");
fail_unless!(trim_left_chars_DBGBRWD(" *** foo *** ", ~['*', ' ']) ==
"foo *** ");
fail_unless!(trim_left_chars_DBGBRWD(" *** *** ", ~['*', ' ']) == "");
fail_unless!(trim_left_chars_DBGBRWD("foo *** ", ~['*', ' ']) ==
"foo *** ");
}
#[test]
fn test_trim_right_chars() {
fail_unless!(trim_right_chars(~" *** foo *** ", ~[]) ==
~" *** foo *** ");
fail_unless!(trim_right_chars(~" *** foo *** ", ~['*', ' ']) ==
~" *** foo");
fail_unless!(trim_right_chars(~" *** *** ", ~['*', ' ']) == ~"");
fail_unless!(trim_right_chars(~" *** foo", ~['*', ' ']) ==
~" *** foo");
fail_unless!(trim_right_chars_DBGBRWD(" *** foo *** ", ~[]) ==
" *** foo *** ");
fail_unless!(trim_right_chars_DBGBRWD(" *** foo *** ", ~['*', ' ']) ==
" *** foo");
fail_unless!(trim_right_chars_DBGBRWD(" *** *** ", ~['*', ' ']) == "");
fail_unless!(trim_right_chars_DBGBRWD(" *** foo", ~['*', ' ']) ==
" *** foo");
}
#[test]
fn test_trim_chars() {
fail_unless!(trim_chars(~" *** foo *** ", ~[]) == ~" *** foo *** ");
fail_unless!(trim_chars(~" *** foo *** ", ~['*', ' ']) == ~"foo");
fail_unless!(trim_chars(~" *** *** ", ~['*', ' ']) == ~"");
fail_unless!(trim_chars(~"foo", ~['*', ' ']) == ~"foo");
fail_unless!(trim_chars_DBGBRWD(" *** foo *** ", ~[]) == " *** foo *** ");
fail_unless!(trim_chars_DBGBRWD(" *** foo *** ", ~['*', ' ']) == "foo");
fail_unless!(trim_chars_DBGBRWD(" *** *** ", ~['*', ' ']) == "");
fail_unless!(trim_chars_DBGBRWD("foo", ~['*', ' ']) == "foo");
}
#[test]
fn test_trim_left() {
fail_unless!((trim_left(~"") == ~""));
fail_unless!((trim_left(~"a") == ~"a"));
fail_unless!((trim_left(~" ") == ~""));
fail_unless!((trim_left(~" blah") == ~"blah"));
fail_unless!((trim_left(~" \u3000 wut") == ~"wut"));
fail_unless!((trim_left(~"hey ") == ~"hey "));
fail_unless!((trim_left_DBGBRWD("") == ""));
fail_unless!((trim_left_DBGBRWD("a") == "a"));
fail_unless!((trim_left_DBGBRWD(" ") == ""));
fail_unless!((trim_left_DBGBRWD(" blah") == "blah"));
fail_unless!((trim_left_DBGBRWD(" \u3000 wut") == "wut"));
fail_unless!((trim_left_DBGBRWD("hey ") == "hey "));
}
#[test]
fn test_trim_right() {
fail_unless!((trim_right(~"") == ~""));
fail_unless!((trim_right(~"a") == ~"a"));
fail_unless!((trim_right(~" ") == ~""));
fail_unless!((trim_right(~"blah ") == ~"blah"));
fail_unless!((trim_right(~"wut \u3000 ") == ~"wut"));
fail_unless!((trim_right(~" hey") == ~" hey"));
fail_unless!((trim_right_DBGBRWD("") == ""));
fail_unless!((trim_right_DBGBRWD("a") == "a"));
fail_unless!((trim_right_DBGBRWD(" ") == ""));
fail_unless!((trim_right_DBGBRWD("blah ") == "blah"));
fail_unless!((trim_right_DBGBRWD("wut \u3000 ") == "wut"));
fail_unless!((trim_right_DBGBRWD(" hey") == " hey"));
}
#[test]
fn test_trim() {
fail_unless!((trim(~"") == ~""));
fail_unless!((trim(~"a") == ~"a"));
fail_unless!((trim(~" ") == ~""));
fail_unless!((trim(~" blah ") == ~"blah"));
fail_unless!((trim(~"\nwut \u3000 ") == ~"wut"));
fail_unless!((trim(~" hey dude ") == ~"hey dude"));
fail_unless!((trim_DBGBRWD("") == ""));
fail_unless!((trim_DBGBRWD("a") == "a"));
fail_unless!((trim_DBGBRWD(" ") == ""));
fail_unless!((trim_DBGBRWD(" blah ") == "blah"));
fail_unless!((trim_DBGBRWD("\nwut \u3000 ") == "wut"));
fail_unless!((trim_DBGBRWD(" hey dude ") == "hey dude"));
}
#[test]
......
......@@ -28,18 +28,6 @@ impl ToStr for () {
#[inline(always)]
pure fn to_str(&self) -> ~str { ~"()" }
}
impl ToStr for ~str {
#[inline(always)]
pure fn to_str(&self) -> ~str { copy *self }
}
impl ToStr for &'self str {
#[inline(always)]
pure fn to_str(&self) -> ~str { ::str::from_slice(*self) }
}
impl ToStr for @str {
#[inline(always)]
pure fn to_str(&self) -> ~str { ::str::from_slice(*self) }
}
// FIXME #4898: impl for one-tuples
......
......@@ -325,7 +325,7 @@ pub fn parse_type(s: &str, i: uint, lim: uint, err: ErrorFn) ->
'o' as u8 => TyOctal,
'f' as u8 => TyFloat,
'?' as u8 => TyPoly,
_ => err(~"unknown type in conversion: " + s.substr(i, 1))
_ => err(~"unknown type in conversion: " + s.substr_DBGBRWD(i, 1))
};
Parsed::new(t, i + 1)
......@@ -537,7 +537,7 @@ pub struct Conv {
let mut unpadded = match cv.precision {
CountImplied => s.to_owned(),
CountIs(max) => if (max as uint) < str::char_len(s) {
str::substr(s, 0, max as uint)
str::substr_DBGBRWD(s, 0, max as uint).to_owned()
} else {
s.to_owned()
}
......
......@@ -543,7 +543,7 @@ pub fn build_session_options(+binary: ~str,
let lint_dict = lint::get_lint_dict();
for lint_levels.each |level| {
let level_name = lint::level_to_str(*level);
let level_short = level_name.substr(0,1).to_upper();
let level_short = level_name.substr_DBGBRWD(0,1).to_upper();
let flags = vec::append(getopts::opt_strs(matches, level_short),
getopts::opt_strs(matches, level_name));
for flags.each |lint_name| {
......
......@@ -1849,6 +1849,7 @@ fn trans_assign_op(bcx: block,
return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum);
}
// NOTE: Mode neccessary here?
fn shorten(+x: ~str) -> ~str {
if x.len() > 60 { x.substr(0, 60) } else { x }
if x.len() > 60 { x.substr_DBGBRWD(0, 60).to_owned() } else { x }
}
......@@ -311,7 +311,7 @@ pub fn mk_doc(source: ~str) -> doc::Doc {
let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
let doc = (desc_to_brief_pass::mk_pass().f)(srv.clone(), doc);
let doc = (sectionalize_pass::mk_pass().f)(srv.clone(), doc);
(mk_pass(~"", |s| str::trim(s) ).f)(srv.clone(), doc)
(mk_pass(~"", |s| str::trim_DBGBRWD(s).to_owned() ).f)(srv.clone(), doc)
}
}
}
......@@ -21,7 +21,7 @@
use core::str;
pub fn mk_pass() -> Pass {
text_pass::mk_pass(~"trim", |s| str::trim(s) )
text_pass::mk_pass(~"trim", |s| s.trim_DBGBRWD().to_owned() )
}
#[test]
......
......@@ -78,7 +78,7 @@ fn unindent(s: &str) -> ~str {
};
if !lines.is_empty() {
let unindented = ~[lines.head().trim()]
let unindented = ~[lines.head().trim_DBGBRWD().to_owned()]
+ do lines.tail().map |line| {
if str::is_whitespace(*line) {
copy *line
......
......@@ -283,7 +283,7 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer,
for args.each |arg| {
let (crate, filename) =
if arg.ends_with(".rs") || arg.ends_with(".rc") {
(arg.substr(0, arg.len() - 3), *arg)
(arg.substr_DBGBRWD(0, arg.len() - 3).to_owned(), *arg)
} else {
(*arg, arg + ~".rs")
};
......@@ -317,7 +317,7 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer,
match get_line(~"rusti| ") {
None => fail!(~"unterminated multiline command :{ .. :}"),
Some(line) => {
if str::trim(line) == ~":}" {
if str::trim_DBGBRWD(line) == ~":}" {
end_multiline = true;
} else {
multiline_cmd += line + ~"\n";
......@@ -337,7 +337,7 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer,
fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str)
-> Option<Repl> {
if line.starts_with(~":") {
let full = line.substr(1, line.len() - 1);
let full = line.substr_DBGBRWD(1, line.len() - 1);
let split = str::words(full);
let len = split.len();
......
......@@ -458,10 +458,11 @@ pub impl BigUint {
pure fn fill_concat(v: &[BigDigit], radix: uint, l: uint) -> ~str {
if v.is_empty() { return ~"0" }
str::trim_left_chars(str::concat(vec::reversed(v).map(|n| {
let s = str::concat(vec::reversed(v).map(|n| {
let s = uint::to_str_radix(*n as uint, radix);
str::from_chars(vec::from_elem(l - s.len(), '0')) + s
})), ['0'])
}));
str::trim_left_chars_DBGBRWD(s, ['0']).to_owned()
}
}
......
......@@ -223,12 +223,12 @@ pub fn parse(s: &str) -> Option<Version> {
if ! str::is_ascii(s) {
return None;
}
let s = s.trim();
let s = s.trim_DBGBRWD();
let mut bad = false;
do bad_parse::cond.trap(|_| { debug!("bad"); bad = true }).in {
do io::with_str_reader(s) |rdr| {
let v = parse_reader(rdr);
if bad || v.to_str() != s {
if bad || v.to_str() != s.to_owned() {
None
} else {
Some(v)
......
......@@ -70,10 +70,10 @@ pub fn strip_doc_comment_decoration(comment: &str) -> ~str {
/// remove whitespace-only lines from the start/end of lines
fn vertical_trim(lines: ~[~str]) -> ~[~str] {
let mut i = 0u, j = lines.len();
while i < j && lines[i].trim().is_empty() {
while i < j && lines[i].trim_DBGBRWD().is_empty() {
i += 1u;
}
while j > i && lines[j - 1u].trim().is_empty() {
while j > i && lines[j - 1u].trim_DBGBRWD().is_empty() {
j -= 1u;
}
return lines.slice(i, j).to_owned();
......@@ -84,7 +84,7 @@ fn block_trim(lines: ~[~str], chars: ~str, max: Option<uint>) -> ~[~str] {
let mut i = max.get_or_default(uint::max_value);
for lines.each |line| {
if line.trim().is_empty() {
if line.trim_DBGBRWD().is_empty() {
loop;
}
for line.each_chari |j, c| {
......@@ -109,7 +109,10 @@ fn block_trim(lines: ~[~str], chars: ~str, max: Option<uint>) -> ~[~str] {
}
if comment.starts_with(~"//") {
return comment.slice(3u, comment.len()).trim();
// FIXME #5475:
// return comment.slice(3u, comment.len()).trim_DBGBRWD().to_owned();
let r = comment.slice(3u, comment.len()); return r.trim_DBGBRWD().to_owned();
}
if comment.starts_with(~"/*") {
......
......@@ -262,7 +262,7 @@ fn consume_whitespace_and_comments(rdr: @mut StringReader)
}
pub pure fn is_line_non_doc_comment(s: &str) -> bool {
s.trim_right().all(|ch| ch == '/')
s.trim_right_DBGBRWD().all(|ch| ch == '/')
}
// PRECONDITION: rdr.curr is not whitespace
......
......@@ -67,7 +67,8 @@ pub fn equal(&self, other: &Sudoku) -> bool {
let mut g = vec::from_fn(10u, { |_i| ~[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] });
while !reader.eof() {
let comps = str::split_char(str::trim(reader.read_line()), ',');
let line = reader.read_line();
let comps = str::split_char(line.trim_DBGBRWD(), ',');
if vec::len(comps) == 3u {
let row = uint::from_str(comps[0]).get() as u8;
let col = uint::from_str(comps[1]).get() as u8;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册