From a7c5ced87c814112e31d76706ef3e2dc58795818 Mon Sep 17 00:00:00 2001 From: Jad Ghalayini Date: Thu, 13 Apr 2023 09:27:17 +0100 Subject: [PATCH] Added serde feature (#22) --- Cargo.toml | 5 ++++- src/string.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/vec.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bac771a..14576e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,8 @@ license = "MIT OR Apache-2.0" categories = ["data-structures", "no-std"] keywords = ["string", "vector", "sso", "cow"] +[dependencies] +serde = { version = "1.0", optional = true, default-features = false } + [target.'cfg(loom)'.dependencies] -loom = { version = "0.5", optional = true } +loom = { version = "0.5", optional = true } \ No newline at end of file diff --git a/src/string.rs b/src/string.rs index 03eee1e..bd6fa70 100644 --- a/src/string.rs +++ b/src/string.rs @@ -438,3 +438,55 @@ impl From<&EcoString> for String { const fn exceeded_inline_capacity() -> ! { panic!("exceeded inline capacity"); } + +#[cfg(feature = "serde")] +mod serde { + use crate::EcoString; + use core::fmt; + use serde::de::{Deserializer, Error, Unexpected, Visitor}; + + impl serde::Serialize for EcoString { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.as_str().serialize(serializer) + } + } + + impl<'de> serde::Deserialize<'de> for EcoString { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct EcoStringVisitor; + + impl<'a> Visitor<'a> for EcoStringVisitor { + type Value = EcoString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(EcoString::from(v)) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + if let Ok(utf8) = core::str::from_utf8(v) { + return Ok(EcoString::from(utf8)); + } + Err(Error::invalid_value(Unexpected::Bytes(v), &self)) + } + } + + deserializer.deserialize_str(EcoStringVisitor) + } + } +} diff --git a/src/vec.rs b/src/vec.rs index 44ef5d9..ee47692 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1172,3 +1172,50 @@ fn ref_count_overflow(ptr: NonNull, len: usize) -> ! { fn out_of_bounds(index: usize, len: usize) -> ! { panic!("index is out bounds (index: {index}, len: {len})"); } + +#[cfg(feature = "serde")] +mod serde { + use crate::EcoVec; + use core::{fmt, marker::PhantomData}; + use serde::de::{Deserializer, Visitor}; + + impl serde::Serialize for EcoVec { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + (&self[..]).serialize(serializer) + } + } + + struct EcoVecVisitor(PhantomData); + + impl<'a, T: serde::Deserialize<'a> + Clone> Visitor<'a> for EcoVecVisitor { + type Value = EcoVec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'a>, + { + let len = seq.size_hint().unwrap_or(0); + let mut values = EcoVec::with_capacity(len); + while let Some(value) = seq.next_element()? { + values.push(value) + } + Ok(values) + } + } + + impl<'de, T: serde::Deserialize<'de> + Clone> serde::Deserialize<'de> for EcoVec { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_seq(EcoVecVisitor(PhantomData)) + } + } +}