use std::borrow::Cow;
use super::{
decode_percents, decode_percents_str, transport, transport::TransportImpl, Error, Guid,
KeyValIter, Result,
};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DBusAddr<'a> {
pub(super) addr: Cow<'a, str>,
}
impl<'a> DBusAddr<'a> {
pub fn guid(&self) -> Result<Option<Guid>> {
if let Some(guid) = self.get_string("guid") {
Ok(Some(guid?.as_ref().try_into()?))
} else {
Ok(None)
}
}
pub fn transport(&self) -> Result<transport::Transport<'_>> {
transport::Transport::for_address(self)
}
pub fn as_str(&self) -> &str {
match &self.addr {
Cow::Borrowed(a) => a,
Cow::Owned(a) => a.as_str(),
}
}
pub(super) fn key_val_iter(&'a self) -> KeyValIter<'a> {
let mut split = self.addr.splitn(2, ':');
split.next();
let kv = split.next().unwrap_or("");
KeyValIter::new(kv)
}
fn new<A: Into<Cow<'a, str>>>(addr: A) -> Result<Self> {
let addr = addr.into();
let addr = Self { addr };
addr.validate()?;
Ok(addr)
}
fn validate(&self) -> Result<()> {
self.transport()?;
for (k, v) in self.key_val_iter() {
match (k, v) {
("guid", Some(v)) => {
Guid::try_from(decode_percents_str(v)?.as_ref())?;
}
(_, Some(v)) => {
decode_percents(v)?;
}
_ => {}
}
}
Ok(())
}
fn get_string(&'a self, key: &str) -> Option<Result<Cow<'a, str>>> {
let mut val = None;
for (k, v) in self.key_val_iter() {
if key == k {
val = v;
}
}
val.map(decode_percents_str)
}
}
impl<'a> TryFrom<String> for DBusAddr<'a> {
type Error = Error;
fn try_from(addr: String) -> Result<Self> {
Self::new(addr)
}
}
impl<'a> TryFrom<&'a str> for DBusAddr<'a> {
type Error = Error;
fn try_from(addr: &'a str) -> Result<Self> {
Self::new(addr)
}
}
pub trait ToDBusAddrs<'a> {
type Iter: Iterator<Item = Result<DBusAddr<'a>>>;
fn to_dbus_addrs(&'a self) -> Self::Iter;
}
impl<'a> ToDBusAddrs<'a> for DBusAddr<'a> {
type Iter = std::iter::Once<Result<DBusAddr<'a>>>;
fn to_dbus_addrs(&'a self) -> Self::Iter {
std::iter::once(Ok(self.clone()))
}
}
impl<'a> ToDBusAddrs<'a> for str {
type Iter = std::iter::Once<Result<DBusAddr<'a>>>;
fn to_dbus_addrs(&'a self) -> Self::Iter {
std::iter::once(self.try_into())
}
}
impl<'a> ToDBusAddrs<'a> for String {
type Iter = std::iter::Once<Result<DBusAddr<'a>>>;
fn to_dbus_addrs(&'a self) -> Self::Iter {
std::iter::once(self.as_str().try_into())
}
}
impl<'a> ToDBusAddrs<'a> for Vec<Result<DBusAddr<'_>>> {
type Iter = std::iter::Cloned<std::slice::Iter<'a, Result<DBusAddr<'a>>>>;
fn to_dbus_addrs(&'a self) -> Self::Iter {
self.iter().cloned()
}
}