Skip to content

Return Option rather than fail for slice_shift_char and {shift,pop}_{char,byte} #12797

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

Merged
merged 3 commits into from
Mar 12, 2014
Merged
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
11 changes: 6 additions & 5 deletions src/libglob/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,11 @@ impl Pattern {
return EntirePatternDoesntMatch;
}

let (c, next) = file.slice_shift_char();
if require_literal(c) {
let (some_c, next) = file.slice_shift_char();
if require_literal(some_c.unwrap()) {
return SubPatternDoesntMatch;
}
prev_char.set(Some(c));
prev_char.set(some_c);
file = next;
}
}
Expand All @@ -382,7 +382,8 @@ impl Pattern {
return EntirePatternDoesntMatch;
}

let (c, next) = file.slice_shift_char();
let (some_c, next) = file.slice_shift_char();
let c = some_c.unwrap();
let matches = match *token {
AnyChar => {
!require_literal(c)
Expand All @@ -403,7 +404,7 @@ impl Pattern {
if !matches {
return SubPatternDoesntMatch;
}
prev_char.set(Some(c));
prev_char.set(some_c);
file = next;
}
}
Expand Down
126 changes: 75 additions & 51 deletions src/libstd/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1355,6 +1355,7 @@ pub mod raw {
use libc;
use ptr;
use ptr::RawPtr;
use option::{Option, Some, None};
use str::{is_utf8, OwnedStr, StrSlice};
use vec;
use vec::{MutableVector, ImmutableVector, OwnedVector};
Expand Down Expand Up @@ -1464,23 +1465,31 @@ pub mod raw {
}

/// Removes the last byte from a string and returns it.
/// Returns None when an empty string is passed.
/// The caller must preserve the valid UTF-8 property.
pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
pub unsafe fn pop_byte(s: &mut ~str) -> Option<u8> {
let len = s.len();
assert!((len > 0u));
let b = s[len - 1u];
s.set_len(len - 1);
return b;
if len == 0u {
return None;
} else {
let b = s[len - 1u];
s.set_len(len - 1);
return Some(b);
}
}

/// Removes the first byte from a string and returns it.
/// Returns None when an empty string is passed.
/// The caller must preserve the valid UTF-8 property.
pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
pub unsafe fn shift_byte(s: &mut ~str) -> Option<u8> {
let len = s.len();
assert!((len > 0u));
let b = s[0];
*s = s.slice(1, len).to_owned();
return b;
if len == 0u {
return None;
} else {
let b = s[0];
*s = s.slice(1, len).to_owned();
return Some(b);
}
}

/// Access the str in its vector representation.
Expand Down Expand Up @@ -2273,25 +2282,22 @@ pub trait StrSlice<'a> {
/// Retrieves the first character from a string slice and returns
/// it. This does not allocate a new string; instead, it returns a
/// slice that point one character beyond the character that was
/// shifted.
///
/// # Failure
///
/// If the string does not contain any characters.
/// shifted. If the string does not contain any characters,
/// a tuple of None and an empty string is returned instead.
///
/// # Example
///
/// ```rust
/// let s = "Löwe 老虎 Léopard";
/// let (c, s1) = s.slice_shift_char();
/// assert_eq!(c, 'L');
/// assert_eq!(c, Some('L'));
/// assert_eq!(s1, "öwe 老虎 Léopard");
///
/// let (c, s2) = s1.slice_shift_char();
/// assert_eq!(c, 'ö');
/// assert_eq!(c, Some('ö'));
/// assert_eq!(s2, "we 老虎 Léopard");
/// ```
fn slice_shift_char(&self) -> (char, &'a str);
fn slice_shift_char(&self) -> (Option<char>, &'a str);

/// Levenshtein Distance between two strings.
fn lev_distance(&self, t: &str) -> uint;
Expand Down Expand Up @@ -2744,10 +2750,14 @@ impl<'a> StrSlice<'a> for &'a str {
}

#[inline]
fn slice_shift_char(&self) -> (char, &'a str) {
let CharRange {ch, next} = self.char_range_at(0u);
let next_s = unsafe { raw::slice_bytes(*self, next, self.len()) };
return (ch, next_s);
fn slice_shift_char(&self) -> (Option<char>, &'a str) {
if self.is_empty() {
return (None, *self);
} else {
let CharRange {ch, next} = self.char_range_at(0u);
let next_s = unsafe { raw::slice_bytes(*self, next, self.len()) };
return (Some(ch), next_s);
}
}

fn lev_distance(&self, t: &str) -> uint {
Expand Down Expand Up @@ -2810,19 +2820,13 @@ pub trait OwnedStr {
/// Appends a character to the back of a string
fn push_char(&mut self, c: char);

/// Remove the final character from a string and return it
///
/// # Failure
///
/// If the string does not contain any characters
fn pop_char(&mut self) -> char;
/// Remove the final character from a string and return it. Return None
/// when the string is empty.
fn pop_char(&mut self) -> Option<char>;

/// Remove the first character from a string and return it
///
/// # Failure
///
/// If the string does not contain any characters
fn shift_char(&mut self) -> char;
/// Remove the first character from a string and return it. Return None
/// when the string is empty.
fn shift_char(&mut self) -> Option<char>;

/// Prepend a char to a string
fn unshift_char(&mut self, ch: char);
Expand Down Expand Up @@ -2925,19 +2929,26 @@ impl OwnedStr for ~str {
}

#[inline]
fn pop_char(&mut self) -> char {
fn pop_char(&mut self) -> Option<char> {
let end = self.len();
assert!(end > 0u);
let CharRange {ch, next} = self.char_range_at_reverse(end);
unsafe { self.set_len(next); }
return ch;
if end == 0u {
return None;
} else {
let CharRange {ch, next} = self.char_range_at_reverse(end);
unsafe { self.set_len(next); }
return Some(ch);
}
}

#[inline]
fn shift_char(&mut self) -> char {
let CharRange {ch, next} = self.char_range_at(0u);
*self = self.slice(next, self.len()).to_owned();
return ch;
fn shift_char(&mut self) -> Option<char> {
if self.is_empty() {
return None;
} else {
let CharRange {ch, next} = self.char_range_at(0u);
*self = self.slice(next, self.len()).to_owned();
return Some(ch);
}
}

#[inline]
Expand Down Expand Up @@ -3148,22 +3159,23 @@ mod tests {
let mut data = ~"ประเทศไทย中华";
let cc = data.pop_char();
assert_eq!(~"ประเทศไทย中", data);
assert_eq!('华', cc);
assert_eq!(Some('华'), cc);
}

#[test]
fn test_pop_char_2() {
let mut data2 = ~"华";
let cc2 = data2.pop_char();
assert_eq!(~"", data2);
assert_eq!('华', cc2);
assert_eq!(Some('华'), cc2);
}

#[test]
#[should_fail]
fn test_pop_char_fail() {
fn test_pop_char_empty() {
let mut data = ~"";
let _cc3 = data.pop_char();
let cc3 = data.pop_char();
assert_eq!(~"", data);
assert_eq!(None, cc3);
}

#[test]
Expand All @@ -3182,7 +3194,7 @@ mod tests {
let mut data = ~"ประเทศไทย中";
let cc = data.shift_char();
assert_eq!(~"ระเทศไทย中", data);
assert_eq!('ป', cc);
assert_eq!(Some('ป'), cc);
}

#[test]
Expand Down Expand Up @@ -3599,6 +3611,18 @@ mod tests {
assert!(!" _ ".is_whitespace());
}

#[test]
fn test_slice_shift_char() {
let data = "ประเทศไทย中";
assert_eq!(data.slice_shift_char(), (Some('ป'), "ระเทศไทย中"));
}

#[test]
fn test_slice_shift_char_2() {
let empty = "";
assert_eq!(empty.slice_shift_char(), (None, ""));
}

#[test]
fn test_push_byte() {
let mut s = ~"ABC";
Expand All @@ -3611,15 +3635,15 @@ mod tests {
let mut s = ~"ABC";
let b = unsafe{raw::shift_byte(&mut s)};
assert_eq!(s, ~"BC");
assert_eq!(b, 65u8);
assert_eq!(b, Some(65u8));
}

#[test]
fn test_pop_byte() {
let mut s = ~"ABC";
let b = unsafe{raw::pop_byte(&mut s)};
assert_eq!(s, ~"AB");
assert_eq!(b, 67u8);
assert_eq!(b, Some(67u8));
}

#[test]
Expand Down
8 changes: 4 additions & 4 deletions src/test/run-pass/utf8_chars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ pub fn main() {
assert!((!str::is_utf8([0xf0_u8, 0xff_u8, 0xff_u8, 0x10_u8])));

let mut stack = ~"a×c€";
assert_eq!(stack.pop_char(), '€');
assert_eq!(stack.pop_char(), 'c');
assert_eq!(stack.pop_char(), Some('€'));
assert_eq!(stack.pop_char(), Some('c'));
stack.push_char('u');
assert!(stack == ~"a×u");
assert_eq!(stack.shift_char(), 'a');
assert_eq!(stack.shift_char(), '×');
assert_eq!(stack.shift_char(), Some('a'));
assert_eq!(stack.shift_char(), Some('×'));
stack.unshift_char('ß');
assert!(stack == ~"ßu");
}