Skip to content

Commit

Permalink
Add OsStrBytesExt::index
Browse files Browse the repository at this point in the history
  • Loading branch information
dylni committed Nov 4, 2023
1 parent 693c1e2 commit b0180f7
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 39 deletions.
69 changes: 69 additions & 0 deletions src/ext.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
use std::ffi::OsStr;
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeFull;
use std::ops::RangeInclusive;
use std::ops::RangeTo;
use std::ops::RangeToInclusive;
use std::str;

use super::pattern::Encoded as EncodedPattern;
Expand Down Expand Up @@ -243,6 +249,32 @@ pub trait OsStrBytesExt: OsStrBytes {
where
P: Pattern;

/// Equivalent to the [`Index::index`] implementation for [`prim@str`].
///
/// # Panics
///
/// Panics if the index is not a [valid boundary].
///
/// # Examples
///
/// ```
/// use std::ffi::OsStr;
///
/// use os_str_bytes::OsStrBytesExt;
///
/// let os_string = OsStr::new("foobar");
/// assert_eq!("foo", os_string.index(..3));
/// assert_eq!("bar", os_string.index(3..));
/// ```
///
/// [`Index::index`]: std::ops::Index::index
/// [valid boundary]: #indices
#[must_use]
#[track_caller]
fn index<I>(&self, index: I) -> &Self
where
I: SliceIndex;

/// Equivalent to [`str::rfind`].
///
/// # Examples
Expand Down Expand Up @@ -504,6 +536,14 @@ impl OsStrBytesExt for OsStr {
find(self.as_encoded_bytes(), pat)
}

#[inline]
fn index<I>(&self, index: I) -> &Self
where
I: SliceIndex,
{
index.index(self)
}

#[inline]
fn rfind<P>(&self, pat: P) -> Option<usize>
where
Expand Down Expand Up @@ -611,3 +651,32 @@ impl OsStrBytesExt for OsStr {
trim_start_matches(self, &pat.__encode())
}
}

pub trait SliceIndex {
fn index(self, string: &OsStr) -> &OsStr;
}

macro_rules! r#impl {
( $type:ty $(, $var:ident , $($bound:expr),+)? ) => {
impl SliceIndex for $type {
#[inline]
fn index(self, string: &OsStr) -> &OsStr {
$(
let $var = &self;
$(check_bound(string, $bound);)+
)?

// SAFETY: This substring is separated by valid boundaries.
unsafe { os_str(&string.as_encoded_bytes()[self]) }
}
}
};
}
r#impl!(Range<usize>, x, x.start, x.end);
r#impl!(RangeFrom<usize>, x, x.start);
r#impl!(RangeFull);
// [usize::MAX] will always be a valid inclusive end index.
#[rustfmt::skip]
r#impl!(RangeInclusive<usize>, x, *x.start(), x.end().wrapping_add(1));
r#impl!(RangeTo<usize>, x, x.end);
r#impl!(RangeToInclusive<usize>, x, x.end.wrapping_add(1));
60 changes: 21 additions & 39 deletions src/raw_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@ use std::fmt::Formatter;
use std::mem;
use std::ops::Deref;
use std::ops::Index;
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeFull;
use std::ops::RangeInclusive;
use std::ops::RangeTo;
use std::ops::RangeToInclusive;
use std::result;
use std::str;

Expand Down Expand Up @@ -776,6 +770,18 @@ impl From<Box<str>> for Box<RawOsStr> {
}
}

impl<Idx> Index<Idx> for RawOsStr
where
Idx: ext::SliceIndex,
{
type Output = Self;

#[inline]
fn index(&self, idx: Idx) -> &Self::Output {
Self::new(self.as_os_str().index(idx))
}
}

impl ToOwned for RawOsStr {
type Owned = RawOsString;

Expand Down Expand Up @@ -1337,41 +1343,17 @@ macro_rules! r#impl {
r#impl!(RawOsStr);
r#impl!(RawOsString);

macro_rules! r#impl {
( $index_type:ty $(, $index_var:ident , $($bound:expr),+)? ) => {
impl Index<$index_type> for RawOsStr {
type Output = Self;
impl<Idx> Index<Idx> for RawOsString
where
Idx: ext::SliceIndex,
{
type Output = <RawOsStr as Index<Idx>>::Output;

#[inline]
fn index(&self, idx: $index_type) -> &Self::Output {
$(
let $index_var = &idx;
$(self.check_bound($bound);)+
)?

// SAFETY: This substring is separated by valid boundaries.
unsafe { Self::from_encoded_bytes_unchecked(&self.0[idx]) }
}
}

impl Index<$index_type> for RawOsString {
type Output = RawOsStr;

#[inline]
fn index(&self, idx: $index_type) -> &Self::Output {
&(**self)[idx]
}
}
};
#[inline]
fn index(&self, idx: Idx) -> &Self::Output {
&(**self)[idx]
}
}
r#impl!(Range<usize>, x, x.start, x.end);
r#impl!(RangeFrom<usize>, x, x.start);
r#impl!(RangeFull);
// [usize::MAX] will always be a valid inclusive end index.
#[rustfmt::skip]
r#impl!(RangeInclusive<usize>, x, *x.start(), x.end().wrapping_add(1));
r#impl!(RangeTo<usize>, x, x.end);
r#impl!(RangeToInclusive<usize>, x, x.end.wrapping_add(1));

macro_rules! r#impl {
( $(#[$attr:meta])* $type:ty , $other_type:ty ) => {
Expand Down

0 comments on commit b0180f7

Please sign in to comment.