use core::fmt;
use core::hash;
use core::str::from_utf8_unchecked;
#[cfg(feature = "alloc")]
use alloc::borrow::ToOwned;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use crate::{Body, WriteAligned, WriteUnaligned};
use crate::{Read, Result, Signature, Write};
#[cfg(feature = "alloc")]
use super::ObjectPathBuf;
use super::{Iter, ObjectPathError, validate};
#[derive(PartialEq, Eq)]
#[repr(transparent)]
pub struct ObjectPath([u8]);
impl ObjectPath {
pub const ROOT: &'static Self = Self::new_const(b"/");
#[track_caller]
pub const fn new_const(path: &[u8]) -> &Self {
if !validate(path) {
panic!("Invalid D-Bus object path");
}
unsafe { Self::new_unchecked(path) }
}
pub fn new<P>(path: &P) -> Result<&Self, ObjectPathError>
where
P: ?Sized + AsRef<[u8]>,
{
let path = path.as_ref();
if !validate(path) {
return Err(ObjectPathError);
}
unsafe { Ok(Self::new_unchecked(path)) }
}
pub fn iter(&self) -> Iter<'_> {
Iter::new(&self.0)
}
#[must_use]
pub fn starts_with(&self, other: &ObjectPath) -> bool {
self.0.starts_with(&other.0)
}
#[must_use]
pub(super) const unsafe fn new_unchecked(path: &[u8]) -> &Self {
unsafe { &*(path as *const _ as *const Self) }
}
pub(crate) fn as_str(&self) -> &str {
unsafe { from_utf8_unchecked(&self.0) }
}
}
impl fmt::Display for ObjectPath {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
impl fmt::Debug for ObjectPath {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
impl hash::Hash for ObjectPath {
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher,
{
self.0.hash(state);
}
}
impl AsRef<ObjectPath> for ObjectPath {
#[inline]
fn as_ref(&self) -> &ObjectPath {
self
}
}
impl AsRef<[u8]> for ObjectPath {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
#[cfg(feature = "alloc")]
impl ToOwned for ObjectPath {
type Owned = ObjectPathBuf;
#[inline]
fn to_owned(&self) -> Self::Owned {
unsafe { ObjectPathBuf::from_raw_vec(self.0.to_vec()) }
}
}
#[cfg(feature = "alloc")]
impl From<&ObjectPath> for Box<ObjectPath> {
#[inline]
fn from(object_path: &ObjectPath) -> Self {
unsafe {
Box::from_raw(Box::into_raw(Box::<[u8]>::from(&object_path.0)) as *mut ObjectPath)
}
}
}
#[cfg(feature = "alloc")]
impl Clone for Box<ObjectPath> {
#[inline]
fn clone(&self) -> Self {
Box::<ObjectPath>::from(&**self)
}
}
impl<'a> IntoIterator for &'a ObjectPath {
type Item = &'a str;
type IntoIter = Iter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl crate::write::sealed::Sealed for ObjectPath {}
impl Write for ObjectPath {
const SIGNATURE: &'static Signature = Signature::OBJECT_PATH;
#[inline]
fn write_to<B>(&self, buf: &mut B)
where
B: ?Sized + WriteAligned,
{
buf.store_frame(self.0.len() as u32);
buf.extend_from_slice_nul(&self.0);
}
#[inline]
fn write_to_unaligned<B>(&self, buf: &mut B)
where
B: ?Sized + WriteUnaligned,
{
buf.store(self.0.len() as u32);
buf.extend_from_slice_nul(&self.0);
}
}
impl_traits_for_write!(
ObjectPath,
ObjectPath::new("/se/tedro/DBusExample")?,
"qo",
ObjectPath
);
impl crate::read::sealed::Sealed for ObjectPath {}
impl Read for ObjectPath {
#[inline]
fn read_from<'de>(buf: &mut Body<'de>) -> Result<&'de Self> {
let len = buf.load::<u32>()? as usize;
let bytes = buf.load_slice_nul(len)?;
Ok(ObjectPath::new(bytes)?)
}
}