use genco::prelude::*;
use tokio_dbus_core::signature::{self, Signature};
use crate::error::ErrorKind;
use crate::{Error, Result};
fn single(signature: &Signature) -> Result<signature::Type<'_>> {
let mut iter = signature.iter();
let Some(ty) = iter.next() else {
return Err(Error::new(ErrorKind::EmptyType));
};
if iter.next().is_some() {
return Err(Error::new(ErrorKind::CompoundType(signature.to_owned())));
}
Ok(ty)
}
pub fn owned_type(signature: &str) -> Result<rust::Tokens> {
let signature = Signature::new(signature)?;
owned(single(signature)?)
}
pub fn parameter_type(signature: &str) -> Result<rust::Tokens> {
let signature = Signature::new(signature)?;
parameter(single(signature)?)
}
fn owned(ty: signature::Type<'_>) -> Result<rust::Tokens> {
Ok(match ty {
signature::Type::Signature(signature) => basic(signature)?,
signature::Type::Array(element) => {
if let Ok(signature::Type::Dict(key, value)) = single(element) {
let key = owned(single(key)?)?;
let value = owned(single(value)?)?;
quote!(HashMap<$key, $value>)
} else {
let element = owned(single(element)?)?;
quote!(Vec<$element>)
}
}
signature::Type::Struct(fields) => {
let mut out = rust::Tokens::new();
for (index, field) in fields.iter().enumerate() {
if index > 0 {
out.append(quote!(,));
out.space();
}
out.append(owned(field)?);
}
if fields.iter().count() == 1 {
out.append(quote!(,));
}
quote!(($out))
}
signature::Type::Dict(..) => {
return Err(Error::new(ErrorKind::LooseDictEntry));
}
})
}
fn parameter(ty: signature::Type<'_>) -> Result<rust::Tokens> {
Ok(match ty {
signature::Type::Signature(signature) => match signature.as_bytes() {
b"s" => quote!(&str),
b"o" => quote!(&ObjectPath),
b"g" => quote!(&Signature),
b"v" => quote!(&Value),
_ => basic(signature)?,
},
signature::Type::Array(element) => {
if single(element).is_ok_and(|t| matches!(t, signature::Type::Dict(..))) {
let map = owned(ty)?;
quote!(&$map)
} else {
let element = owned(single(element)?)?;
quote!(&[$element])
}
}
signature::Type::Struct(..) => {
let fields = owned(ty)?;
quote!(&$fields)
}
signature::Type::Dict(..) => {
return Err(Error::new(ErrorKind::LooseDictEntry));
}
})
}
fn basic(signature: &Signature) -> Result<rust::Tokens> {
Ok(match signature.as_bytes() {
b"y" => quote!(u8),
b"b" => quote!(bool),
b"n" => quote!(i16),
b"q" => quote!(u16),
b"i" => quote!(i32),
b"u" => quote!(u32),
b"x" => quote!(i64),
b"t" => quote!(u64),
b"d" => quote!(f64),
b"s" => quote!(String),
b"o" => quote!(ObjectPathBuf),
b"g" => quote!(SignatureBuf),
b"v" => quote!(Value),
b"h" => return Err(Error::new(ErrorKind::UnixFd)),
_ => {
return Err(Error::new(ErrorKind::UnknownType(signature.to_owned())));
}
})
}