use super::ByteView;
use alloc::{string::String, sync::Arc};
use core::ops::Deref;
#[repr(C)]
#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct StrView(ByteView);
impl core::fmt::Display for StrView {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", &**self)
}
}
impl core::fmt::Debug for StrView {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", &**self)
}
}
impl Deref for StrView {
type Target = str;
fn deref(&self) -> &Self::Target {
unsafe { core::str::from_utf8_unchecked(&self.0) }
}
}
impl core::hash::Hash for StrView {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.deref().hash(state);
}
}
impl StrView {
#[must_use]
pub fn new(s: &str) -> Self {
Self(ByteView::new(s.as_bytes()))
}
#[doc(hidden)]
#[must_use]
#[allow(clippy::missing_const_for_fn)]
pub unsafe fn from_raw(view: ByteView) -> Self {
Self(view)
}
#[must_use]
pub fn to_detached(&self) -> Self {
Self::new(self)
}
#[must_use]
pub fn slice(&self, range: impl core::ops::RangeBounds<usize>) -> Self {
Self(self.0.slice(range))
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn starts_with(&self, needle: &str) -> bool {
self.0.starts_with(needle.as_bytes())
}
}
impl core::borrow::Borrow<str> for StrView {
fn borrow(&self) -> &str {
self
}
}
impl AsRef<str> for StrView {
fn as_ref(&self) -> &str {
self
}
}
impl From<&str> for StrView {
fn from(value: &str) -> Self {
Self::new(value)
}
}
impl From<String> for StrView {
fn from(value: String) -> Self {
Self::new(&value)
}
}
impl From<Arc<str>> for StrView {
fn from(value: Arc<str>) -> Self {
Self::new(&value)
}
}
impl TryFrom<ByteView> for StrView {
type Error = core::str::Utf8Error;
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
core::str::from_utf8(&value)?;
Ok(Self(value))
}
}
impl From<StrView> for ByteView {
fn from(val: StrView) -> Self {
val.0
}
}
#[cfg(feature = "serde")]
mod serde {
use super::StrView;
use core::fmt;
use core::ops::Deref;
use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
impl Serialize for StrView {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.deref())
}
}
impl<'de> Deserialize<'de> for StrView {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct StrViewVisitor;
impl<'de> Visitor<'de> for StrViewVisitor {
type Value = StrView;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string")
}
fn visit_str<E>(self, v: &str) -> Result<StrView, E>
where
E: de::Error,
{
Ok(StrView::new(v))
}
}
deserializer.deserialize_str(StrViewVisitor)
}
}
}
#[cfg(test)]
mod tests;