Skip to content

Follow std library convention and return Option for to_ascii() and into_ascii() instead of failing #12320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiletest/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn parse_expected(line_num: uint, line: ~str) -> ~[ExpectedError] {
while idx < len && line[idx] != (' ' as u8) { idx += 1u; }

let kind = line.slice(start_kind, idx);
let kind = kind.to_ascii().to_lower().into_str();
let kind = kind.to_ascii().unwrap().to_lower().into_str();

// Extract msg:
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
Expand Down
7 changes: 3 additions & 4 deletions src/compiletest/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,10 +504,9 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError],
fn to_lower( s : &str ) -> ~str {
let i = s.chars();
let c : ~[char] = i.map( |c| {
if c.is_ascii() {
c.to_ascii().to_lower().to_char()
} else {
c
match c.to_ascii() {
Some(ascii) => ascii.to_lower().to_char(),
None => c
}
} ).collect();
str::from_chars( c )
Expand Down
8 changes: 4 additions & 4 deletions src/libglob/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptio
// FIXME: work with non-ascii chars properly (issue #1347)
if !options.case_sensitive && c.is_ascii() && start.is_ascii() && end.is_ascii() {

let start = start.to_ascii().to_lower();
let end = end.to_ascii().to_lower();
let start = start.to_ascii().unwrap().to_lower();
let end = end.to_ascii().unwrap().to_lower();

let start_up = start.to_upper();
let end_up = end.to_upper();
Expand All @@ -458,7 +458,7 @@ fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptio
if start != start_up && end != end_up {
let start = start.to_char();
let end = end.to_char();
let c = c.to_ascii().to_lower().to_char();
let c = c.to_ascii().unwrap().to_lower().to_char();
if c >= start && c <= end {
return true;
}
Expand All @@ -481,7 +481,7 @@ fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
true
} else if !case_sensitive && a.is_ascii() && b.is_ascii() {
// FIXME: work with non-ascii chars properly (issue #1347)
a.to_ascii().eq_ignore_case(b.to_ascii())
a.to_ascii().unwrap().eq_ignore_case(b.to_ascii().unwrap())
} else {
a == b
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ pub fn build_session_options(matches: &getopts::Matches)
let level_name = lint::level_to_str(*level);

let level_short = level_name.slice_chars(0, 1);
let level_short = level_short.to_ascii().to_upper().into_str();
let level_short = level_short.to_ascii().unwrap().to_upper().into_str();
let flags = vec::append(matches.opt_strs(level_short),
matches.opt_strs(level_name));
for lint_name in flags.iter() {
Expand Down
136 changes: 60 additions & 76 deletions src/libstd/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use iter::Iterator;
use vec::{ImmutableVector, MutableVector, Vector};
use to_bytes::IterBytes;
use option::{Option, Some, None};
use result::{Result, Ok, Err};

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[deriving(Clone, Eq, Ord, TotalOrd, TotalEq)]
Expand Down Expand Up @@ -143,16 +144,9 @@ impl<'a> fmt::Show for Ascii {

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
/// Convert to an ascii type, fail on non-ASCII input.
#[inline]
fn to_ascii(&self) -> T {
assert!(self.is_ascii());
unsafe {self.to_ascii_nocheck()}
}

/// Convert to an ascii type, return None on non-ASCII input.
#[inline]
fn to_ascii_opt(&self) -> Option<T> {
fn to_ascii(&self) -> Option<T> {
if self.is_ascii() {
Some(unsafe { self.to_ascii_nocheck() })
} else {
Expand All @@ -175,10 +169,7 @@ impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] {

#[inline]
fn is_ascii(&self) -> bool {
for b in self.iter() {
if !b.is_ascii() { return false; }
}
true
self.iter().all(|b| b.is_ascii())
}
}

Expand Down Expand Up @@ -223,20 +214,13 @@ pub trait OwnedAsciiCast {
/// Check if convertible to ascii
fn is_ascii(&self) -> bool;

/// Take ownership and cast to an ascii vector. Fail on non-ASCII input.
/// Take ownership and cast to an ascii vector. Return Err(Self) on non-ASCII input.
#[inline]
fn into_ascii(self) -> ~[Ascii] {
assert!(self.is_ascii());
unsafe {self.into_ascii_nocheck()}
}

/// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
#[inline]
fn into_ascii_opt(self) -> Option<~[Ascii]> {
fn into_ascii(self) -> Result<~[Ascii], Self> {
if self.is_ascii() {
Some(unsafe { self.into_ascii_nocheck() })
Ok(unsafe { self.into_ascii_nocheck() })
} else {
None
Err(self)
}
}

Expand Down Expand Up @@ -498,29 +482,29 @@ mod tests {

#[test]
fn test_ascii() {
assert_eq!(65u8.to_ascii().to_byte(), 65u8);
assert_eq!(65u8.to_ascii().to_char(), 'A');
assert_eq!('A'.to_ascii().to_char(), 'A');
assert_eq!('A'.to_ascii().to_byte(), 65u8);

assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');

assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
assert_eq!('['.to_ascii().to_lower().to_char(), '[');
assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
assert_eq!('{'.to_ascii().to_upper().to_char(), '{');

assert!('0'.to_ascii().is_digit());
assert!('9'.to_ascii().is_digit());
assert!(!'/'.to_ascii().is_digit());
assert!(!':'.to_ascii().is_digit());

assert!((0x1fu8).to_ascii().is_control());
assert!(!' '.to_ascii().is_control());
assert!((0x7fu8).to_ascii().is_control());
assert_eq!(65u8.to_ascii().unwrap().to_byte(), 65u8);
assert_eq!(65u8.to_ascii().unwrap().to_char(), 'A');
assert_eq!('A'.to_ascii().unwrap().to_char(), 'A');
assert_eq!('A'.to_ascii().unwrap().to_byte(), 65u8);

assert_eq!('A'.to_ascii().unwrap().to_lower().to_char(), 'a');
assert_eq!('Z'.to_ascii().unwrap().to_lower().to_char(), 'z');
assert_eq!('a'.to_ascii().unwrap().to_upper().to_char(), 'A');
assert_eq!('z'.to_ascii().unwrap().to_upper().to_char(), 'Z');

assert_eq!('@'.to_ascii().unwrap().to_lower().to_char(), '@');
assert_eq!('['.to_ascii().unwrap().to_lower().to_char(), '[');
assert_eq!('`'.to_ascii().unwrap().to_upper().to_char(), '`');
assert_eq!('{'.to_ascii().unwrap().to_upper().to_char(), '{');

assert!('0'.to_ascii().unwrap().is_digit());
assert!('9'.to_ascii().unwrap().is_digit());
assert!(!'/'.to_ascii().unwrap().is_digit());
assert!(!':'.to_ascii().unwrap().is_digit());

assert!((0x1fu8).to_ascii().unwrap().is_control());
assert!(!' '.to_ascii().unwrap().is_control());
assert!((0x7fu8).to_ascii().unwrap().is_control());

assert!("banana".chars().all(|c| c.is_ascii()));
assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
Expand All @@ -529,21 +513,21 @@ mod tests {
#[test]
fn test_ascii_vec() {
let test = &[40u8, 32u8, 59u8];
assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59]));
assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
assert_eq!(test.to_ascii(), Some(v2ascii!([40, 32, 59])));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So assert_eq!(test.to_ascii(), Some(v2ascii!(&[40, 32, 59]))); instead?

assert_eq!("( ;".to_ascii(), Some(v2ascii!([40, 32, 59])));
// FIXME: #5475 borrowchk error, owned vectors do not live long enough
// if chained-from directly
let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
let v = ~"( ;"; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), Some(v2ascii!([40, 32, 59])));
let v = ~"( ;"; assert_eq!(v.to_ascii(), Some(v2ascii!([40, 32, 59])));

assert_eq!("abCDef&?#".to_ascii().to_lower().into_str(), ~"abcdef&?#");
assert_eq!("abCDef&?#".to_ascii().to_upper().into_str(), ~"ABCDEF&?#");
assert_eq!("abCDef&?#".to_ascii().unwrap().to_lower().into_str(), ~"abcdef&?#");
assert_eq!("abCDef&?#".to_ascii().unwrap().to_upper().into_str(), ~"ABCDEF&?#");

assert_eq!("".to_ascii().to_lower().into_str(), ~"");
assert_eq!("YMCA".to_ascii().to_lower().into_str(), ~"ymca");
assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().into_str(), ~"ABCDEFXYZ:.;");
assert_eq!("".to_ascii().unwrap().to_lower().into_str(), ~"");
assert_eq!("YMCA".to_ascii().unwrap().to_lower().into_str(), ~"ymca");
assert_eq!("abcDEFxyz:.;".to_ascii().unwrap().to_upper().into_str(), ~"ABCDEFXYZ:.;");

assert!("aBcDeF&?#".to_ascii().eq_ignore_case("AbCdEf&?#".to_ascii()));
assert!("aBcDeF&?#".to_ascii().unwrap().eq_ignore_case("AbCdEf&?#".to_ascii().unwrap()));

assert!("".is_ascii());
assert!("a".is_ascii());
Expand All @@ -553,8 +537,8 @@ mod tests {

#[test]
fn test_owned_ascii_vec() {
assert_eq!((~"( ;").into_ascii(), v2ascii!(~[40, 32, 59]));
assert_eq!((~[40u8, 32u8, 59u8]).into_ascii(), v2ascii!(~[40, 32, 59]));
assert_eq!((~"( ;").into_ascii(), Ok(v2ascii!(~[40, 32, 59])));
assert_eq!((~[40u8, 32u8, 59u8]).into_ascii(), Ok(v2ascii!(~[40, 32, 59])));
}

#[test]
Expand All @@ -574,46 +558,46 @@ mod tests {
}

#[test] #[should_fail]
fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); }
fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii().unwrap(); }

#[test] #[should_fail]
fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }
fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii().unwrap(); }

#[test] #[should_fail]
fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }
fn test_ascii_fail_u8_slice() { 255u8.to_ascii().unwrap(); }

#[test] #[should_fail]
fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
fn test_ascii_fail_char_slice() { 'λ'.to_ascii().unwrap(); }

#[test]
fn test_opt() {
assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
assert_eq!(255u8.to_ascii_opt(), None);
assert_eq!(65u8.to_ascii(), Some(Ascii { chr: 65u8 }));
assert_eq!(255u8.to_ascii(), None);

assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
assert_eq!('λ'.to_ascii_opt(), None);
assert_eq!('A'.to_ascii(), Some(Ascii { chr: 65u8 }));
assert_eq!('λ'.to_ascii(), None);

assert_eq!("zoä华".to_ascii_opt(), None);
assert_eq!("zoä华".to_ascii(), None);

let test1 = &[127u8, 128u8, 255u8];
assert_eq!((test1).to_ascii_opt(), None);
assert_eq!((test1).to_ascii(), None);

let v = [40u8, 32u8, 59u8];
let v2 = v2ascii!(&[40, 32, 59]);
assert_eq!(v.to_ascii_opt(), Some(v2));
assert_eq!(v.to_ascii(), Some(v2));
let v = [127u8, 128u8, 255u8];
assert_eq!(v.to_ascii_opt(), None);
assert_eq!(v.to_ascii(), None);

let v = "( ;";
let v2 = v2ascii!(&[40, 32, 59]);
assert_eq!(v.to_ascii_opt(), Some(v2));
assert_eq!("zoä华".to_ascii_opt(), None);
assert_eq!(v.to_ascii(), Some(v2));
assert_eq!("zoä华".to_ascii(), None);

assert_eq!((~[40u8, 32u8, 59u8]).into_ascii_opt(), Some(v2ascii!(~[40, 32, 59])));
assert_eq!((~[127u8, 128u8, 255u8]).into_ascii_opt(), None);
assert_eq!((~[40u8, 32u8, 59u8]).into_ascii(), Ok(v2ascii!(~[40, 32, 59])));
assert_eq!((~[127u8, 128u8, 255u8]).into_ascii(), Err(~[127u8, 128u8, 255u8]));

assert_eq!((~"( ;").into_ascii_opt(), Some(v2ascii!(~[40, 32, 59])));
assert_eq!((~"zoä华").into_ascii_opt(), None);
assert_eq!((~"( ;").into_ascii(), Ok(v2ascii!(~[40, 32, 59])));
assert_eq!((~"zoä华").into_ascii(), Err(~"zoä华"));
}

#[test]
Expand Down
21 changes: 12 additions & 9 deletions src/libstd/path/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,9 @@ impl GenericPathUnsafe for Path {
fn shares_volume(me: &Path, path: &str) -> bool {
// path is assumed to have a prefix of Some(DiskPrefix)
match me.prefix {
Some(DiskPrefix) => me.repr[0] == path[0].to_ascii().to_upper().to_byte(),
Some(VerbatimDiskPrefix) => me.repr[4] == path[0].to_ascii().to_upper().to_byte(),
Some(DiskPrefix) => me.repr[0] == path[0].to_ascii().unwrap().to_upper().to_byte(),
Some(VerbatimDiskPrefix) =>
me.repr[4] == path[0].to_ascii().unwrap().to_upper().to_byte(),
_ => false
}
}
Expand Down Expand Up @@ -655,14 +656,16 @@ impl Path {
match (self.prefix, other.prefix) {
(Some(DiskPrefix), Some(VerbatimDiskPrefix)) => {
self.is_absolute() &&
self.repr[0].to_ascii().eq_ignore_case(other.repr[4].to_ascii())
self.repr[0].to_ascii().unwrap().
eq_ignore_case(other.repr[4].to_ascii().unwrap())
}
(Some(VerbatimDiskPrefix), Some(DiskPrefix)) => {
other.is_absolute() &&
self.repr[4].to_ascii().eq_ignore_case(other.repr[0].to_ascii())
self.repr[4].to_ascii().unwrap().
eq_ignore_case(other.repr[0].to_ascii().unwrap())
}
(Some(VerbatimDiskPrefix), Some(VerbatimDiskPrefix)) => {
self.repr[4].to_ascii().eq_ignore_case(other.repr[4].to_ascii())
self.repr[4].to_ascii().unwrap().eq_ignore_case(other.repr[4].to_ascii().unwrap())
}
(Some(UNCPrefix(_,_)), Some(VerbatimUNCPrefix(_,_))) => {
self.repr.slice(2, self.prefix_len()) == other.repr.slice(8, other.prefix_len())
Expand Down Expand Up @@ -729,7 +732,7 @@ impl Path {
let mut s = s.slice_to(len).to_owned();
unsafe {
str::raw::as_owned_vec(&mut s)[0] =
s[0].to_ascii().to_upper().to_byte();
s[0].to_ascii().unwrap().to_upper().to_byte();
}
if is_abs {
// normalize C:/ to C:\
Expand All @@ -744,7 +747,7 @@ impl Path {
let mut s = s.slice_to(len).to_owned();
unsafe {
str::raw::as_owned_vec(&mut s)[4] =
s[4].to_ascii().to_upper().to_byte();
s[4].to_ascii().unwrap().to_upper().to_byte();
}
Some(s)
}
Expand All @@ -765,12 +768,12 @@ impl Path {
let mut s = str::with_capacity(n);
match prefix {
Some(DiskPrefix) => {
s.push_char(prefix_[0].to_ascii().to_upper().to_char());
s.push_char(prefix_[0].to_ascii().unwrap().to_upper().to_char());
s.push_char(':');
}
Some(VerbatimDiskPrefix) => {
s.push_str(prefix_.slice_to(4));
s.push_char(prefix_[4].to_ascii().to_upper().to_char());
s.push_char(prefix_[4].to_ascii().unwrap().to_upper().to_char());
s.push_str(prefix_.slice_from(5));
}
Some(UNCPrefix(a,b)) => {
Expand Down
2 changes: 1 addition & 1 deletion src/libterm/terminfo/parm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> {
}
}
FormatHEX => {
s = s.into_ascii().to_upper().into_bytes();
s = s.into_ascii().unwrap().to_upper().into_bytes();
if flags.alternate {
let s_ = replace(&mut s, ~['0' as u8, 'X' as u8]);
s.push_all_move(s_);
Expand Down
4 changes: 2 additions & 2 deletions src/test/bench/shootout-k-nucleotide-pipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str {
for &(ref k, v) in pairs_sorted.iter() {
unsafe {
buffer.push_str(format!("{} {:0.3f}\n",
k.to_ascii().to_upper().into_str(), v));
k.to_ascii().unwrap().to_upper().into_str(), v));
}
}

Expand All @@ -77,7 +77,7 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str {

// given a map, search for the frequency of a pattern
fn find(mm: &HashMap<~[u8], uint>, key: ~str) -> uint {
let key = key.into_ascii().to_lower().into_str();
let key = key.into_ascii().unwrap().to_lower().into_str();
match mm.find_equiv(&key.as_bytes()) {
option::None => { return 0u; }
option::Some(&num) => { return num; }
Expand Down