#[cfg(test)]
mod tests;
use crate::{owned_slice::OwnedSlice, util::range, IndexOutOfBounds, RangeOfSubset, SharedBytes};
use std::{
borrow::{Borrow, Cow},
fmt::{self, Debug, Display},
io,
net::ToSocketAddrs,
ops::{Deref, Range, RangeBounds},
sync::Arc,
};
#[derive(Clone)]
pub struct SharedStr(pub(crate) Flavour);
#[derive(Clone)]
pub(crate) enum Flavour {
Static(&'static str),
ArcVecSlice(OwnedSlice<Arc<Vec<u8>>, str>),
ArcStringSlice(OwnedSlice<Arc<String>, str>),
}
impl SharedStr {
#[inline]
pub const fn new() -> Self {
Self(Flavour::Static(""))
}
#[inline]
pub const fn from_static(x: &'static str) -> Self {
Self(Flavour::Static(x))
}
#[inline]
pub fn from_string(x: String) -> Self {
Self::from_arc_string(Arc::new(x))
}
#[inline]
pub fn from_arc_string(x: Arc<String>) -> Self {
Self(Flavour::ArcStringSlice(OwnedSlice::new(x).unwrap()))
}
pub fn from_utf8(bytes: SharedBytes) -> Result<Self, SharedBytes> {
use crate::shared_bytes::Flavour::*;
let flavour = match bytes.0 {
Static(b) => match std::str::from_utf8(b) {
Ok(string) => Flavour::Static(string),
Err(_) => return Err(bytes),
},
ArcVecSlice(x) => Flavour::ArcVecSlice(
x.try_map_output()
.map_err(|x| SharedBytes(ArcVecSlice(x)))?,
),
ArcStringSlice(x) => Flavour::ArcStringSlice(
x.try_map_output()
.map_err(|x| SharedBytes(ArcStringSlice(x)))?,
),
};
Ok(Self(flavour))
}
pub fn into_string(self) -> String {
self.into_static_cow().into_owned()
}
fn into_static_cow(self) -> Cow<'static, str> {
match self.0 {
Flavour::Static(x) => Cow::Borrowed(x),
Flavour::ArcVecSlice(x) => Cow::Owned(
x.into_unwrapped(|vec| String::from_utf8(vec).unwrap(), ToOwned::to_owned),
),
Flavour::ArcStringSlice(x) => {
Cow::Owned(x.into_unwrapped(Into::into, ToOwned::to_owned))
}
}
}
#[inline]
pub fn as_str(&self) -> &str {
self.as_slice()
}
#[inline]
pub fn as_slice(&self) -> &str {
match &self.0 {
Flavour::Static(x) => x,
Flavour::ArcVecSlice(x) => x,
Flavour::ArcStringSlice(x) => x,
}
}
pub fn as_static(&self) -> Option<&'static str> {
match &self.0 {
Flavour::Static(x) => Some(x),
_ => None,
}
}
pub fn len(&self) -> usize {
self.as_slice().len()
}
pub fn is_empty(&self) -> bool {
self.as_slice().is_empty()
}
pub fn clear(&mut self) {
*self = Self::new()
}
pub fn truncate(&mut self, at: usize) {
self.try_slice_mut(..at)
.unwrap_or_else(|_| panic!("truncate index '{at}' should be <= len '{}'", self.len()))
}
#[must_use = "consider fn truncate if you don't need the other half"]
pub fn split_off(&mut self, at: usize) -> Self {
self.try_split_off(at)
.unwrap_or_else(|| panic!("split index '{at}' should be <= len '{}'", self.len()))
}
fn try_split_off(&mut self, at: usize) -> Option<Self> {
self.as_slice().get(at..)?; let mut split = self.clone();
split.slice_mut(at..);
self.slice_mut(..at);
Some(split)
}
pub fn range_of_subset(&self, subset: &str) -> Range<usize> {
RangeOfSubset::range_of_subset(self.as_slice(), subset)
}
pub fn slice_cloned<R: RangeBounds<usize>>(&self, r: R) -> Self {
self.non_generic_slice_cloned(self.slice_range_from_bounds(r))
}
fn non_generic_slice_cloned(&self, range: Range<usize>) -> Self {
self.non_generic_try_slice_cloned(range.clone())
.unwrap_or_else(|_| self.out_of_bounds_panic(range))
}
pub fn try_slice_cloned<R: RangeBounds<usize>>(&self, r: R) -> Result<Self, IndexOutOfBounds> {
self.non_generic_try_slice_cloned(self.slice_range_from_bounds(r))
}
fn non_generic_try_slice_cloned(&self, range: Range<usize>) -> Result<Self, IndexOutOfBounds> {
if self.as_slice().get(range.clone()).is_none() {
return Err(IndexOutOfBounds::new());
}
Ok(self.clone().slice_into(range))
}
pub fn slice_into<R: RangeBounds<usize>>(self, r: R) -> Self {
let range = self.slice_range_from_bounds(r);
self.non_generic_slice_into(range)
}
fn non_generic_slice_into(self, range: Range<usize>) -> Self {
self.non_generic_try_slice_into(range.clone())
.unwrap_or_else(|this| this.out_of_bounds_panic(range))
}
pub fn try_slice_into<R: RangeBounds<usize>>(self, r: R) -> Result<Self, Self> {
let range = self.slice_range_from_bounds(r);
self.non_generic_try_slice_into(range)
}
fn non_generic_try_slice_into(mut self, range: Range<usize>) -> Result<Self, Self> {
match self.internal_try_slice_mut(range) {
Ok(()) => Ok(self),
Err(()) => Err(self),
}
}
pub fn slice_mut<R: RangeBounds<usize>>(&mut self, r: R) {
self.non_generic_slice_mut(self.slice_range_from_bounds(r))
}
fn non_generic_slice_mut(&mut self, range: Range<usize>) {
self.internal_try_slice_mut(range.clone())
.unwrap_or_else(|()| self.out_of_bounds_panic(range))
}
pub fn try_slice_mut<R: RangeBounds<usize>>(&mut self, r: R) -> Result<(), IndexOutOfBounds> {
self.non_generic_try_slice_mut(self.slice_range_from_bounds(r))
}
fn non_generic_try_slice_mut(&mut self, range: Range<usize>) -> Result<(), IndexOutOfBounds> {
self.internal_try_slice_mut(range)
.map_err(|()| IndexOutOfBounds::new())
}
fn slice_range_from_bounds<R: RangeBounds<usize>>(&self, r: R) -> Range<usize> {
range::from_slice_bounds(r, || self.len())
}
fn out_of_bounds_panic<R: RangeBounds<usize> + Debug, T>(&self, range: R) -> T {
let length = self.len();
panic!("slice range {range:?} is out of bounds for length {length}")
}
#[must_use = "`internal_try_slice_mut` may fail to mutate `self`"]
fn internal_try_slice_mut(&mut self, range: Range<usize>) -> Result<(), ()> {
match &mut self.0 {
Flavour::Static(old) => match old.get(range) {
None => Err(()),
Some(new) => {
*old = new;
Ok(())
}
},
Flavour::ArcVecSlice(x) => x.try_slice_mut(range),
Flavour::ArcStringSlice(x) => x.try_slice_mut(range),
}
}
}
impl AsRef<[u8]> for SharedStr {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_slice().as_bytes()
}
}
impl AsRef<str> for SharedStr {
#[inline]
fn as_ref(&self) -> &str {
self.as_slice()
}
}
impl Borrow<str> for SharedStr {
#[inline]
fn borrow(&self) -> &str {
self.as_slice()
}
}
impl Debug for SharedStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(self.as_str(), f)
}
}
impl Display for SharedStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(self.as_str(), f)
}
}
impl Default for SharedStr {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Deref for SharedStr {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl Eq for SharedStr {}
impl PartialEq for SharedStr {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<Other: ?Sized> PartialEq<&Other> for SharedStr
where
Self: PartialEq<Other>,
{
#[inline]
fn eq(&self, other: &&Other) -> bool {
self == *other
}
}
impl PartialEq<str> for SharedStr {
#[inline]
fn eq(&self, other: &str) -> bool {
self.as_slice() == other
}
}
impl PartialEq<String> for SharedStr {
#[inline]
fn eq(&self, other: &String) -> bool {
self.as_slice() == other.as_str()
}
}
impl std::hash::Hash for SharedStr {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_slice().hash(state)
}
}
impl From<&'static str> for SharedStr {
#[inline]
fn from(x: &'static str) -> Self {
Self::from_static(x)
}
}
impl From<String> for SharedStr {
#[inline]
fn from(x: String) -> Self {
Self::from_string(x)
}
}
impl From<Arc<String>> for SharedStr {
#[inline]
fn from(x: Arc<String>) -> Self {
Self::from_arc_string(x)
}
}
impl From<char> for SharedStr {
#[inline]
fn from(x: char) -> Self {
Self::from_string(x.into())
}
}
impl From<SharedStr> for String {
fn from(x: SharedStr) -> Self {
x.into_string()
}
}
impl FromIterator<char> for SharedStr {
#[inline]
fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
Self::from_string(iter.into_iter().collect())
}
}
impl<'a> FromIterator<&'a str> for SharedStr {
#[inline]
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
Self::from_string(iter.into_iter().collect())
}
}
impl FromIterator<String> for SharedStr {
#[inline]
fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
Self::from_string(iter.into_iter().collect())
}
}
impl ToSocketAddrs for SharedStr {
type Iter = <str as ToSocketAddrs>::Iter;
#[inline]
fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
self.as_str().to_socket_addrs()
}
}