From 2b582548851f40f01b5046d1347502096d9ebeb5 Mon Sep 17 00:00:00 2001 From: Yassine Date: Fri, 20 Sep 2024 03:55:43 +0300 Subject: [PATCH] zu: create thin wrapper for bot `Path` and `PathBuf` --- zvariant/src/file_path.rs | 106 ++++++++++++++++++++++++++++++++++++++ zvariant/src/lib.rs | 3 ++ 2 files changed, 109 insertions(+) create mode 100644 zvariant/src/file_path.rs diff --git a/zvariant/src/file_path.rs b/zvariant/src/file_path.rs new file mode 100644 index 000000000..43769697c --- /dev/null +++ b/zvariant/src/file_path.rs @@ -0,0 +1,106 @@ +use std::{ffi::{OsStr, OsString}, path::{Path, PathBuf}}; + +use serde::{de::{self, Visitor}, Deserialize, Deserializer, Serialize, Serializer}; +use crate::de::Deserializer as ZbusDeserializer; + +use crate::Type; + +/// A file name represented as a nul-terminated byte array. +#[derive(Type, Debug, Default, PartialEq)] +#[zvariant(signature = "ay")] +pub struct FilePath(OsString); + +impl From<&Path> for FilePath { + fn from(value: &Path) -> Self { + Self(value.as_os_str().to_os_string()) + } +} + +impl From for FilePath { + fn from(value: PathBuf) -> Self { + Self(value.as_os_str().to_os_string()) + } +} + +impl<'de> Deserialize<'de> for FilePath { + fn deserialize(deserializer: D) -> std::result::Result + where + D: Deserializer<'de> + { + struct FilePathVisitor; + impl<'de> Visitor<'de> for FilePathVisitor { + type Value = FilePath; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("unable to deserialize FilePath") + } + + fn visit_bytes(self, v: &[u8]) -> std::result::Result + where + E: de::Error, + { + unsafe { + Ok(FilePath( + OsStr::from_encoded_bytes_unchecked(v).to_os_string() + )) + } + } + } + let visitor = FilePathVisitor; + deserializer.deserialize_bytes(visitor) + } +} + +impl Serialize for FilePath { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: Serializer + { + serializer.serialize_bytes(&self.0.as_encoded_bytes()) + } +} + + +impl AsRef for FilePath { + fn as_ref(&self) -> &FilePath { + &self + } +} + +impl Into for FilePath { + fn into(self) -> PathBuf { + PathBuf::from(self.0) + } +} + +#[cfg(test)] +mod file_path { + use crate::zvariant::Signature; + use super::*; + + #[test] + fn filepath_from() { + let path = Path::new("/hello/world"); + let _ = FilePath::from(path); + let path_buf = PathBuf::from("/hello/world"); + let _ = FilePath::from(path_buf); + } + + #[test] + fn filepath_signature() { + assert_eq!( + &Signature::Array(zvariant_utils::signature::Child::Static { + child: &Signature::U8 + }), + FilePath::SIGNATURE + ); + } + + #[test] + fn into_test() { + let first = PathBuf::from("/hello/world"); + let p = FilePath::from(first.clone()); + let second: PathBuf = p.into(); + assert_eq!(first, second); + } +} diff --git a/zvariant/src/lib.rs b/zvariant/src/lib.rs index a9a5d4529..68d2059b4 100644 --- a/zvariant/src/lib.rs +++ b/zvariant/src/lib.rs @@ -43,6 +43,9 @@ pub use fd::*; mod object_path; pub use crate::object_path::*; +mod file_path; +pub use crate::file_path::*; + mod ser; pub use ser::*;