Skip to content

Commit

Permalink
add borrow deserialize for string
Browse files Browse the repository at this point in the history
  • Loading branch information
polazarus committed Aug 10, 2023
1 parent 93afd39 commit 51efbb0
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 12 deletions.
17 changes: 7 additions & 10 deletions src/bytes/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,12 @@ where

/// Deserializes a `HipByt` as a borrow if possible.
///
/// ```rust
/// # use serde::Deserialize;
/// # use serde_json;
/// use hipstr::bytes::HipByt;
/// use hipstr::Local;
/// ```ignore
/// use hipstr::HipByt;
/// #[derive(Deserialize)]
/// struct MyStruct<'a> {
/// #[serde(borrow, deserialize_with = "hipstr::bytes::serde::borrowing_deserialize")]
/// field: HipByt<'a, Local>,
/// #[serde(borrow, deserialize_with = "hipstr::bytes::serde::borrowg_deserialize")]
/// field: HipByt<'a>,
/// }
/// # fn main() {
/// let s: MyStruct = serde_json::from_str(r#"{"field": "abc"}"#).unwrap();
Expand All @@ -51,7 +48,7 @@ where
/// # Errors
///
/// Returns a deserializer if either the serialization is incorrect or an unexpected value is encountered.
pub fn borrowing_deserialize<'de: 'a, 'a, D, B>(deserializer: D) -> Result<HipByt<'a, B>, D::Error>
pub fn borrow_deserialize<'de: 'a, 'a, D, B>(deserializer: D) -> Result<HipByt<'a, B>, D::Error>
where
D: serde::Deserializer<'de>,
B: Backend,
Expand All @@ -66,7 +63,7 @@ mod tests {
assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens, Token,
};

use crate::bytes::serde::borrowing_deserialize;
use crate::bytes::serde::borrow_deserialize;
use crate::HipByt;

#[test]
Expand Down Expand Up @@ -111,7 +108,7 @@ mod tests {
use crate::Local;

let v = Value::from("abcdefghijklmnopqrstuvwxyz");
let h1: HipByt<'_, Local> = borrowing_deserialize(&v).unwrap();
let h1: HipByt<'_, Local> = borrow_deserialize(&v).unwrap();
let h2: HipByt<'_, Local> = Deserialize::deserialize(&v).unwrap();
assert!(h1.is_borrowed());
assert!(!h2.is_borrowed());
Expand Down
2 changes: 1 addition & 1 deletion src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod cmp;
mod convert;

#[cfg(feature = "serde")]
mod serde;
pub mod serde;

/// Smart string, i.e. cheaply clonable and sliceable string.
///
Expand Down
88 changes: 87 additions & 1 deletion src/string/serde.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::fmt;

use serde::{de, Deserialize, Serialize};

use super::HipStr;
use crate::Backend;
Expand Down Expand Up @@ -28,10 +31,72 @@ where
}
}

/// Minimal string cow visitor
struct CowVisitor;

impl<'de> de::Visitor<'de> for CowVisitor {
type Value = Cow<'de, str>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string")
}

fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: de::Error,
{
println!("borrowed");
Ok(Cow::Borrowed(v))
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
println!("owned");
Ok(Cow::Owned(v.to_string()))
}

fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Cow::Owned(v))
}
}

/// Deserializes a `HipStr` as a borrow if possible.
///
/// ```ignore
/// use hipstr::HipStr;
/// #[derive(Deserialize)]
/// struct MyStruct<'a> {
/// #[serde(borrow, deserialize_with = "hipstr::string::serde::borrow_deserialize")]
/// field: HipStr<'a>,
/// }
/// # fn main() {
/// let s: MyStruct = serde_json::from_str(r#"{"field": "abc"}"#).unwrap();
/// assert!(s.field.is_borrowed());
/// # }
/// ```
///
/// # Errors
///
/// Returns a deserializer if either the serialization is incorrect or an unexpected value is encountered.
pub fn borrow_deserialize<'de: 'a, 'a, D, B>(deserializer: D) -> Result<HipStr<'a, B>, D::Error>
where
D: serde::Deserializer<'de>,
B: Backend,
{
let cow: Cow<'de, str> = deserializer.deserialize_str(CowVisitor)?;
Ok(HipStr::from(cow))
}

#[cfg(test)]
mod tests {
use serde_test::{assert_de_tokens, assert_tokens, Token};

use super::borrow_deserialize;
use crate::HipStr;

#[test]
Expand All @@ -46,4 +111,25 @@ mod tests {
assert_de_tokens(&small, &[Token::BorrowedStr("abc")]);
assert_de_tokens(&small, &[Token::String("abc")]);
}

#[test]
fn test_serde_borrowing() {
use serde::Deserialize;
use serde_json::Value;

let v = Value::from("abcdefghijklmnopqrstuvwxyz");
let h1: HipStr = borrow_deserialize(&v).unwrap();
let h2: HipStr = Deserialize::deserialize(&v).unwrap();
assert!(h1.is_borrowed());
assert!(!h2.is_borrowed());

#[derive(Deserialize)]
struct MyStruct<'a> {
#[serde(borrow, deserialize_with = "crate::string::serde::borrow_deserialize")]
field: HipStr<'a>,
}
let s: MyStruct =
serde_json::from_str(r#"{"field": "abcdefghijklmnopqrstuvwxyz"}"#).unwrap();
assert!(s.field.is_borrowed());
}
}

0 comments on commit 51efbb0

Please sign in to comment.