Skip to content

Commit

Permalink
Deserialize borrowed variants of cowstr
Browse files Browse the repository at this point in the history
  • Loading branch information
fasterthanlime committed Oct 16, 2024
1 parent 9041019 commit 88290a8
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .zed/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"command": "clippy"
},
"cargo": {
"features": ["merde/full", "merde_time/full", "merde_json/full"]
"features": ["merde/full", "merde_core/full", "merde_time/full", "merde_json/full"]
}
}
}
Expand Down
88 changes: 80 additions & 8 deletions merde_core/src/cowstr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,30 @@ pub enum CowStr<'s> {
Owned(String),
}

impl CowStr<'static> {
/// Create a new `CowStr` by copying from a `&str` — this might allocate
/// if the `compact_str` feature is disabled, or if the string is longer
/// than `MAX_INLINE_SIZE`.
pub fn copy_from_str(s: &str) -> Self {
#[cfg(feature = "compact_str")]
{
Self::Owned(CompactString::from(s))
}

#[cfg(not(feature = "compact_str"))]
{
Self::Owned(s.into())
}
}
}

impl<'s> CowStr<'s> {
#[inline]
pub fn from_utf8(s: &'s [u8]) -> Result<Self, std::str::Utf8Error> {
Ok(Self::Borrowed(std::str::from_utf8(s)?))
}

#[inline]
pub fn from_utf8_owned(s: Vec<u8>) -> Result<Self, std::str::Utf8Error> {
#[cfg(feature = "compact_str")]
{
Expand All @@ -40,6 +59,7 @@ impl<'s> CowStr<'s> {
}
}

#[inline]
pub fn from_utf8_lossy(s: &'s [u8]) -> Self {
#[cfg(feature = "compact_str")]
{
Expand All @@ -54,6 +74,7 @@ impl<'s> CowStr<'s> {
/// # Safety
///
/// This function is unsafe because it does not check that the bytes are valid UTF-8.
#[inline]
pub unsafe fn from_utf8_unchecked(s: &'s [u8]) -> Self {
#[cfg(feature = "compact_str")]
{
Expand All @@ -67,6 +88,7 @@ impl<'s> CowStr<'s> {
}

impl AsRef<str> for CowStr<'_> {
#[inline]
fn as_ref(&self) -> &str {
crate::compatibility_check_once();

Expand All @@ -80,6 +102,7 @@ impl AsRef<str> for CowStr<'_> {
impl Deref for CowStr<'_> {
type Target = str;

#[inline]
fn deref(&self) -> &Self::Target {
crate::compatibility_check_once();

Expand All @@ -91,6 +114,7 @@ impl Deref for CowStr<'_> {
}

impl<'a> From<Cow<'a, str>> for CowStr<'a> {
#[inline]
fn from(s: Cow<'a, str>) -> Self {
match s {
Cow::Borrowed(s) => CowStr::Borrowed(s),
Expand All @@ -101,31 +125,36 @@ impl<'a> From<Cow<'a, str>> for CowStr<'a> {
}

impl<'s> From<&'s str> for CowStr<'s> {
#[inline]
fn from(s: &'s str) -> Self {
CowStr::Borrowed(s)
}
}

impl From<String> for CowStr<'_> {
#[inline]
fn from(s: String) -> Self {
#[allow(clippy::useless_conversion)]
CowStr::Owned(s.into())
}
}

impl From<Box<str>> for CowStr<'_> {
#[inline]
fn from(s: Box<str>) -> Self {
CowStr::Owned(s.into())
}
}

impl<'s> From<&'s String> for CowStr<'s> {
#[inline]
fn from(s: &'s String) -> Self {
CowStr::Borrowed(s.as_str())
}
}

impl From<CowStr<'_>> for String {
#[inline]
fn from(s: CowStr<'_>) -> Self {
match s {
CowStr::Borrowed(s) => s.into(),
Expand All @@ -136,6 +165,7 @@ impl From<CowStr<'_>> for String {
}

impl From<CowStr<'_>> for Box<str> {
#[inline]
fn from(s: CowStr<'_>) -> Self {
match s {
CowStr::Borrowed(s) => s.into(),
Expand All @@ -145,34 +175,39 @@ impl From<CowStr<'_>> for Box<str> {
}

impl<'a, 'b> PartialEq<CowStr<'a>> for CowStr<'b> {
#[inline]
fn eq(&self, other: &CowStr<'a>) -> bool {
crate::compatibility_check_once();
self.deref() == other.deref()
}
}

impl PartialEq<&str> for CowStr<'_> {
#[inline]
fn eq(&self, other: &&str) -> bool {
crate::compatibility_check_once();
self.deref() == *other
}
}

impl PartialEq<CowStr<'_>> for &str {
#[inline]
fn eq(&self, other: &CowStr<'_>) -> bool {
crate::compatibility_check_once();
*self == other.deref()
}
}

impl PartialEq<String> for CowStr<'_> {
#[inline]
fn eq(&self, other: &String) -> bool {
crate::compatibility_check_once();
self.deref() == other.as_str()
}
}

impl PartialEq<CowStr<'_>> for String {
#[inline]
fn eq(&self, other: &CowStr<'_>) -> bool {
crate::compatibility_check_once();
self.as_str() == other.deref()
Expand All @@ -182,20 +217,23 @@ impl PartialEq<CowStr<'_>> for String {
impl Eq for CowStr<'_> {}

impl Hash for CowStr<'_> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
crate::compatibility_check_once();
self.deref().hash(state)
}
}

impl fmt::Debug for CowStr<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
crate::compatibility_check_once();
self.deref().fmt(f)
}
}

impl fmt::Display for CowStr<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
crate::compatibility_check_once();
self.deref().fmt(f)
Expand All @@ -205,6 +243,7 @@ impl fmt::Display for CowStr<'_> {
impl IntoStatic for CowStr<'_> {
type Output = CowStr<'static>;

#[inline]
fn into_static(self) -> Self::Output {
crate::compatibility_check_once();
match self {
Expand All @@ -221,6 +260,7 @@ mod serde_impls {
use serde::{Deserialize, Serialize};

impl Serialize for CowStr<'_> {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
Expand All @@ -230,20 +270,50 @@ mod serde_impls {
}
}

impl<'de> Deserialize<'de> for CowStr<'_> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
impl<'de: 'a, 'a> Deserialize<'de> for CowStr<'a> {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<CowStr<'a>, D::Error>
where
D: serde::Deserializer<'de>,
{
crate::compatibility_check_once();

#[cfg(feature = "compact_str")]
let s = compact_str::CompactString::deserialize(deserializer)?;

#[cfg(not(feature = "compact_str"))]
let s = String::deserialize(deserializer)?;
struct CowStrVisitor;

impl<'de> serde::de::Visitor<'de> for CowStrVisitor {
type Value = CowStr<'de>;

#[inline]
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a string")
}

#[inline]
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(CowStr::copy_from_str(v))
}

#[inline]
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(CowStr::Borrowed(v))
}

#[inline]
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(v.into())
}
}

Ok(CowStr::Owned(s))
deserializer.deserialize_str(CowStrVisitor)
}
}
}
Expand All @@ -254,13 +324,15 @@ mod rusqlite_impls {
use rusqlite::{types::FromSql, types::FromSqlError, types::ToSql, Result as RusqliteResult};

impl ToSql for CowStr<'_> {
#[inline]
fn to_sql(&self) -> RusqliteResult<rusqlite::types::ToSqlOutput<'_>> {
crate::compatibility_check_once();
Ok(rusqlite::types::ToSqlOutput::Borrowed(self.as_ref().into()))
}
}

impl FromSql for CowStr<'_> {
#[inline]
fn column_result(value: rusqlite::types::ValueRef<'_>) -> Result<Self, FromSqlError> {
crate::compatibility_check_once();
match value {
Expand Down

0 comments on commit 88290a8

Please sign in to comment.