zbus 6.2.0

API for D-Bus communication and its wire format
Documentation
//! The object server API.

use std::{
    future::Future,
    pin::Pin,
    task::{Context, Poll},
};

use serde::{Deserialize, Serialize};
use zruntime::{Event, EventListener};

use crate::{Signature, Type};

/// A response wrapper that notifies after the response has been sent.
///
/// Sometimes in [`interface`] method implementations we need to do some other work after the
/// response has been sent off. This wrapper type allows us to do that. Instead of returning your
/// intended response type directly, wrap it in this type and return it from your method. The
/// [`ResponseDispatchListener`] returned by the `new` method is notified when the response has
/// been sent.
///
/// A typical use case is sending off signals after the response has been sent. The easiest way to
/// do that is to spawn a task from the method that sends the signal but only after being notified
/// of the response dispatch.
///
/// # Caveats
///
/// The notification indicates that the response has been sent off, not that destination peer has
/// received it. That can only be guaranteed for a peer-to-peer connection.
///
/// [`interface`]: crate::interface
#[derive(Debug)]
pub struct ResponseDispatchNotifier<R> {
    response: R,
    event: Option<Event>,
}

impl<R> ResponseDispatchNotifier<R> {
    /// A new notifier for `response`, along with the listener it notifies.
    pub fn new(response: R) -> (Self, ResponseDispatchListener) {
        let event = Event::new();
        let listener = ResponseDispatchListener(event.listen());
        (
            Self {
                response,
                event: Some(event),
            },
            listener,
        )
    }

    /// Get the response.
    pub fn response(&self) -> &R {
        &self.response
    }
}

impl<R> Serialize for ResponseDispatchNotifier<R>
where
    R: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.response.serialize(serializer)
    }
}

impl<'de, R> Deserialize<'de> for ResponseDispatchNotifier<R>
where
    R: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        Ok(Self {
            response: R::deserialize(deserializer)?,
            event: None,
        })
    }
}

impl<R> Type for ResponseDispatchNotifier<R>
where
    R: Type,
{
    const SIGNATURE: &'static Signature = R::SIGNATURE;
}

impl<T> Drop for ResponseDispatchNotifier<T> {
    fn drop(&mut self) {
        if let Some(event) = self.event.take() {
            event.notify(usize::MAX);
        }
    }
}

/// A future that completes once a [`ResponseDispatchNotifier`]'s response has been sent off.
///
/// It also completes if the notifier is dropped without its response ever being sent, for
/// example because the connection went away before the object server could send it.
///
/// Obtain one from [`ResponseDispatchNotifier::new`].
#[derive(Debug)]
#[must_use = "listeners do nothing unless polled"]
pub struct ResponseDispatchListener(EventListener);

impl Future for ResponseDispatchListener {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        Pin::new(&mut self.0).poll(cx)
    }
}