tor_rpcbase/
dispatch.rs

1//! A multiple-argument dispatch system for our RPC system.
2//!
3//! Our RPC functionality is polymorphic in Methods (what we're told to do) and
4//! Objects (the things that we give the methods to); we want to be able to
5//! provide different implementations for each method, on each object.
6//!
7//! ## Writing RPC functions
8//! <a name="func"></a>
9//!
10//! To participate in this system, an RPC function must have a particular type:
11//! ```rust,ignore
12//! async fn my_rpc_func(
13//!     target: Arc<OBJTYPE>,
14//!     method: Box<METHODTYPE>,
15//!     ctx: Arc<dyn rpc::Context>,
16//!     [ updates: rpc::UpdateSink<METHODTYPE::Update ] // this argument is optional!
17//! ) -> Result<METHODTYPE::Output, impl Into<rpc::RpcError>>
18//! { ... }
19//! ```
20//!
21//! If the "updates" argument is present,
22//! then you will need to use the `[Updates]` flag when registering this function.
23//!
24//! ## Registering RPC functions statically
25//!
26//! After writing a function in the form above,
27//! you need to register it with the RPC system so that it can be invoked on objects of the right type.
28//! The easiest way to do so is by registering it, using [`static_rpc_invoke_fn!`](crate::static_rpc_invoke_fn):
29//!
30//! ```rust,ignore
31//! static_rpc_invoke_fn!{ my_rpc_func; my_other_rpc_func; }
32//! ```
33//!
34//! You can register particular instantiations of generic types, if they're known ahead of time:
35//! ```rust,ignore
36//! static_rpc_invoke_fn!{ my_generic_fn::<PreferredRuntime>; }
37//! ```
38//!
39//! ## Registering RPC functions at runtime.
40//!
41//! If you can't predict all the instantiations of your function in advance,
42//! you can insert them into a [`DispatchTable`] at run time:
43//! ```rust,ignore
44//! fn install_my_rpc_methods<T>(table: &mut DispatchTable) {
45//!     table.insert(invoker_ent!(my_generic_fn::<T>));
46//!     table.insert(invoker_ent!(my_generic_fn_with_update::<T>));
47//! }
48//! ```
49
50use std::any;
51use std::collections::HashMap;
52use std::pin::Pin;
53use std::sync::Arc;
54
55use futures::future::BoxFuture;
56use futures::Sink;
57
58use tor_error::internal;
59use void::Void;
60
61#[cfg(feature = "describe-methods")]
62pub(crate) mod description;
63
64#[cfg(not(feature = "describe-methods"))]
65#[macro_export]
66#[doc(hidden)]
67macro_rules! register_delegation_note {
68    { $from_type:ty, $to_type:ty } => {
69    }
70}
71
72use crate::{Context, DynMethod, Object, RpcError, SendUpdateError};
73
74/// A type-erased serializable value.
75#[doc(hidden)]
76pub type RpcValue = Box<dyn erased_serde::Serialize + Send + 'static>;
77
78/// The return type from an RPC function.
79#[doc(hidden)]
80pub type RpcResult = Result<RpcValue, RpcError>;
81
82/// The return type from sending an update.
83#[doc(hidden)]
84pub type RpcSendResult = Result<RpcValue, SendUpdateError>;
85
86/// A boxed future holding the result of an RPC method.
87pub type RpcResultFuture = BoxFuture<'static, RpcResult>;
88
89/// A boxed sink on which updates can be sent.
90pub type BoxedUpdateSink = Pin<Box<dyn Sink<RpcValue, Error = SendUpdateError> + Send>>;
91
92/// A boxed sink on which updates of a particular type can be sent.
93//
94// NOTE: I'd like our functions to be able to take `impl Sink<U>` instead,
95// but that doesn't work with our macro nonsense.
96// Instead, we might choose to specialize `Invoker` if we find that the
97// extra boxing in this case ever matters.
98pub type UpdateSink<U> = Pin<Box<dyn Sink<U, Error = SendUpdateError> + Send + 'static>>;
99
100/// Type returned by DispatchTable::invoke_special, to represent a future containing
101/// a type-erased type.
102type SpecialResultFuture = BoxFuture<'static, Box<dyn any::Any>>;
103
104/// An installable handler for running a method on an object type.
105///
106/// Callers should not typically implement this trait directly;
107/// instead, use one of its blanket implementations.
108//
109// (This trait isn't sealed because there _are_ theoretical reasons
110// why you might want to provide a special implementation.)
111pub trait Invocable: Send + Sync + 'static {
112    /// Return the type of object that this Invocable will accept.
113    fn object_type(&self) -> any::TypeId;
114    /// Return the type of method that this Invocable will accept.
115    fn method_type(&self) -> any::TypeId;
116    /// Return the names of the type for the object and methods types this Invocable will accept.
117    ///
118    /// Caveats apply as for [`any::type_name`].
119    fn object_and_method_type_names(&self) -> (&'static str, &'static str);
120    /// Describe the types for this Invocable.  Used for debugging.
121    fn describe_invocable(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        let (object_name, method_name) = self.object_and_method_type_names();
123        let rpc_method_name = crate::method::method_info_by_typeid(self.method_type())
124            .map(|mi| mi.method_name)
125            .unwrap_or("???");
126        write!(
127            f,
128            "Invocable({} ({}) for {})",
129            method_name, rpc_method_name, object_name,
130        )
131    }
132
133    /// Invoke this method on an object.
134    ///
135    /// Requires that `obj` has the type `self.object_type()`,
136    /// and that `method` has the type `self.method_type()`.
137    ///
138    /// Unlike `RpcInvocable::invoke()`, does not convert the resulting types
139    /// into serializable formats, and does not require that they _can be_
140    /// so converted.
141    fn invoke_special(
142        &self,
143        obj: Arc<dyn Object>,
144        method: Box<dyn DynMethod>,
145        ctx: Arc<dyn Context>,
146    ) -> Result<SpecialResultFuture, InvokeError>;
147}
148
149/// Subtrait of `Invocable` that requires its outputs to be serializable as RPC replies.
150pub trait RpcInvocable: Invocable {
151    /// Invoke a method on an object.
152    ///
153    /// Requires that `obj` has the type `self.object_type()`,
154    /// and that `method` has the type `self.method_type()`.
155    fn invoke(
156        &self,
157        obj: Arc<dyn Object>,
158        method: Box<dyn DynMethod>,
159        ctx: Arc<dyn Context>,
160        sink: BoxedUpdateSink,
161    ) -> Result<RpcResultFuture, InvokeError>;
162}
163
164/// Helper: Declare a blanket implementation for Invocable.
165///
166/// We provide two blanket implementations:
167/// Once over a fn() taking an update sink,
168/// and once over a fn() not taking an update sink.
169macro_rules! declare_invocable_impl {
170    {
171      // These arguments are used to fill in some blanks that we need to use
172      // when handling an update sink.
173      $( update_gen: $update_gen:ident,
174         update_arg: { $sink:ident: $update_arg:ty } ,
175         update_arg_where: { $($update_arg_where:tt)+ } ,
176         sink_fn: $sink_fn:expr
177      )?
178    } => {
179        impl<M, OBJ, Fut, S, E, $($update_gen)?> Invocable
180             for fn(Arc<OBJ>, Box<M>, Arc<dyn Context + 'static> $(, $update_arg )? ) -> Fut
181        where
182            M: crate::Method,
183            OBJ: Object,
184            S: 'static,
185            E: 'static,
186            Fut: futures::Future<Output = Result<S,E>> + Send + 'static,
187            $( M::Update: From<$update_gen>, )?
188            $( $($update_arg_where)+ )?
189        {
190            fn object_type(&self) -> any::TypeId {
191                any::TypeId::of::<OBJ>()
192            }
193
194            fn method_type(&self) -> any::TypeId {
195                any::TypeId::of::<M>()
196            }
197
198            fn object_and_method_type_names(&self) -> (&'static str, &'static str) {
199                (
200                    any::type_name::<OBJ>(),
201                    any::type_name::<M>(),
202                )
203            }
204
205            fn invoke_special(
206                &self,
207                obj: Arc<dyn Object>,
208                method: Box<dyn DynMethod>,
209                ctx: Arc<dyn Context>,
210            ) -> Result<SpecialResultFuture, $crate::InvokeError> {
211                use futures::FutureExt;
212                #[allow(unused)]
213                use {tor_async_utils::SinkExt as _, futures::SinkExt as _};
214
215                let Ok(obj) = obj.downcast_arc::<OBJ>() else {
216                    return Err(InvokeError::Bug($crate::internal!("Wrong object type")));
217                 };
218                 let Ok(method) = method.downcast::<M>() else {
219                     return Err(InvokeError::Bug($crate::internal!("Wrong method type")));
220                 };
221
222                 $(
223                    let $sink = Box::pin(futures::sink::drain().sink_err_into());
224                 )?
225
226                 Ok(
227                    (self)(obj, method, ctx $(, $sink )? )
228                        .map(|r| Box::new(r) as Box<dyn any::Any>)
229                        .boxed()
230                 )
231            }
232        }
233
234        impl<M, OBJ, Fut, S, E, $($update_gen)?> RpcInvocable
235            for fn(Arc<OBJ>, Box<M>, Arc<dyn Context + 'static> $(, $update_arg )? ) -> Fut
236        where
237            M: crate::RpcMethod,
238            M::Output: serde::Serialize,
239            S: 'static,
240            E: 'static,
241            OBJ: Object,
242            Fut: futures::Future<Output = Result<S, E>> + Send + 'static,
243            M::Output: From<S>,
244            RpcError: From<E>,
245            $( M::Update: From<$update_gen>, )?
246            $( $($update_arg_where)+ )?
247        {
248            fn invoke(
249                &self,
250                obj: Arc<dyn Object>,
251                method: Box<dyn DynMethod>,
252                ctx: Arc<dyn Context>,
253                #[allow(unused)]
254                sink: BoxedUpdateSink,
255            ) -> Result<RpcResultFuture, $crate::InvokeError> {
256                use futures::FutureExt;
257                #[allow(unused)]
258                use tor_async_utils::SinkExt as _;
259                let Ok(obj) = obj.downcast_arc::<OBJ>() else {
260                   return Err(InvokeError::Bug($crate::internal!("Wrong object type")));
261                };
262                let Ok(method) = method.downcast::<M>() else {
263                    return Err(InvokeError::Bug($crate::internal!("Wrong method type")));
264                };
265                $(
266                #[allow(clippy::redundant_closure_call)]
267                let $sink = {
268                    ($sink_fn)(sink)
269                };
270                )?
271
272                Ok(
273                    (self)(obj, method, ctx $(, $sink)? )
274                        .map(|r| {
275                            let r: RpcResult = match r {
276                                Ok(v) => Ok(Box::new(M::Output::from(v))),
277                                Err(e) => Err(RpcError::from(e)),
278                            };
279                            r
280                        })
281                        .boxed()
282                )
283            }
284        }
285    }
286}
287
288declare_invocable_impl! {}
289
290declare_invocable_impl! {
291    update_gen: U,
292    update_arg: { sink: UpdateSink<U> },
293    update_arg_where: {
294        U: 'static + Send,
295        M::Update: serde::Serialize
296    },
297    sink_fn: |sink:BoxedUpdateSink| Box::pin(
298        sink.with_fn(|update: U| RpcSendResult::Ok(
299            Box::new(M::Update::from(update))
300        )
301    ))
302}
303
304/// An annotated Invocable; used to compile a [`DispatchTable`].
305///
306/// Do not construct this type directly!  Instead, use [`invoker_ent!`](crate::invoker_ent!).
307#[allow(clippy::exhaustive_structs)]
308#[derive(Clone, Copy)]
309#[must_use]
310pub struct InvokerEnt {
311    /// The function that implements this method on a given type.
312    ///
313    /// Always present.
314    #[doc(hidden)]
315    pub invoker: &'static (dyn Invocable),
316
317    /// The same function as `invoker`, but only if that function implements
318    /// `RpcInvocable`
319    ///
320    /// This will be `None` if this is a "special" method--that is, one whose inputs and outputs are not serializable,
321    /// and which is therefore not invocable directly from an RPC connection.
322    #[doc(hidden)]
323    pub rpc_invoker: Option<&'static (dyn RpcInvocable)>,
324
325    // These fields are used to make sure that we aren't installing different
326    // functions for the same (Object, Method) pair.
327    // This is a bit of a hack, but we can't do reliable comparison on fn(),
328    // so this is our next best thing.
329    #[doc(hidden)]
330    pub file: &'static str,
331    #[doc(hidden)]
332    pub line: u32,
333    #[doc(hidden)]
334    pub function: &'static str,
335}
336impl InvokerEnt {
337    /// Return true if these two entries appear to be the same declaration
338    /// for the same function.
339    //
340    // It seems like it should be possible to compare these by pointer equality, somehow.
341    // But that would have to be done by comparing `&dyn`, including their vtables,
342    // and Rust's vtables aren't at all stable.  This is a sanity check, not critical
343    // for correctness or security, so it's fine that it will catch most mistakes but
344    // not deliberate abuse or exciting stunts.
345    fn same_decl(&self, other: &Self) -> bool {
346        self.file == other.file && self.line == other.line && self.function == other.function
347    }
348}
349
350/// Create an [`InvokerEnt`] around a single function.
351///
352/// Syntax:
353/// ```rust,ignore
354///   invoker_ent!( function )
355///   invoker_ent!( @special function )
356/// ```
357///
358/// The function must be a `fn` item
359/// (with all necessary generic parameters specified)
360/// with the correct type for an RPC implementation function;
361/// see the [module documentation](self).
362///
363/// If the function is marked as @special,
364/// it does not have to return a type serializable as an RPC message,
365/// and it will not be exposed as an RPC function.
366/// You will still be able to invoke it with `DispatchTable::invoke_special`.
367#[macro_export]
368macro_rules! invoker_ent {
369    { $func:expr } => {
370        $crate::invoker_ent!{ @@impl
371            func: ($func),
372            rpc_invoker:
373                (Some($crate::invocable_func_as_dyn_invocable!($func, $crate::dispatch::RpcInvocable))),
374        }
375    };
376    { @special $func:expr } => {
377        $crate::invoker_ent!{ @@impl
378            func: ($func),
379            rpc_invoker: (None),
380        }
381    };
382    { @@impl
383            func: ($func:expr),
384            rpc_invoker:  ($rpc_invoker:expr),
385    }  => {
386        $crate::dispatch::InvokerEnt {
387            invoker: $crate::invocable_func_as_dyn_invocable!($func, $crate::dispatch::Invocable),
388            rpc_invoker: $rpc_invoker,
389            file: file!(),
390            line: line!(),
391            function: stringify!($func)
392        }
393    };
394}
395
396/// Crate a `Vec<` of [`InvokerEnt`].
397///
398///
399/// See `invoker_ent` for function syntax.
400///
401/// ## Example:
402///
403/// ```rust,ignore
404/// dispatch_table.extend(invoker_ent_list![
405///    function1,
406///    function2,
407///    function3,
408/// ]);
409/// ```
410#[macro_export]
411macro_rules! invoker_ent_list {
412    { $($(@$tag:ident)* $func:expr),* $(,)? } => {
413        vec![
414            $(
415                $crate::invoker_ent!($(@$tag)* $func)
416            ),*
417        ]
418    }
419}
420
421impl std::fmt::Debug for InvokerEnt {
422    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
423        self.invoker.describe_invocable(f)
424    }
425}
426inventory::collect!(InvokerEnt);
427
428/// Cause one or more RPC functions to be statically registered,
429/// each for handling a single Method on a single Object type.
430///
431/// # Example
432///
433/// ```
434/// use tor_rpcbase::{self as rpc, templates::*};
435/// use derive_deftly::Deftly;
436///
437/// use futures::sink::{Sink, SinkExt};
438/// use std::sync::Arc;
439///
440/// #[derive(Debug, Deftly)]
441/// #[derive_deftly(Object)]
442/// struct ExampleObject {}
443/// #[derive(Debug, Deftly)]
444/// #[derive_deftly(Object)]
445/// struct ExampleObject2 {}
446///
447/// #[derive(Debug,serde::Deserialize, Deftly)]
448/// #[derive_deftly(DynMethod)]
449/// #[deftly(rpc(method_name = "arti:x-example"))]
450/// struct ExampleMethod {}
451/// impl rpc::RpcMethod for ExampleMethod {
452///     type Output = ExampleResult;
453///     type Update = Progress;
454/// }
455///
456/// #[derive(serde::Serialize)]
457/// struct ExampleResult {
458///    text: String,
459/// }
460///
461/// #[derive(serde::Serialize)]
462/// struct Progress(f64);
463///
464/// // Note that the types of this function are very constrained:
465/// //  - `obj` must be an Arc<O> for some `Object` type.
466/// //  - `mth` must be Box<M> for some `Method` type.
467/// //  - `ctx` must be Arc<dyn rpc::Context>.
468/// //  - The function must be async.
469/// //  - The return type must be a Result.
470/// //  - The OK variant of the result must M::Output.
471/// //  - The Err variant of the result must implement Into<rpc::RpcError>.
472/// async fn example(obj: Arc<ExampleObject>,
473///                  method: Box<ExampleMethod>,
474///                  ctx: Arc<dyn rpc::Context>,
475/// ) -> Result<ExampleResult, rpc::RpcError> {
476///     println!("Running example method!");
477///     Ok(ExampleResult { text: "here is your result".into() })
478/// }
479///
480/// rpc::static_rpc_invoke_fn!{example;}
481///
482/// // You can declare an example that produces updates as well:
483/// // - The fourth argument must be `UpdateSink<M::Update>`.
484/// async fn example2(obj: Arc<ExampleObject2>,
485///                   method: Box<ExampleMethod>,
486///                   ctx: Arc<dyn rpc::Context>,
487///                   mut updates: rpc::UpdateSink<Progress>
488/// ) -> Result<ExampleResult, rpc::RpcError> {
489///     updates.send(Progress(0.90)).await?;
490///     Ok(ExampleResult { text: "that was fast, wasn't it?".to_string() })
491/// }
492///
493/// rpc::static_rpc_invoke_fn! {
494///     example2;
495/// }
496/// ```
497///
498/// # Syntax:
499///
500/// ```rust,ignore
501/// static_rpc_invoke_fn{
502///   function;  // zero or morea
503///   ...
504/// }
505/// ```
506///
507/// where `function` is an expression referring to a static fn item,
508/// with all necessary generics.
509#[macro_export]
510macro_rules! static_rpc_invoke_fn {
511    {
512        $( $(@$tag:ident)* $func:expr; )*
513    } => {$crate::paste::paste!{ $(
514        $crate::inventory::submit!{
515            $crate::invoker_ent!($(@$tag)* $func)
516        }
517    )* }};
518}
519
520/// Obtain `&'static dyn `[`Invocable`] for a fn item
521///
522/// Given the name of a suitable fn item with all necessary generics,
523/// expands to an expression for it of type `&'static dyn Invocable`.
524#[doc(hidden)]
525#[macro_export]
526macro_rules! invocable_func_as_dyn_invocable { { $f:expr, $trait:path } => { {
527    let f = &($f as _);
528    // We want ^ this `as _ ` cast to convert the fn item (as a value
529    // of its unique unnameable type) to a value of type `fn(..) -> _`.
530    // We're not allowed to write `fn(..) -> _`, though.
531    //
532    // So: we cast it to `_`, and then arrange for the type inference to have to unify
533    // the `_` with the appropriate fn type, which we obtain through further trickery.
534    if let Some(v) = None {
535        // Putting `*f` and the return value from `obtain_fn_type_for`
536        // into the same array means that they must have the same type.
537        // Ie type inference can see they must be the same type.
538        //
539        // We would have preferred to write, above, something like
540        //     let f = $f as <$f as FnTypeOfFnTrait>::FnType;
541        // but the compiler refuses to let us treat the name of the fn item as a type name.
542        //
543        // We evade this problem by passing `$f` to a function that expects
544        // an impl `FnTypeOfFnTrait` and pretends that it would return the `fn` type.
545        let _: [_; 2] = [*f, $crate::dispatch::obtain_fn_type_for($f, v)];
546    }
547    // So, because of all the above, f is of type `fn(..) -> _`, which implements `Invocable`
548    // (assuming the fn item has the right signature).  So we can cast it to dyn.
549    f as &'static dyn $trait
550} } }
551
552/// Helper trait for obtaining (at the type level) `fn` type from an `impl Fn`
553///
554/// Implemented for all types that implement `Fn`, up to and including 6 arguments.
555/// (We only use the arities 3 and 4 right now.)
556#[doc(hidden)]
557pub trait FnTypeOfFnTrait<X> {
558    /// The `fn` type with the same arguments and return type.
559    type FnType;
560}
561/// Provide a blanket implementation of [`FnTypeOfFnTrait`] for some specific arity.
562#[doc(hidden)]
563macro_rules! impl_fn_type_of_fn_trait { { $($arg:ident)* } => {
564    impl<Func, Ret, $($arg),*> FnTypeOfFnTrait<(Ret, $($arg),*)> for Func
565    where Func: Fn($($arg),*) -> Ret {
566        type FnType = fn($($arg),*) -> Ret;
567    }
568} }
569impl_fn_type_of_fn_trait!();
570impl_fn_type_of_fn_trait!(A);
571impl_fn_type_of_fn_trait!(A B);
572impl_fn_type_of_fn_trait!(A B C);
573impl_fn_type_of_fn_trait!(A B C D);
574impl_fn_type_of_fn_trait!(A B C D E);
575impl_fn_type_of_fn_trait!(A B C D E F);
576
577/// Pretend to return a value of type `fn..` corresponding to an `impl Fn`
578///
579/// Given a function implementing `FnTypeOfFnTrait`, ie, any `Fn` closure,
580/// pretends that it would return a value of the corresponding `fn` type.
581///
582/// Doesn't actually return a value (since that would be impossible):
583/// can only be called in statically unreachable contexts,
584/// as evidenced by the uninhabited [`Void`] argument.
585///
586/// Instead we use the type of its mythical return value, in a non-taken branch,
587/// to drive type inference.
588#[doc(hidden)]
589pub const fn obtain_fn_type_for<X, F: FnTypeOfFnTrait<X>>(_: F, v: Void) -> F::FnType {
590    match v {}
591}
592
593/// Actual types to use when looking up a function in our HashMap.
594#[derive(Eq, PartialEq, Clone, Debug, Hash)]
595struct FuncType {
596    /// The type of object to which this function applies.
597    obj_id: any::TypeId,
598    /// The type of method to which this function applies.
599    method_id: any::TypeId,
600}
601
602/// A collection of method implementations for different method and object types.
603///
604/// A DispatchTable is constructed at run-time from entries registered with
605/// [`static_rpc_invoke_fn!`].
606///
607/// There is one for each `arti-rpcserver::RpcMgr`, shared with each `arti-rpcserver::Connection`.
608#[derive(Debug, Clone)]
609pub struct DispatchTable {
610    /// An internal HashMap used to look up the correct function for a given
611    /// method/object pair.
612    map: HashMap<FuncType, InvokerEnt>,
613}
614
615impl DispatchTable {
616    /// Construct a `DispatchTable` from the entries registered statically via
617    /// [`static_rpc_invoke_fn!`].
618    ///
619    /// # Panics
620    ///
621    /// Panics if two entries are found for the same (method,object) types.
622    pub fn from_inventory() -> Self {
623        // We want to assert that there are no duplicates, so we can't use "collect"
624        let mut this = Self {
625            map: HashMap::new(),
626        };
627        for ent in inventory::iter::<InvokerEnt>() {
628            let old_val = this.insert_inner(*ent);
629            if old_val.is_some() {
630                panic!("Tried to insert duplicate entry for {:?}", ent);
631            }
632        }
633        this
634    }
635
636    /// Add a new entry to this DispatchTable, and return the old value if any.
637    fn insert_inner(&mut self, ent: InvokerEnt) -> Option<InvokerEnt> {
638        self.map.insert(
639            FuncType {
640                obj_id: ent.invoker.object_type(),
641                method_id: ent.invoker.method_type(),
642            },
643            ent,
644        )
645    }
646
647    /// Add a new entry to this DispatchTable.
648    ///
649    /// # Panics
650    ///
651    /// Panics if there was a previous entry inserted with the same (Object,Method) pair,
652    /// but (apparently) with a different implementation function, or from a macro invocation.
653    pub fn insert(&mut self, ent: InvokerEnt) {
654        if let Some(old_ent) = self.insert_inner(ent) {
655            // This is not a perfect check by any means; see `same_decl`.
656            assert!(old_ent.same_decl(&ent));
657        }
658    }
659
660    /// Add multiple new entries to this DispatchTable.
661    ///
662    /// # Panics
663    ///
664    /// As for `insert`.
665    pub fn extend<I>(&mut self, ents: I)
666    where
667        I: IntoIterator<Item = InvokerEnt>,
668    {
669        ents.into_iter().for_each(|e| self.insert(e));
670    }
671
672    /// Helper: Look up the `InvokerEnt` for a given method on a given object,
673    /// performing delegation as necessary.
674    ///
675    /// Along with the `InvokerEnt`, return either the object, or a delegation target
676    /// on which the method should be invoked.
677    fn resolve_entry(
678        &self,
679        mut obj: Arc<dyn Object>,
680        method_id: std::any::TypeId,
681    ) -> Result<(Arc<dyn Object>, &InvokerEnt), InvokeError> {
682        loop {
683            let obj_id = {
684                let dyn_obj: &dyn Object = obj.as_ref();
685                dyn_obj.type_id()
686            };
687            let func_type = FuncType { obj_id, method_id };
688            if let Some(ent) = self.map.get(&func_type) {
689                return Ok((obj, ent));
690            } else if let Some(delegation) = obj.delegate() {
691                obj = delegation;
692            } else {
693                return Err(InvokeError::NoImpl);
694            }
695        }
696    }
697
698    /// Helper: Resolve the invoker for a given RPC object and a given method type,
699    /// if there is one.
700    ///
701    /// Along with the invoker, return either the object, or a delegation target
702    /// on which the method should be invoked.
703    pub(crate) fn resolve_rpc_invoker(
704        &self,
705        obj: Arc<dyn Object>,
706        method: &dyn DynMethod,
707    ) -> Result<(Arc<dyn Object>, &'static dyn RpcInvocable), InvokeError> {
708        let (obj, invoker_ent) = self.resolve_entry(obj, method.type_id())?;
709        let rpc_invoker = invoker_ent.rpc_invoker.ok_or_else(|| {
710            InvokeError::Bug(internal!(
711                "Somehow tried to call a special method as an RPC method."
712            ))
713        })?;
714        Ok((obj, rpc_invoker))
715    }
716
717    /// Helper: Return the special invoker for a given object and a given method type,
718    /// if there is one.
719    ///
720    /// Along with the invoker, return either the object, or a delegation target
721    /// on which the method should be invoked.
722    pub(crate) fn resolve_special_invoker<M: crate::Method>(
723        &self,
724        obj: Arc<dyn Object>,
725    ) -> Result<(Arc<dyn Object>, &'static dyn Invocable), InvokeError> {
726        let (obj, invoker_ent) = self.resolve_entry(obj, std::any::TypeId::of::<M>())?;
727        Ok((obj, invoker_ent.invoker))
728    }
729}
730
731/// An error that occurred while trying to invoke a method on an object.
732#[derive(Debug, Clone, thiserror::Error)]
733#[non_exhaustive]
734pub enum InvokeError {
735    /// There is no implementation for the given combination of object
736    /// type and method type.
737    #[error("No implementation for provided object and method types.")]
738    NoImpl,
739
740    /// Tried to call `invoke_without_dispatch` on an RPC method that _does_ support
741    /// regular RPC method dispatch.
742    #[error("Called invoke_without_dispatch on a regular RPC method")]
743    NoDispatchBypass,
744
745    /// An internal problem occurred while invoking a method.
746    #[error("Internal error")]
747    Bug(#[from] tor_error::Bug),
748}
749
750impl From<InvokeError> for RpcError {
751    fn from(err: InvokeError) -> Self {
752        use crate::RpcErrorKind as EK;
753        let kind = match &err {
754            InvokeError::NoImpl => EK::MethodNotImpl,
755            InvokeError::NoDispatchBypass => EK::InternalError,
756            InvokeError::Bug(_) => EK::InternalError,
757        };
758        RpcError::new(err.to_string(), kind)
759    }
760}
761
762#[cfg(test)]
763pub(crate) mod test {
764    // @@ begin test lint list maintained by maint/add_warning @@
765    #![allow(clippy::bool_assert_comparison)]
766    #![allow(clippy::clone_on_copy)]
767    #![allow(clippy::dbg_macro)]
768    #![allow(clippy::mixed_attributes_style)]
769    #![allow(clippy::print_stderr)]
770    #![allow(clippy::print_stdout)]
771    #![allow(clippy::single_char_pattern)]
772    #![allow(clippy::unwrap_used)]
773    #![allow(clippy::unchecked_duration_subtraction)]
774    #![allow(clippy::useless_vec)]
775    #![allow(clippy::needless_pass_by_value)]
776    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
777
778    use crate::{method::RpcMethod, templates::*, DispatchTable, InvokeError, Method, NoUpdates};
779    use derive_deftly::Deftly;
780    use futures::SinkExt;
781    use futures_await_test::async_test;
782    use std::sync::{Arc, RwLock};
783
784    use super::UpdateSink;
785
786    // Define 3 animals and one brick.
787    #[derive(Clone, Deftly)]
788    #[derive_deftly(Object)]
789    pub(crate) struct Swan;
790    #[derive(Clone, Deftly)]
791    #[derive_deftly(Object)]
792    pub(crate) struct Wombat;
793    #[derive(Clone, Deftly)]
794    #[derive_deftly(Object)]
795    pub(crate) struct Sheep;
796    #[derive(Clone, Deftly)]
797    #[derive_deftly(Object)]
798    pub(crate) struct Brick;
799
800    // Define 2 methods.
801    #[derive(Debug, serde::Deserialize, Deftly)]
802    #[derive_deftly(DynMethod)]
803    #[deftly(rpc(method_name = "x-test:getname"))]
804    pub(crate) struct GetName;
805
806    #[derive(Debug, serde::Deserialize, Deftly)]
807    #[derive_deftly(DynMethod)]
808    #[deftly(rpc(method_name = "x-test:getkids"))]
809    pub(crate) struct GetKids;
810
811    impl RpcMethod for GetName {
812        type Output = Outcome;
813        type Update = NoUpdates;
814    }
815    impl RpcMethod for GetKids {
816        type Output = Outcome;
817        type Update = String;
818    }
819
820    #[derive(serde::Serialize)]
821    pub(crate) struct Outcome {
822        pub(crate) v: String,
823    }
824
825    async fn getname_swan(
826        _obj: Arc<Swan>,
827        _method: Box<GetName>,
828        _ctx: Arc<dyn crate::Context>,
829    ) -> Result<Outcome, crate::RpcError> {
830        Ok(Outcome {
831            v: "swan".to_string(),
832        })
833    }
834    async fn getname_sheep(
835        _obj: Arc<Sheep>,
836        _method: Box<GetName>,
837        _ctx: Arc<dyn crate::Context>,
838    ) -> Result<Outcome, crate::RpcError> {
839        Ok(Outcome {
840            v: "sheep".to_string(),
841        })
842    }
843    async fn getname_wombat(
844        _obj: Arc<Wombat>,
845        _method: Box<GetName>,
846        _ctx: Arc<dyn crate::Context>,
847    ) -> Result<Outcome, crate::RpcError> {
848        Ok(Outcome {
849            v: "wombat".to_string(),
850        })
851    }
852    async fn getname_brick(
853        _obj: Arc<Brick>,
854        _method: Box<GetName>,
855        _ctx: Arc<dyn crate::Context>,
856    ) -> Result<Outcome, crate::RpcError> {
857        Ok(Outcome {
858            v: "brick".to_string(),
859        })
860    }
861    async fn getkids_swan(
862        _obj: Arc<Swan>,
863        _method: Box<GetKids>,
864        _ctx: Arc<dyn crate::Context>,
865    ) -> Result<Outcome, crate::RpcError> {
866        Ok(Outcome {
867            v: "cygnets".to_string(),
868        })
869    }
870    async fn getkids_sheep(
871        _obj: Arc<Sheep>,
872        _method: Box<GetKids>,
873        _ctx: Arc<dyn crate::Context>,
874    ) -> Result<Outcome, crate::RpcError> {
875        Ok(Outcome {
876            v: "lambs".to_string(),
877        })
878    }
879    async fn getkids_wombat(
880        _obj: Arc<Wombat>,
881        _method: Box<GetKids>,
882        _ctx: Arc<dyn crate::Context>,
883        mut sink: UpdateSink<String>,
884    ) -> Result<Outcome, crate::RpcError> {
885        let _ignore = sink.send("brb, burrowing".to_string()).await;
886        Ok(Outcome {
887            v: "joeys".to_string(),
888        })
889    }
890
891    static_rpc_invoke_fn! {
892        getname_swan;
893        getname_sheep;
894        getname_wombat;
895        getname_brick;
896
897        getkids_swan;
898        getkids_sheep;
899        getkids_wombat;
900    }
901
902    pub(crate) struct Ctx {
903        table: Arc<RwLock<DispatchTable>>,
904    }
905    impl From<DispatchTable> for Ctx {
906        fn from(table: DispatchTable) -> Self {
907            Self {
908                table: Arc::new(RwLock::new(table)),
909            }
910        }
911    }
912
913    impl crate::Context for Ctx {
914        fn lookup_object(
915            &self,
916            _id: &crate::ObjectId,
917        ) -> Result<std::sync::Arc<dyn crate::Object>, crate::LookupError> {
918            todo!()
919        }
920        fn register_owned(&self, _object: Arc<dyn crate::Object>) -> crate::ObjectId {
921            todo!()
922        }
923
924        fn release_owned(&self, _object: &crate::ObjectId) -> Result<(), crate::LookupError> {
925            todo!()
926        }
927
928        fn dispatch_table(&self) -> &Arc<RwLock<crate::DispatchTable>> {
929            &self.table
930        }
931    }
932
933    #[derive(Deftly, Clone)]
934    #[derive_deftly(Object)]
935    struct GenericObj<T, U>
936    where
937        T: Send + Sync + 'static + Clone + ToString,
938        U: Send + Sync + 'static + Clone + ToString,
939    {
940        name: T,
941        kids: U,
942    }
943
944    async fn getname_generic<T, U>(
945        obj: Arc<GenericObj<T, U>>,
946        _method: Box<GetName>,
947        _ctx: Arc<dyn crate::Context>,
948    ) -> Result<Outcome, crate::RpcError>
949    where
950        T: Send + Sync + 'static + Clone + ToString,
951        U: Send + Sync + 'static + Clone + ToString,
952    {
953        Ok(Outcome {
954            v: obj.name.to_string(),
955        })
956    }
957    async fn getkids_generic<T, U>(
958        obj: Arc<GenericObj<T, U>>,
959        _method: Box<GetKids>,
960        _ctx: Arc<dyn crate::Context>,
961    ) -> Result<Outcome, crate::RpcError>
962    where
963        T: Send + Sync + 'static + Clone + ToString,
964        U: Send + Sync + 'static + Clone + ToString,
965    {
966        Ok(Outcome {
967            v: obj.kids.to_string(),
968        })
969    }
970
971    // We can also install specific instantiations statically.
972    static_rpc_invoke_fn! {
973        getname_generic::<u32,u32>;
974        getname_generic::<&'static str, &'static str>;
975        getkids_generic::<u32,u32>;
976        getkids_generic::<&'static str, &'static str>;
977    }
978
979    // And we can make code to install them dynamically too.
980    impl<T, U> GenericObj<T, U>
981    where
982        T: Send + Sync + 'static + Clone + ToString,
983        U: Send + Sync + 'static + Clone + ToString,
984    {
985        fn install_rpc_functions(table: &mut super::DispatchTable) {
986            table.insert(invoker_ent!(getname_generic::<T, U>));
987            table.insert(invoker_ent!(getkids_generic::<T, U>));
988        }
989    }
990
991    // Define an object with delegation.
992    #[derive(Clone, Deftly)]
993    #[derive_deftly(Object)]
994    #[deftly(rpc(
995        delegate_with = "|this: &Self| this.contents.clone()",
996        delegate_type = "dyn crate::Object"
997    ))]
998    struct CatCarrier {
999        contents: Option<Arc<dyn crate::Object>>,
1000    }
1001
1002    #[async_test]
1003    async fn try_invoke() {
1004        use super::*;
1005        fn invoke_helper<O: Object, M: Method>(
1006            ctx: &Arc<dyn Context>,
1007            obj: O,
1008            method: M,
1009        ) -> Result<RpcResultFuture, InvokeError> {
1010            let animal: Arc<dyn crate::Object> = Arc::new(obj);
1011            let request: Box<dyn DynMethod> = Box::new(method);
1012            let discard = Box::pin(futures::sink::drain().sink_err_into());
1013            crate::invoke_rpc_method(
1014                Arc::clone(ctx),
1015                &crate::ObjectId::from("AnimalIdent"),
1016                animal,
1017                request,
1018                discard,
1019            )
1020        }
1021        async fn invoke_ok<O: crate::Object, M: crate::Method>(
1022            table: &Arc<dyn Context>,
1023            obj: O,
1024            method: M,
1025        ) -> String {
1026            let res = invoke_helper(table, obj, method).unwrap().await.unwrap();
1027            serde_json::to_string(&res).unwrap()
1028        }
1029        async fn sentence<O: crate::Object + Clone>(table: &Arc<dyn Context>, obj: O) -> String {
1030            format!(
1031                "Hello I am a friendly {} and these are my lovely {}.",
1032                invoke_ok(table, obj.clone(), GetName).await,
1033                invoke_ok(table, obj, GetKids).await
1034            )
1035        }
1036
1037        let table: Arc<dyn Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1038
1039        assert_eq!(
1040            sentence(&table, Swan).await,
1041            r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1042        );
1043        assert_eq!(
1044            sentence(&table, Sheep).await,
1045            r#"Hello I am a friendly {"v":"sheep"} and these are my lovely {"v":"lambs"}."#
1046        );
1047        assert_eq!(
1048            sentence(&table, Wombat).await,
1049            r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1050        );
1051
1052        assert!(matches!(
1053            invoke_helper(&table, Brick, GetKids),
1054            Err(InvokeError::NoImpl)
1055        ));
1056
1057        /*
1058        install_generic_fns::<&'static str, &'static str>(&mut table);
1059        install_generic_fns::<u32, u32>(&mut table);
1060        */
1061        let obj1 = GenericObj {
1062            name: "nuncle",
1063            kids: "niblings",
1064        };
1065        let obj2 = GenericObj {
1066            name: 1337_u32,
1067            kids: 271828_u32,
1068        };
1069        assert_eq!(
1070            sentence(&table, obj1).await,
1071            r#"Hello I am a friendly {"v":"nuncle"} and these are my lovely {"v":"niblings"}."#
1072        );
1073        assert_eq!(
1074            sentence(&table, obj2).await,
1075            r#"Hello I am a friendly {"v":"1337"} and these are my lovely {"v":"271828"}."#
1076        );
1077
1078        let obj3 = GenericObj {
1079            name: 13371337_u64,
1080            kids: 2718281828_u64,
1081        };
1082        assert!(matches!(
1083            invoke_helper(&table, obj3.clone(), GetKids),
1084            Err(InvokeError::NoImpl)
1085        ));
1086        {
1087            let mut tab = table.dispatch_table().write().unwrap();
1088            GenericObj::<u64, u64>::install_rpc_functions(&mut tab);
1089        }
1090        assert_eq!(
1091            sentence(&table, obj3).await,
1092            r#"Hello I am a friendly {"v":"13371337"} and these are my lovely {"v":"2718281828"}."#
1093        );
1094
1095        // Try with delegation.
1096        let carrier_1 = CatCarrier {
1097            contents: Some(Arc::new(Wombat)),
1098        };
1099        let carrier_2 = CatCarrier {
1100            contents: Some(Arc::new(Swan)),
1101        };
1102        let carrier_3 = CatCarrier {
1103            contents: Some(Arc::new(Brick)),
1104        };
1105        let carrier_4 = CatCarrier { contents: None };
1106        assert_eq!(
1107            sentence(&table, carrier_1).await,
1108            r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1109        );
1110        assert_eq!(
1111            sentence(&table, carrier_2).await,
1112            r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1113        );
1114        assert!(matches!(
1115            invoke_helper(&table, carrier_3, GetKids),
1116            Err(InvokeError::NoImpl)
1117        ));
1118        assert!(matches!(
1119            invoke_helper(&table, carrier_4, GetKids),
1120            Err(InvokeError::NoImpl)
1121        ));
1122    }
1123
1124    // Doesn't implement Deserialize.
1125    #[derive(Debug)]
1126    struct MyObject {}
1127
1128    #[derive(Debug, Deftly)]
1129    #[derive_deftly(DynMethod)]
1130    #[deftly(rpc(no_method_name))]
1131    struct SpecialOnly {}
1132    impl Method for SpecialOnly {
1133        type Output = Result<MyObject, MyObject>; // Doesn't implement deserialize.
1134        type Update = crate::NoUpdates;
1135    }
1136
1137    async fn specialonly_swan(
1138        _obj: Arc<Swan>,
1139        _method: Box<SpecialOnly>,
1140        _ctx: Arc<dyn crate::Context>,
1141    ) -> Result<MyObject, MyObject> {
1142        Ok(MyObject {})
1143    }
1144    static_rpc_invoke_fn! { @special specialonly_swan; }
1145
1146    #[async_test]
1147    async fn try_invoke_special() {
1148        let table = crate::DispatchTable::from_inventory();
1149        let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(table));
1150
1151        let res: Outcome =
1152            crate::invoke_special_method(Arc::clone(&ctx), Arc::new(Swan), Box::new(GetKids))
1153                .await
1154                .unwrap()
1155                .unwrap();
1156
1157        assert_eq!(res.v, "cygnets");
1158
1159        let _an_obj: MyObject = crate::invoke_special_method(
1160            Arc::clone(&ctx),
1161            Arc::new(Swan),
1162            Box::new(SpecialOnly {}),
1163        )
1164        .await
1165        .unwrap()
1166        .unwrap();
1167    }
1168
1169    #[test]
1170    fn invoke_poorly() {
1171        fn is_internal_invoke_err<T>(val: Result<T, InvokeError>) -> bool {
1172            matches!(val, Err(InvokeError::Bug(_)))
1173        }
1174
1175        // Make sure that our invoker function invocations return plausible bugs warnings on
1176        // misuse.
1177        let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1178        let discard = || Box::pin(futures::sink::drain().sink_err_into());
1179
1180        let table = DispatchTable::from_inventory();
1181        let (_swan, ent) = table.resolve_rpc_invoker(Arc::new(Swan), &GetKids).unwrap();
1182
1183        // Wrong method
1184        let bug = ent.invoke(
1185            Arc::new(Swan),
1186            Box::new(GetName),
1187            Arc::clone(&ctx),
1188            discard(),
1189        );
1190        assert!(is_internal_invoke_err(bug));
1191
1192        // Wrong object type
1193        let bug = ent.invoke(
1194            Arc::new(Wombat),
1195            Box::new(GetKids),
1196            Arc::clone(&ctx),
1197            discard(),
1198        );
1199        assert!(is_internal_invoke_err(bug));
1200
1201        // Special: Wrong method.
1202        let bug = ent.invoke_special(Arc::new(Swan), Box::new(GetName), Arc::clone(&ctx));
1203        assert!(is_internal_invoke_err(bug));
1204        // Special: Wrong object type
1205        let bug = ent.invoke_special(Arc::new(Wombat), Box::new(GetKids), Arc::clone(&ctx));
1206        assert!(is_internal_invoke_err(bug));
1207    }
1208
1209    #[test]
1210    fn invoker_ents() {
1211        let ent1 = invoker_ent!(@special specialonly_swan);
1212        let ent1b = invoker_ent!(@special specialonly_swan); // Same as 1, but different declaration.
1213        let ent2 = invoker_ent!(getname_generic::<String, String>);
1214        let ent2b = invoker_ent!(getname_generic::<String, String>);
1215
1216        assert_eq!(ent1.same_decl(&ent1), true);
1217        assert_eq!(ent1.same_decl(&ent1b), false);
1218        assert_eq!(ent1.same_decl(&ent2), false);
1219
1220        assert_eq!(ent2.same_decl(&ent2), true);
1221        assert_eq!(ent2.same_decl(&ent2b), false);
1222
1223        let re = regex::Regex::new(
1224            r#"^Invocable\(.*GetName \(x-test:getname\) for .*GenericObj.*String.*String"#,
1225        )
1226        .unwrap();
1227        let debug_fmt = format!("{:?}", &ent2);
1228        dbg!(&debug_fmt);
1229        assert!(re.is_match(&debug_fmt));
1230    }
1231
1232    #[test]
1233    fn redundant_invoker_ents() {
1234        let ent = invoker_ent!(getname_generic::<String, String>);
1235        let mut table = DispatchTable::from_inventory();
1236
1237        assert_eq!(ent.same_decl(&ent.clone()), true);
1238        table.insert(ent.clone());
1239        table.insert(ent);
1240    }
1241
1242    #[test]
1243    #[should_panic]
1244    fn conflicting_invoker_ents() {
1245        let ent = invoker_ent!(getname_generic::<String, String>);
1246        let ent2 = invoker_ent!(getname_generic::<String, String>);
1247        let mut table = DispatchTable::from_inventory();
1248        table.insert(ent);
1249        table.insert(ent2);
1250    }
1251}