zbus/object_server/
interface.rs

1use std::{
2    any::{Any, TypeId},
3    collections::HashMap,
4    fmt::{self, Write},
5    future::Future,
6    pin::Pin,
7    sync::Arc,
8};
9
10use async_trait::async_trait;
11use zbus::message::Flags;
12use zbus_names::{InterfaceName, MemberName};
13use zvariant::{DynamicType, OwnedValue, Value};
14
15use crate::{
16    async_lock::RwLock, fdo, message::Message, object_server::SignalContext, Connection,
17    ObjectServer, Result,
18};
19use tracing::trace;
20
21/// A helper type returned by [`Interface`] callbacks.
22pub enum DispatchResult<'a> {
23    /// This interface does not support the given method
24    NotFound,
25
26    /// Retry with [Interface::call_mut].
27    ///
28    /// This is equivalent to NotFound if returned by call_mut.
29    RequiresMut,
30
31    /// The method was found and will be completed by running this Future
32    Async(Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>),
33}
34
35impl<'a> DispatchResult<'a> {
36    /// Helper for creating the Async variant
37    pub fn new_async<F, T, E>(conn: &'a Connection, msg: &'a Message, f: F) -> Self
38    where
39        F: Future<Output = ::std::result::Result<T, E>> + Send + 'a,
40        T: serde::Serialize + DynamicType + Send + Sync,
41        E: zbus::DBusError + Send,
42    {
43        DispatchResult::Async(Box::pin(async move {
44            let hdr = msg.header();
45            let ret = f.await;
46            if !hdr.primary().flags().contains(Flags::NoReplyExpected) {
47                match ret {
48                    Ok(r) => conn.reply(msg, &r).await,
49                    Err(e) => conn.reply_dbus_error(&hdr, e).await,
50                }
51                .map(|_seq| ())
52            } else {
53                trace!("No reply expected for {:?} by the caller.", msg);
54                Ok(())
55            }
56        }))
57    }
58}
59
60/// The trait is used to dispatch messages to an interface instance.
61///
62/// This trait should be treated as unstable API and compatibility may break in minor
63/// version bumps. Because of this and other reasons, it is not recommended to manually implement
64/// this trait. The [`crate::dbus_interface`] macro implements it for you.
65///
66/// If you have an advanced use case where `dbus_interface` is inadequate, consider using
67/// [`crate::MessageStream`] or [`crate::blocking::MessageIterator`] instead.
68#[async_trait]
69pub trait Interface: Any + Send + Sync {
70    /// Return the name of the interface. Ex: "org.foo.MyInterface"
71    fn name() -> InterfaceName<'static>
72    where
73        Self: Sized;
74
75    /// Whether each method call will be handled from a different spawned task.
76    ///
77    /// Note: When methods are called from separate tasks, they may not be run in the order in which
78    /// they were called.
79    fn spawn_tasks_for_methods(&self) -> bool {
80        true
81    }
82
83    /// Get a property value. Returns `None` if the property doesn't exist.
84    async fn get(&self, property_name: &str) -> Option<fdo::Result<OwnedValue>>;
85
86    /// Return all the properties.
87    async fn get_all(&self) -> fdo::Result<HashMap<String, OwnedValue>>;
88
89    /// Set a property value.
90    ///
91    /// Return [`DispatchResult::NotFound`] if the property doesn't exist, or
92    /// [`DispatchResult::RequiresMut`] if `set_mut` should be used instead.  The default
93    /// implementation just returns `RequiresMut`.
94    fn set<'call>(
95        &'call self,
96        property_name: &'call str,
97        value: &'call Value<'_>,
98        ctxt: &'call SignalContext<'_>,
99    ) -> DispatchResult<'call> {
100        let _ = (property_name, value, ctxt);
101        DispatchResult::RequiresMut
102    }
103
104    /// Set a property value.
105    ///
106    /// Returns `None` if the property doesn't exist.
107    ///
108    /// This will only be invoked if `set` returned `RequiresMut`.
109    async fn set_mut(
110        &mut self,
111        property_name: &str,
112        value: &Value<'_>,
113        ctxt: &SignalContext<'_>,
114    ) -> Option<fdo::Result<()>>;
115
116    /// Call a method.
117    ///
118    /// Return [`DispatchResult::NotFound`] if the method doesn't exist, or
119    /// [`DispatchResult::RequiresMut`] if `call_mut` should be used instead.
120    ///
121    /// It is valid, though inefficient, for this to always return `RequiresMut`.
122    fn call<'call>(
123        &'call self,
124        server: &'call ObjectServer,
125        connection: &'call Connection,
126        msg: &'call Message,
127        name: MemberName<'call>,
128    ) -> DispatchResult<'call>;
129
130    /// Call a `&mut self` method.
131    ///
132    /// This will only be invoked if `call` returned `RequiresMut`.
133    fn call_mut<'call>(
134        &'call mut self,
135        server: &'call ObjectServer,
136        connection: &'call Connection,
137        msg: &'call Message,
138        name: MemberName<'call>,
139    ) -> DispatchResult<'call>;
140
141    /// Write introspection XML to the writer, with the given indentation level.
142    fn introspect_to_writer(&self, writer: &mut dyn Write, level: usize);
143}
144
145/// A type for a reference counted Interface trait-object, with associated run-time details and a
146/// manual Debug impl.
147#[derive(Clone)]
148pub(crate) struct ArcInterface {
149    pub instance: Arc<RwLock<dyn Interface>>,
150    pub spawn_tasks_for_methods: bool,
151}
152
153impl ArcInterface {
154    pub fn new<I>(iface: I) -> Self
155    where
156        I: Interface,
157    {
158        let spawn_tasks_for_methods = iface.spawn_tasks_for_methods();
159        Self {
160            instance: Arc::new(RwLock::new(iface)),
161            spawn_tasks_for_methods,
162        }
163    }
164}
165
166impl fmt::Debug for ArcInterface {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        f.debug_struct("Arc<RwLock<dyn Interface>>")
169            .finish_non_exhaustive()
170    }
171}
172
173// Note: while it is possible to implement this without `unsafe`, it currently requires a helper
174// trait with a blanket impl that creates `dyn Any` refs.  It's simpler (and more performant) to
175// just check the type ID and do the downcast ourself.
176//
177// See https://github.com/rust-lang/rust/issues/65991 for a rustc feature that will make it
178// possible to get a `dyn Any` ref directly from a `dyn Interface` ref; once that is stable, we can
179// remove this unsafe code.
180impl dyn Interface {
181    /// Return Any of self
182    pub(crate) fn downcast_ref<T: Any>(&self) -> Option<&T> {
183        if <dyn Interface as Any>::type_id(self) == TypeId::of::<T>() {
184            // SAFETY: If type ID matches, it means object is of type T
185            Some(unsafe { &*(self as *const dyn Interface as *const T) })
186        } else {
187            None
188        }
189    }
190
191    /// Return Any of self
192    pub(crate) fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
193        if <dyn Interface as Any>::type_id(self) == TypeId::of::<T>() {
194            // SAFETY: If type ID matches, it means object is of type T
195            Some(unsafe { &mut *(self as *mut dyn Interface as *mut T) })
196        } else {
197            None
198        }
199    }
200}