From 64675ca6336a40ab039bd589ea59f71ee4f670c9 Mon Sep 17 00:00:00 2001 From: li <@li:maisiliym.xyz> Date: Wed, 21 Oct 2020 06:58:38 +0000 Subject: [PATCH] serde: seemingly working Path & PathBuf --- Cargo.toml | 1 + src/path/path.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++ src/path/pathbuf.rs | 58 ++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 1d431d741..13e2e29c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,6 +74,7 @@ once_cell = { version = "1.3.1", optional = true } pin-project-lite = { version = "0.1.4", optional = true } pin-utils = { version = "0.1.0-alpha.4", optional = true } slab = { version = "0.4.2", optional = true } +serde = { version = "1.0.117", optional = true, default-features = false } # Devdepencency, but they are not allowed to be optional :/ surf = { version = "2.0.0", optional = true } diff --git a/src/path/path.rs b/src/path/path.rs index 185bfaff0..71b12d195 100644 --- a/src/path/path.rs +++ b/src/path/path.rs @@ -8,6 +8,15 @@ use crate::path::{Ancestors, Components, Display, Iter, PathBuf, StripPrefixErro #[cfg(not(target_os = "unknown"))] use crate::{fs, io}; +#[cfg(feature = "serde")] +use { + std::fmt, + serde::{ + ser::{ Serialize, Serializer }, + de::{ Deserialize, Deserializer, Visitor, Unexpected, }, + }, +}; + /// A slice of a path. /// /// This struct is an async version of [`std::path::Path`]. @@ -1039,3 +1048,74 @@ impl AsRef for std::path::PathBuf { p.into() } } + +#[cfg(feature = "serde")] +struct PathVisitor; + +#[cfg(feature = "serde")] +impl<'a> Visitor<'a> for PathVisitor { + type Value = &'a Path; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed path") + } + + fn visit_borrowed_str(self, v: &'a str) -> Result + where + E: serde::de::Error, + { + Ok(v.as_ref()) + } + + fn visit_borrowed_bytes(self, v: &'a [u8]) -> Result + where + E: serde::de::Error, + { + std::str::from_utf8(v) + .map(AsRef::as_ref) + .map_err(|_| serde::de::Error::invalid_value(Unexpected::Bytes(v), &self)) + } +} + +#[cfg(feature = "serde")] +impl<'de: 'a, 'a> Deserialize<'de> for &'a Path { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(PathVisitor) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Path { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.inner.to_str() { + Some(s) => s.serialize(serializer), + None => Err(serde::ser::Error::custom("path contains invalid UTF-8 characters")), + } + } +} + +macro_rules! forwarded_impl { + ( + $(#[doc = $doc:tt])* + ( $($id: ident),* ), $ty: ty, $func: expr + ) => { + $(#[doc = $doc])* + impl<'de $(, $id : Deserialize<'de>,)*> Deserialize<'de> for $ty { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map($func) + } + } + } +} + +#[cfg(feature = "serde")] +forwarded_impl!((), Box, PathBuf::into_boxed_path); diff --git a/src/path/pathbuf.rs b/src/path/pathbuf.rs index f9370cbab..00748bd4a 100644 --- a/src/path/pathbuf.rs +++ b/src/path/pathbuf.rs @@ -13,6 +13,14 @@ use crate::path::Path; use crate::prelude::*; #[cfg(feature = "unstable")] use crate::stream::{self, FromStream, IntoStream}; +#[cfg(feature = "serde")] +use { + std::{ str, fmt }, + serde::{ + ser::{ Serialize, Serializer }, + de::{ Deserialize, Deserializer, Visitor, Unexpected }, + }, +}; /// This struct is an async version of [`std::path::PathBuf`]. /// @@ -375,3 +383,53 @@ impl AsRef for PathBuf { self.inner.as_ref() } } + +#[cfg(feature = "serde")] +struct PathBufVisitor; + +#[cfg(feature = "serde")] +impl<'de> Visitor<'de> for PathBufVisitor { + type Value = PathBuf; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("path string") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(From::from(v)) + } + + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: serde::de::Error, + { + str::from_utf8(v) + .map(From::from) + .map_err(|_| serde::de::Error::invalid_value(Unexpected::Bytes(v), &self)) + } + +} + +#[cfg(feature = "serde")] +impl Serialize for PathBuf { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_path().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for PathBuf { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(PathBufVisitor) + } +}