use core::ops::{Bound, RangeBounds};
#[must_use]
pub fn char_slice<R: RangeBounds<usize>>(s: &str, range: R) -> Option<&str> {
let start_inclusive = match range.start_bound() {
Bound::Included(i) => *i,
Bound::Excluded(i) => i.checked_add(1)?,
Bound::Unbounded => 0,
};
if start_inclusive >= s.len() {
return None;
}
let mut iter = s.char_indices();
let start_char = iter.nth(start_inclusive)?;
let start_index = start_char.0;
Some(
if let Some(end_inclusive) = match range.end_bound() {
Bound::Included(i) => Some(*i),
Bound::Excluded(i) => {
if let Some(index) = i.checked_sub(1) {
Some(index)
} else {
return (start_inclusive == 0).then(||
unsafe { s.get_unchecked(0..0) });
}
}
Bound::Unbounded => None,
} {
if end_inclusive >= s.len() {
return None;
}
let offset = end_inclusive.checked_sub(start_inclusive)?;
let end_char = if let Some(n) = offset.checked_sub(1) {
iter.nth(n)?
} else {
start_char
};
let end_index = end_char.0 + end_char.1.len_utf8();
unsafe { s.get_unchecked(start_index..end_index) }
} else {
unsafe { s.get_unchecked(start_index..) }
},
)
}
#[must_use]
pub fn char_slice_mut<R: RangeBounds<usize>>(s: &mut str, range: R) -> Option<&mut str> {
let start_inclusive = match range.start_bound() {
Bound::Included(i) => *i,
Bound::Excluded(i) => i.checked_add(1)?,
Bound::Unbounded => 0,
};
if start_inclusive >= s.len() {
return None;
}
let mut iter = s.char_indices();
let start_char = iter.nth(start_inclusive)?;
let start_index = start_char.0;
Some(
if let Some(end_inclusive) = match range.end_bound() {
Bound::Included(i) => Some(*i),
Bound::Excluded(i) => {
if let Some(index) = i.checked_sub(1) {
Some(index)
} else {
return (start_inclusive == 0).then(||
unsafe { s.get_unchecked_mut(0..0) });
}
}
Bound::Unbounded => None,
} {
if end_inclusive >= s.len() {
return None;
}
let offset = end_inclusive.checked_sub(start_inclusive)?;
let end_char = if let Some(n) = offset.checked_sub(1) {
iter.nth(n)?
} else {
start_char
};
let end_index = end_char.0 + end_char.1.len_utf8();
unsafe { s.get_unchecked_mut(start_index..end_index) }
} else {
unsafe { s.get_unchecked_mut(start_index..) }
},
)
}