Skip to content

Commit 3316a0e

Browse files
committed
auto merge of #12797 : pczarn/rust/str_safety, r=huonw
Along the lines of `shift_ref` and `pop_ref`.
2 parents 1835667 + b0e855a commit 3316a0e

File tree

3 files changed

+85
-60
lines changed

3 files changed

+85
-60
lines changed

src/libglob/lib.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -369,11 +369,11 @@ impl Pattern {
369369
return EntirePatternDoesntMatch;
370370
}
371371

372-
let (c, next) = file.slice_shift_char();
373-
if require_literal(c) {
372+
let (some_c, next) = file.slice_shift_char();
373+
if require_literal(some_c.unwrap()) {
374374
return SubPatternDoesntMatch;
375375
}
376-
prev_char.set(Some(c));
376+
prev_char.set(some_c);
377377
file = next;
378378
}
379379
}
@@ -382,7 +382,8 @@ impl Pattern {
382382
return EntirePatternDoesntMatch;
383383
}
384384

385-
let (c, next) = file.slice_shift_char();
385+
let (some_c, next) = file.slice_shift_char();
386+
let c = some_c.unwrap();
386387
let matches = match *token {
387388
AnyChar => {
388389
!require_literal(c)
@@ -403,7 +404,7 @@ impl Pattern {
403404
if !matches {
404405
return SubPatternDoesntMatch;
405406
}
406-
prev_char.set(Some(c));
407+
prev_char.set(some_c);
407408
file = next;
408409
}
409410
}

src/libstd/str.rs

+75-51
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,7 @@ pub mod raw {
13551355
use libc;
13561356
use ptr;
13571357
use ptr::RawPtr;
1358+
use option::{Option, Some, None};
13581359
use str::{is_utf8, OwnedStr, StrSlice};
13591360
use vec;
13601361
use vec::{MutableVector, ImmutableVector, OwnedVector};
@@ -1464,23 +1465,31 @@ pub mod raw {
14641465
}
14651466

14661467
/// Removes the last byte from a string and returns it.
1468+
/// Returns None when an empty string is passed.
14671469
/// The caller must preserve the valid UTF-8 property.
1468-
pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
1470+
pub unsafe fn pop_byte(s: &mut ~str) -> Option<u8> {
14691471
let len = s.len();
1470-
assert!((len > 0u));
1471-
let b = s[len - 1u];
1472-
s.set_len(len - 1);
1473-
return b;
1472+
if len == 0u {
1473+
return None;
1474+
} else {
1475+
let b = s[len - 1u];
1476+
s.set_len(len - 1);
1477+
return Some(b);
1478+
}
14741479
}
14751480

14761481
/// Removes the first byte from a string and returns it.
1482+
/// Returns None when an empty string is passed.
14771483
/// The caller must preserve the valid UTF-8 property.
1478-
pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
1484+
pub unsafe fn shift_byte(s: &mut ~str) -> Option<u8> {
14791485
let len = s.len();
1480-
assert!((len > 0u));
1481-
let b = s[0];
1482-
*s = s.slice(1, len).to_owned();
1483-
return b;
1486+
if len == 0u {
1487+
return None;
1488+
} else {
1489+
let b = s[0];
1490+
*s = s.slice(1, len).to_owned();
1491+
return Some(b);
1492+
}
14841493
}
14851494

14861495
/// Access the str in its vector representation.
@@ -2273,25 +2282,22 @@ pub trait StrSlice<'a> {
22732282
/// Retrieves the first character from a string slice and returns
22742283
/// it. This does not allocate a new string; instead, it returns a
22752284
/// slice that point one character beyond the character that was
2276-
/// shifted.
2277-
///
2278-
/// # Failure
2279-
///
2280-
/// If the string does not contain any characters.
2285+
/// shifted. If the string does not contain any characters,
2286+
/// a tuple of None and an empty string is returned instead.
22812287
///
22822288
/// # Example
22832289
///
22842290
/// ```rust
22852291
/// let s = "Löwe 老虎 Léopard";
22862292
/// let (c, s1) = s.slice_shift_char();
2287-
/// assert_eq!(c, 'L');
2293+
/// assert_eq!(c, Some('L'));
22882294
/// assert_eq!(s1, "öwe 老虎 Léopard");
22892295
///
22902296
/// let (c, s2) = s1.slice_shift_char();
2291-
/// assert_eq!(c, 'ö');
2297+
/// assert_eq!(c, Some('ö'));
22922298
/// assert_eq!(s2, "we 老虎 Léopard");
22932299
/// ```
2294-
fn slice_shift_char(&self) -> (char, &'a str);
2300+
fn slice_shift_char(&self) -> (Option<char>, &'a str);
22952301

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

27462752
#[inline]
2747-
fn slice_shift_char(&self) -> (char, &'a str) {
2748-
let CharRange {ch, next} = self.char_range_at(0u);
2749-
let next_s = unsafe { raw::slice_bytes(*self, next, self.len()) };
2750-
return (ch, next_s);
2753+
fn slice_shift_char(&self) -> (Option<char>, &'a str) {
2754+
if self.is_empty() {
2755+
return (None, *self);
2756+
} else {
2757+
let CharRange {ch, next} = self.char_range_at(0u);
2758+
let next_s = unsafe { raw::slice_bytes(*self, next, self.len()) };
2759+
return (Some(ch), next_s);
2760+
}
27512761
}
27522762

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

2813-
/// Remove the final character from a string and return it
2814-
///
2815-
/// # Failure
2816-
///
2817-
/// If the string does not contain any characters
2818-
fn pop_char(&mut self) -> char;
2823+
/// Remove the final character from a string and return it. Return None
2824+
/// when the string is empty.
2825+
fn pop_char(&mut self) -> Option<char>;
28192826

2820-
/// Remove the first character from a string and return it
2821-
///
2822-
/// # Failure
2823-
///
2824-
/// If the string does not contain any characters
2825-
fn shift_char(&mut self) -> char;
2827+
/// Remove the first character from a string and return it. Return None
2828+
/// when the string is empty.
2829+
fn shift_char(&mut self) -> Option<char>;
28262830

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

29272931
#[inline]
2928-
fn pop_char(&mut self) -> char {
2932+
fn pop_char(&mut self) -> Option<char> {
29292933
let end = self.len();
2930-
assert!(end > 0u);
2931-
let CharRange {ch, next} = self.char_range_at_reverse(end);
2932-
unsafe { self.set_len(next); }
2933-
return ch;
2934+
if end == 0u {
2935+
return None;
2936+
} else {
2937+
let CharRange {ch, next} = self.char_range_at_reverse(end);
2938+
unsafe { self.set_len(next); }
2939+
return Some(ch);
2940+
}
29342941
}
29352942

29362943
#[inline]
2937-
fn shift_char(&mut self) -> char {
2938-
let CharRange {ch, next} = self.char_range_at(0u);
2939-
*self = self.slice(next, self.len()).to_owned();
2940-
return ch;
2944+
fn shift_char(&mut self) -> Option<char> {
2945+
if self.is_empty() {
2946+
return None;
2947+
} else {
2948+
let CharRange {ch, next} = self.char_range_at(0u);
2949+
*self = self.slice(next, self.len()).to_owned();
2950+
return Some(ch);
2951+
}
29412952
}
29422953

29432954
#[inline]
@@ -3148,22 +3159,23 @@ mod tests {
31483159
let mut data = ~"ประเทศไทย中华";
31493160
let cc = data.pop_char();
31503161
assert_eq!(~"ประเทศไทย中", data);
3151-
assert_eq!('华', cc);
3162+
assert_eq!(Some('华'), cc);
31523163
}
31533164
31543165
#[test]
31553166
fn test_pop_char_2() {
31563167
let mut data2 = ~"";
31573168
let cc2 = data2.pop_char();
31583169
assert_eq!(~"", data2);
3159-
assert_eq!('华', cc2);
3170+
assert_eq!(Some('华'), cc2);
31603171
}
31613172
31623173
#[test]
3163-
#[should_fail]
3164-
fn test_pop_char_fail() {
3174+
fn test_pop_char_empty() {
31653175
let mut data = ~"";
3166-
let _cc3 = data.pop_char();
3176+
let cc3 = data.pop_char();
3177+
assert_eq!(~"", data);
3178+
assert_eq!(None, cc3);
31673179
}
31683180
31693181
#[test]
@@ -3182,7 +3194,7 @@ mod tests {
31823194
let mut data = ~"ประเทศไทย中";
31833195
let cc = data.shift_char();
31843196
assert_eq!(~"ระเทศไทย中", data);
3185-
assert_eq!('ป', cc);
3197+
assert_eq!(Some('ป'), cc);
31863198
}
31873199
31883200
#[test]
@@ -3599,6 +3611,18 @@ mod tests {
35993611
assert!(!" _ ".is_whitespace());
36003612
}
36013613

3614+
#[test]
3615+
fn test_slice_shift_char() {
3616+
let data = "ประเทศไทย中";
3617+
assert_eq!(data.slice_shift_char(), (Some('ป'), "ระเทศไทย中"));
3618+
}
3619+
3620+
#[test]
3621+
fn test_slice_shift_char_2() {
3622+
let empty = "";
3623+
assert_eq!(empty.slice_shift_char(), (None, ""));
3624+
}
3625+
36023626
#[test]
36033627
fn test_push_byte() {
36043628
let mut s = ~"ABC";
@@ -3611,15 +3635,15 @@ mod tests {
36113635
let mut s = ~"ABC";
36123636
let b = unsafe{raw::shift_byte(&mut s)};
36133637
assert_eq!(s, ~"BC");
3614-
assert_eq!(b, 65u8);
3638+
assert_eq!(b, Some(65u8));
36153639
}
36163640
36173641
#[test]
36183642
fn test_pop_byte() {
36193643
let mut s = ~"ABC";
36203644
let b = unsafe{raw::pop_byte(&mut s)};
36213645
assert_eq!(s, ~"AB");
3622-
assert_eq!(b, 67u8);
3646+
assert_eq!(b, Some(67u8));
36233647
}
36243648
36253649
#[test]

src/test/run-pass/utf8_chars.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ pub fn main() {
4242
assert!((!str::is_utf8([0xf0_u8, 0xff_u8, 0xff_u8, 0x10_u8])));
4343

4444
let mut stack = ~"a×c€";
45-
assert_eq!(stack.pop_char(), '€');
46-
assert_eq!(stack.pop_char(), 'c');
45+
assert_eq!(stack.pop_char(), Some('€'));
46+
assert_eq!(stack.pop_char(), Some('c'));
4747
stack.push_char('u');
4848
assert!(stack == ~"a×u");
49-
assert_eq!(stack.shift_char(), 'a');
50-
assert_eq!(stack.shift_char(), '×');
49+
assert_eq!(stack.shift_char(), Some('a'));
50+
assert_eq!(stack.shift_char(), Some('×'));
5151
stack.unshift_char('ß');
5252
assert!(stack == ~"ßu");
5353
}

0 commit comments

Comments
 (0)