use std::{borrow::Cow, ffi::OsStr};
use super::{
percent::{decode_percents, decode_percents_os_str, decode_percents_str, EncData, EncOsStr},
DBusAddr, Error, KeyValFmt, Result, TransportImpl,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Unix<'a> {
kind: UnixAddrKind<'a>,
}
impl<'a> Unix<'a> {
pub fn kind(&self) -> &UnixAddrKind<'a> {
&self.kind
}
pub fn into_owned(self) -> Unix<'static> {
Unix {
kind: self.kind.into_owned(),
}
}
}
impl<'a> TransportImpl<'a> for Unix<'a> {
fn for_address(s: &'a DBusAddr<'a>) -> Result<Self> {
let mut kind = None;
let mut iter = s.key_val_iter();
for (k, v) in &mut iter {
match k {
"path" | "dir" | "tmpdir" => {
let v = v.ok_or_else(|| Error::MissingValue(k.into()))?;
let v = decode_percents_os_str(v)?;
kind = Some(match k {
"path" => UnixAddrKind::Path(v),
"dir" => UnixAddrKind::Dir(v),
"tmpdir" => UnixAddrKind::Tmpdir(v),
_ => panic!(),
});
break;
}
"abstract" => {
let v = v.ok_or_else(|| Error::MissingValue(k.into()))?;
let v = decode_percents(v)?;
kind = Some(UnixAddrKind::Abstract(v));
break;
}
"runtime" => {
let v = v.ok_or_else(|| Error::MissingValue(k.into()))?;
let v = decode_percents_str(v)?;
if v != "yes" {
return Err(Error::InvalidValue(k.into()));
}
kind = Some(UnixAddrKind::Runtime);
break;
}
_ => continue,
}
}
let Some(kind) = kind else {
return Err(Error::Other(
"invalid `unix:` address, missing required key".into(),
));
};
for (k, _) in iter {
match k {
"path" | "dir" | "tmpdir" | "abstract" | "runtime" => {
return Err(Error::Other("invalid address, only one of `path` `dir` `tmpdir` `abstract` or `runtime` expected".into()));
}
_ => (),
}
}
Ok(Unix { kind })
}
fn fmt_key_val<'s: 'b, 'b>(&'s self, kv: KeyValFmt<'b>) -> KeyValFmt<'b> {
self.kind().fmt_key_val(kv)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum UnixAddrKind<'a> {
Path(Cow<'a, OsStr>),
Dir(Cow<'a, OsStr>),
Tmpdir(Cow<'a, OsStr>),
Abstract(Cow<'a, [u8]>),
Runtime,
}
impl UnixAddrKind<'_> {
fn fmt_key_val<'s: 'b, 'b>(&'s self, kv: KeyValFmt<'b>) -> KeyValFmt<'b> {
match self {
UnixAddrKind::Path(p) => kv.add("path", Some(EncOsStr(p))),
UnixAddrKind::Dir(p) => kv.add("dir", Some(EncOsStr(p))),
UnixAddrKind::Tmpdir(p) => kv.add("tmpdir", Some(EncOsStr(p))),
UnixAddrKind::Abstract(p) => kv.add("abstract", Some(EncData(p))),
UnixAddrKind::Runtime => kv.add("runtime", Some("yes")),
}
}
fn into_owned(self) -> UnixAddrKind<'static> {
match self {
UnixAddrKind::Path(cow) => UnixAddrKind::Path(cow.into_owned().into()),
UnixAddrKind::Dir(cow) => UnixAddrKind::Dir(cow.into_owned().into()),
UnixAddrKind::Tmpdir(cow) => UnixAddrKind::Tmpdir(cow.into_owned().into()),
UnixAddrKind::Abstract(cow) => UnixAddrKind::Abstract(cow.into_owned().into()),
UnixAddrKind::Runtime => UnixAddrKind::Runtime,
}
}
}