impl Clone for InterfaceRef
Given that all the fields of InterfaceRef
implement Clone, I would expect InterfaceRef
itself to be also clone.
I encountered a deadlock on a project I am working on, which would be solved by this.
"Minimal" example
use std::{error::Error};
use tokio::sync::{mpsc, oneshot};
use zbus::{ConnectionBuilder, InterfaceRef};
/// commands that can be sent to the main thread
pub enum Command {
ComputeAnwser(oneshot::Sender<String>),
}
pub struct DeepThought {
iface: InterfaceRef<interface::DeepThought>,
}
impl DeepThought {
pub async fn compute_anwser(&self) -> u64 {
Self::set_compute_time_async(self.iface.clone(), 7_500_000_000);
42
}
}
/// Interface adapter methods
impl DeepThought {
// this mehtod deadlocks if it is called as a sideeffect while a interface method is running
async fn set_compute_time(&self, years: u64) {
let mut iface = self.iface.get_mut().await;
iface.set_years(years);
iface
.compute_time_changed(self.iface.signal_context())
.await;
}
// this method does not deadlock, but will only execute while the interface is idle
// it also requires a owned InterfaceRef, which is only feasable if InterfaceRef implements Clone
fn set_compute_time_async(iface: InterfaceRef<interface::DeepThought>, years: u64) {
tokio::spawn(async move {
let mut iface_deref = iface.get_mut().await;
iface_deref.set_years(years);
iface_deref
.compute_time_changed(iface.signal_context())
.await;
});
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let (cmd_tx, mut cmd_rx) = mpsc::channel(16);
let iface = interface::DeepThought::new(cmd_tx);
let connection = ConnectionBuilder::session()?
.name("Krikkit.DeepTought")?
.serve_at("/Krikkit/DeepTought", iface)?
.build()
.await?;
let iface = connection
.object_server()
.interface::<_, interface::DeepThought>("/Krikkit/DeepTought")
.await?;
let deep_thought = DeepThought { iface };
// command handling
loop {
match cmd_rx.recv().await {
None => continue,
Some(Command::ComputeAnwser(tx)) => {
let answer = deep_thought.compute_anwser().await;
tx.send(format!("The answer is: {answer}"));
}
}
}
}
/// dbus interface definitions
mod interface {
use tokio::sync::{mpsc, oneshot};
use zbus::dbus_interface;
use crate::Command;
pub struct DeepThought {
years: u64,
cmd_channel: mpsc::Sender<Command>,
}
impl DeepThought {
pub fn new(cmd_channel: mpsc::Sender<Command>) -> Self {
DeepThought {
years: 0,
cmd_channel,
}
}
pub fn set_years(&mut self, years: u64) {
self.years = years
}
}
#[dbus_interface(name = "Krikkit.DeepTought")]
impl DeepThought {
#[dbus_interface(property)]
fn compute_time(&self) -> u64 {
self.years
}
async fn what_is_the_answer(&mut self) -> String {
let (tx, rx) = oneshot::channel();
self.cmd_channel.send(Command::ComputeAnwser(tx)).await;
rx.await.unwrap()
}
}
}