use tokio_dbus_core::signature::Signature;
#[derive(Debug, Clone, Default)]
pub struct Node<'a> {
pub name: Option<&'a str>,
pub interfaces: Box<[Interface<'a>]>,
pub nodes: Box<[Node<'a>]>,
}
impl<'a> Node<'a> {
pub fn interface(&self, name: &str) -> Option<&Interface<'a>> {
if let Some(interface) = self.interfaces.iter().find(|i| i.name == name) {
return Some(interface);
}
self.nodes.iter().find_map(|n| n.interface(name))
}
pub fn all_interfaces(&self) -> impl Iterator<Item = &Interface<'a>> {
let mut stack = vec![(self, 0usize)];
core::iter::from_fn(move || {
loop {
let (node, index) = stack.last_mut()?;
if let Some(interface) = node.interfaces.get(*index) {
*index += 1;
return Some(interface);
}
let node = *node;
stack.pop();
stack.extend(node.nodes.iter().map(|n| (n, 0)));
}
})
}
}
#[derive(Debug, Clone)]
pub struct Interface<'a> {
pub name: &'a str,
pub methods: Box<[Method<'a>]>,
pub signals: Box<[Signal<'a>]>,
pub properties: Box<[Property<'a>]>,
pub annotations: Box<[Annotation<'a>]>,
pub doc: Doc<'a>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
In,
Out,
}
#[derive(Debug, Clone)]
pub struct Argument<'a> {
pub name: Option<&'a str>,
pub ty: &'a Signature,
pub direction: Direction,
pub doc: Doc<'a>,
}
#[derive(Debug, Clone)]
pub struct Method<'a> {
pub name: &'a str,
pub arguments: Box<[Argument<'a>]>,
pub annotations: Box<[Annotation<'a>]>,
pub doc: Doc<'a>,
}
impl<'a> Method<'a> {
pub fn inputs(&self) -> impl Iterator<Item = &Argument<'a>> {
self.arguments
.iter()
.filter(|a| a.direction == Direction::In)
}
pub fn outputs(&self) -> impl Iterator<Item = &Argument<'a>> {
self.arguments
.iter()
.filter(|a| a.direction == Direction::Out)
}
pub fn no_reply(&self) -> bool {
self.annotations
.iter()
.any(|a| a.name == "org.freedesktop.DBus.Method.NoReply" && a.value == "true")
}
}
#[derive(Debug, Clone)]
pub struct Signal<'a> {
pub name: &'a str,
pub arguments: Box<[Argument<'a>]>,
pub annotations: Box<[Annotation<'a>]>,
pub doc: Doc<'a>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Access {
Read,
Write,
ReadWrite,
}
impl Access {
pub fn is_readable(self) -> bool {
matches!(self, Access::Read | Access::ReadWrite)
}
pub fn is_writable(self) -> bool {
matches!(self, Access::Write | Access::ReadWrite)
}
}
#[derive(Debug, Clone)]
pub struct Property<'a> {
pub name: &'a str,
pub ty: &'a Signature,
pub access: Access,
pub annotations: Box<[Annotation<'a>]>,
pub doc: Doc<'a>,
}
#[derive(Debug, Clone, Copy)]
pub struct Annotation<'a> {
pub name: &'a str,
pub value: &'a str,
}
#[derive(Debug, Default, Clone)]
pub struct Doc<'a> {
pub summary: Option<&'a str>,
pub description: Description<'a>,
}
impl<'a> Doc<'a> {
pub fn lines(&self) -> impl Iterator<Item = &'a str> {
self.summary
.into_iter()
.chain(self.description.paragraph)
.flat_map(|text| text.lines())
.map(str::trim)
.filter(|line| !line.is_empty())
}
pub fn is_empty(&self) -> bool {
self.summary.is_none() && self.description.paragraph.is_none()
}
}
#[derive(Debug, Default, Clone)]
pub struct Description<'a> {
pub paragraph: Option<&'a str>,
}