#![allow(deprecated)]
use core::{convert::TryFrom, str};
use serde::{
de::{Deserialize, Deserializer, Visitor},
ser::{Serialize, Serializer},
};
use std::borrow::Cow;
use crate::{Basic, EncodingFormat, Error, Result, Signature, Type};
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct ObjectPath<'a>(Cow<'a, [u8]>);
impl<'a> ObjectPath<'a> {
pub fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.0) }
}
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn from_bytes_unchecked<'s: 'a>(bytes: &'s [u8]) -> Self {
Self(Cow::from(bytes))
}
pub fn from_str_unchecked<'s: 'a>(path: &'s str) -> Self {
Self::from_bytes_unchecked(path.as_bytes())
}
pub fn from_string_unchecked(path: String) -> Self {
Self(Cow::from(path.as_bytes().to_owned()))
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn to_owned(&self) -> ObjectPath<'static> {
let s = self.0.clone().into_owned();
ObjectPath(Cow::Owned(s))
}
pub fn into_owned(self) -> ObjectPath<'static> {
ObjectPath(Cow::Owned(self.0.into_owned()))
}
}
impl std::default::Default for ObjectPath<'_> {
fn default() -> Self {
ObjectPath::from_str_unchecked("/")
}
}
impl<'a> Basic for ObjectPath<'a> {
const SIGNATURE_CHAR: char = 'o';
const SIGNATURE_STR: &'static str = "o";
const ALIGNMENT: usize = <&str>::ALIGNMENT;
fn alignment(format: EncodingFormat) -> usize {
match format {
EncodingFormat::DBus => <&str>::alignment(format),
#[cfg(feature = "gvariant")]
EncodingFormat::GVariant => 1,
}
}
}
impl<'a> Type for ObjectPath<'a> {
fn signature() -> Signature<'static> {
Signature::from_str_unchecked(Self::SIGNATURE_STR)
}
}
impl<'a> TryFrom<&'a [u8]> for ObjectPath<'a> {
type Error = Error;
fn try_from(value: &'a [u8]) -> Result<Self> {
ensure_correct_object_path_str(value)?;
Ok(Self::from_bytes_unchecked(value))
}
}
impl<'a> TryFrom<&'a str> for ObjectPath<'a> {
type Error = Error;
fn try_from(value: &'a str) -> Result<Self> {
Self::try_from(value.as_bytes())
}
}
impl<'a> TryFrom<String> for ObjectPath<'a> {
type Error = Error;
fn try_from(value: String) -> Result<Self> {
ensure_correct_object_path_str(value.as_bytes())?;
Ok(Self::from_string_unchecked(value))
}
}
impl<'a> std::ops::Deref for ObjectPath<'a> {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl<'a> PartialEq<&str> for ObjectPath<'a> {
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl<'a> std::fmt::Display for ObjectPath<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_str().fmt(f)
}
}
impl<'a> Serialize for ObjectPath<'a> {
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de: 'a, 'a> Deserialize<'de> for ObjectPath<'a> {
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let visitor = ObjectPathVisitor;
deserializer.deserialize_str(visitor)
}
}
struct ObjectPathVisitor;
impl<'de> Visitor<'de> for ObjectPathVisitor {
type Value = ObjectPath<'de>;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("an ObjectPath")
}
#[inline]
fn visit_borrowed_str<E>(self, value: &'de str) -> core::result::Result<ObjectPath<'de>, E>
where
E: serde::de::Error,
{
ObjectPath::try_from(value).map_err(serde::de::Error::custom)
}
#[inline]
fn visit_str<E>(self, value: &str) -> core::result::Result<ObjectPath<'de>, E>
where
E: serde::de::Error,
{
ObjectPath::try_from(String::from(value)).map_err(serde::de::Error::custom)
}
}
fn ensure_correct_object_path_str(path: &[u8]) -> Result<()> {
let mut prev = b'\0';
if path.is_empty() {
return Err(serde::de::Error::invalid_length(0, &"> 0 character"));
}
for i in 0..path.len() {
let c = path[i];
if i == 0 && c != b'/' {
return Err(serde::de::Error::invalid_value(
serde::de::Unexpected::Char(c as char),
&"/",
));
} else if c == b'/' && prev == b'/' {
return Err(serde::de::Error::invalid_value(
serde::de::Unexpected::Str("//"),
&"/",
));
} else if path.len() > 1 && i == (path.len() - 1) && c == b'/' {
return Err(serde::de::Error::invalid_value(
serde::de::Unexpected::Char('/'),
&"an alphanumeric character or `_`",
));
} else if !c.is_ascii_alphanumeric() && c != b'/' && c != b'_' {
return Err(serde::de::Error::invalid_value(
serde::de::Unexpected::Char(c as char),
&"an alphanumeric character, `_` or `/`",
));
}
prev = c;
}
Ok(())
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, serde::Serialize, zvariant_derive::Type)]
pub struct OwnedObjectPath(ObjectPath<'static>);
impl OwnedObjectPath {
pub fn into_inner(self) -> ObjectPath<'static> {
self.0
}
}
impl std::ops::Deref for OwnedObjectPath {
type Target = ObjectPath<'static>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::convert::From<OwnedObjectPath> for ObjectPath<'static> {
fn from(o: OwnedObjectPath) -> Self {
o.into_inner()
}
}
impl<'a> std::convert::From<ObjectPath<'a>> for OwnedObjectPath {
fn from(o: ObjectPath<'a>) -> Self {
OwnedObjectPath(o.into_owned())
}
}
impl TryFrom<&'_ str> for OwnedObjectPath {
type Error = Error;
fn try_from(value: &str) -> Result<Self> {
Ok(Self::from(ObjectPath::try_from(value)?))
}
}
impl TryFrom<String> for OwnedObjectPath {
type Error = Error;
fn try_from(value: String) -> Result<Self> {
Ok(Self::from(ObjectPath::try_from(value)?))
}
}
impl<'de> Deserialize<'de> for OwnedObjectPath {
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let visitor = ObjectPathVisitor;
deserializer
.deserialize_string(visitor)
.map(|v| OwnedObjectPath(v.to_owned()))
}
}