Skip to content

Commit

Permalink
Rollup merge of #74021 - 1011X:master, r=dtolnay
Browse files Browse the repository at this point in the history
impl Index<RangeFrom> for CStr

This change implements (partial) slicing for `CStr`.

Since a `CStr` must end in a null byte, it's not possible to trim from the right and still have a valid `CStr`. But, it *is* possible to trim from the left. This lets us be a bit more flexible and treat them more like strings.

```rust
let string = CStr::from_bytes_with_nul(b"Hello World!\0");
let result = CStr::from_bytes_with_nul(b"World!\0");
assert_eq!(&string[6..], result);
```
  • Loading branch information
Manishearth authored Jul 18, 2020
2 parents a6266e2 + 30b8835 commit f305b20
Showing 1 changed file with 38 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/libstd/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1551,6 +1551,27 @@ impl ops::Index<ops::RangeFull> for CString {
}
}

#[stable(feature = "cstr_range_from", since = "1.47.0")]
impl ops::Index<ops::RangeFrom<usize>> for CStr {
type Output = CStr;

fn index(&self, index: ops::RangeFrom<usize>) -> &CStr {
let bytes = self.to_bytes_with_nul();
// we need to manually check the starting index to account for the null
// byte, since otherwise we could get an empty string that doesn't end
// in a null.
if index.start < bytes.len() {
unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) }
} else {
panic!(
"index out of bounds: the len is {} but the index is {}",
bytes.len(),
index.start
);
}
}
}

#[stable(feature = "cstring_asref", since = "1.7.0")]
impl AsRef<CStr> for CStr {
#[inline]
Expand Down Expand Up @@ -1747,4 +1768,21 @@ mod tests {

assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
}

#[test]
fn cstr_index_from() {
let original = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(original).unwrap();
let result = CStr::from_bytes_with_nul(&original[7..]).unwrap();

assert_eq!(&cstr[7..], result);
}

#[test]
#[should_panic]
fn cstr_index_from_empty() {
let original = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(original).unwrap();
let _ = &cstr[original.len()..];
}
}

0 comments on commit f305b20

Please sign in to comment.