use crate::StringSlice;
use koto_memory::Ptr;
use std::{
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
ops::{Deref, Range},
path::{Path, PathBuf},
};
use unicode_segmentation::UnicodeSegmentation;
#[derive(Clone)]
pub struct KString(Inner);
#[derive(Clone)]
enum Inner {
Full(Ptr<String>),
Slice(StringSlice<u16>),
SliceLarge(Ptr<StringSlice<usize>>),
}
impl KString {
pub fn with_bounds(&self, new_bounds: Range<usize>) -> Option<Self> {
match &self.0 {
Inner::Full(string) => {
StringSlice::<usize>::new(string.clone(), new_bounds).map(Self::from)
}
Inner::Slice(slice) => slice.with_bounds(new_bounds).map(Self::from),
Inner::SliceLarge(slice) => slice.with_bounds(new_bounds).map(Self::from),
}
}
pub fn pop_front(&mut self) -> Option<Self> {
match self.clone().graphemes(true).next() {
Some(grapheme) => match &mut self.0 {
Inner::Full(string) => {
let slice = StringSlice::<usize>::from(string.clone());
let (popped, rest) = slice.split(grapheme.len()).unwrap();
*self = rest.into();
Some(popped.into())
}
Inner::Slice(slice) => {
let (popped, rest) = slice.split(grapheme.len()).unwrap();
*slice = rest;
Some(popped.into())
}
Inner::SliceLarge(slice) => {
let (popped, rest) = slice.split(grapheme.len()).unwrap();
*Ptr::make_mut(slice) = rest;
Some(popped.into())
}
},
None => None,
}
}
pub fn pop_back(&mut self) -> Option<Self> {
match self.clone().graphemes(true).next_back() {
Some(grapheme) => match &mut self.0 {
Inner::Full(string) => {
let slice = StringSlice::<usize>::from(string.clone());
let (rest, popped) = slice.split(string.len() - grapheme.len()).unwrap();
*self = rest.into();
Some(popped.into())
}
Inner::Slice(slice) => {
let (rest, popped) = slice.split(slice.len() - grapheme.len()).unwrap();
*slice = rest;
Some(popped.into())
}
Inner::SliceLarge(slice) => {
let (rest, popped) = slice.split(slice.len() - grapheme.len()).unwrap();
*Ptr::make_mut(slice) = rest;
Some(popped.into())
}
},
None => None,
}
}
pub fn as_str(&self) -> &str {
match &self.0 {
Inner::Full(string) => string,
Inner::Slice(slice) => slice,
Inner::SliceLarge(slice) => slice,
}
}
}
impl From<Ptr<String>> for KString {
fn from(string: Ptr<String>) -> Self {
Self(Inner::Full(string))
}
}
impl From<StringSlice<usize>> for KString {
fn from(slice: StringSlice<usize>) -> Self {
if let Some(slice16) = slice.try_convert() {
Self(Inner::Slice(slice16))
} else {
Self(Inner::SliceLarge(slice.into()))
}
}
}
impl From<StringSlice<u16>> for KString {
fn from(slice: StringSlice<u16>) -> Self {
Self(Inner::Slice(slice))
}
}
impl From<String> for KString {
fn from(s: String) -> Self {
Ptr::<String>::from(s).into()
}
}
impl From<&str> for KString {
fn from(s: &str) -> Self {
Ptr::<String>::from(s.to_string()).into()
}
}
impl From<PathBuf> for KString {
fn from(path: PathBuf) -> Self {
Self::from(path.to_string_lossy().to_string())
}
}
impl PartialEq<KString> for &str {
fn eq(&self, other: &KString) -> bool {
*self == other.as_str()
}
}
impl PartialEq<&str> for KString {
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl PartialEq for KString {
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str()
}
}
impl Eq for KString {}
impl PartialOrd<KString> for &str {
fn partial_cmp(&self, other: &KString) -> Option<Ordering> {
PartialOrd::partial_cmp(*self, other.as_str())
}
}
impl PartialOrd<&str> for KString {
fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
PartialOrd::partial_cmp(self.as_str(), *other)
}
}
impl PartialOrd for KString {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(Ord::cmp(self, other))
}
}
impl Ord for KString {
fn cmp(&self, other: &Self) -> Ordering {
self.as_str().cmp(other.as_str())
}
}
impl Hash for KString {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_str().hash(state)
}
}
impl Deref for KString {
type Target = str;
fn deref(&self) -> &str {
self.as_str()
}
}
impl AsRef<str> for KString {
fn as_ref(&self) -> &str {
self.deref()
}
}
impl AsRef<Path> for KString {
fn as_ref(&self) -> &Path {
Path::new(self.as_str())
}
}
impl fmt::Display for KString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl fmt::Debug for KString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}