use std::ops::Deref;
use crate::*;
#[derive(Debug, Clone)]
pub struct SubStr {
pub(crate) string: CowStr,
pub(crate) substr: *const str,
}
#[derive(Debug)]
pub struct RangeError;
impl SubStr {
#[must_use]
pub fn new(from: &CowStr) -> SubStr {
let substr = &from[..] as *const str;
SubStr {
string: from.clone(),
substr,
}
}
pub fn new_range(from: &CowStr, start: usize, end: usize) -> Result<SubStr, RangeError> {
if let Some(substr) = from.get(start..end) {
let substr = substr as *const str;
Ok(SubStr {
string: from.clone(),
substr,
})
} else {
Err(RangeError)
}
}
pub fn sub_range(&self, start: usize, end: usize) -> Result<SubStr, RangeError> {
if let Some(substr) = unsafe { &*self.substr }.get(start..end) {
Ok(SubStr {
string: self.string.clone(),
substr,
})
} else {
Err(RangeError)
}
}
#[must_use]
pub fn from_static(from: &'static str) -> SubStr {
CowStr::from_static(from).into_substr()
}
pub fn deref_static(&self) -> Result<&'static str, &str> {
match self.string.deref_static() {
Ok(_) => Ok(unsafe { &*self.substr }),
Err(_) => Err(unsafe { &*self.substr }),
}
}
}
impl Deref for SubStr {
type Target = str;
fn deref(&self) -> &Self::Target {
unsafe { &*self.substr }
}
}
impl From<CowStr> for SubStr {
fn from(cow: CowStr) -> Self {
cow.into_substr()
}
}
impl From<&CowStr> for SubStr {
fn from(cow: &CowStr) -> Self {
SubStr::new(cow)
}
}
#[test]
fn from() {
let origin = CowStr::from("test string");
let substr = SubStr::from(origin);
assert_eq!(&*substr, "test string");
}
#[test]
fn from_ref() {
let origin = CowStr::from("test string");
let substr = SubStr::from(&origin);
assert_eq!(&*substr, "test string");
}
#[test]
fn new_range() {
let origin = CowStr::from("test string");
let substr = SubStr::new_range(&origin, 0, 4).unwrap();
assert_eq!(&*substr, "test");
let subsubstr = substr.sub_range(1, 3).unwrap();
assert_eq!(&*subsubstr, "es");
}
#[test]
#[should_panic]
fn from_panic() {
let origin = CowStr::from("test string");
let _substr = SubStr::new_range(&origin, 10, 100).unwrap();
}