Skip to main content

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::Sink;
56use futures::future::BoxFuture;
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    /// The object could not be found.
741    //
742    // (We violate our usual rule against duplicating Display implementations here,
743    // since the RPC code will report this string verbatim.)
744    #[error("Target object did not exist: {0}")]
745    NoObject(crate::LookupError),
746
747    /// Tried to call `invoke_without_dispatch` on an RPC method that _does_ support
748    /// regular RPC method dispatch.
749    #[error("Called invoke_without_dispatch on a regular RPC method")]
750    NoDispatchBypass,
751
752    /// An internal problem occurred while invoking a method.
753    #[error("Internal error")]
754    Bug(#[from] tor_error::Bug),
755}
756
757impl From<InvokeError> for RpcError {
758    fn from(err: InvokeError) -> Self {
759        use crate::RpcErrorKind as EK;
760        let kind = match &err {
761            InvokeError::NoImpl => EK::MethodNotImpl,
762            InvokeError::NoObject(e) => e.rpc_error_kind(),
763            InvokeError::NoDispatchBypass => EK::InternalError,
764            InvokeError::Bug(_) => EK::InternalError,
765        };
766        RpcError::new(err.to_string(), kind)
767    }
768}
769
770#[cfg(test)]
771pub(crate) mod test {
772    // @@ begin test lint list maintained by maint/add_warning @@
773    #![allow(clippy::bool_assert_comparison)]
774    #![allow(clippy::clone_on_copy)]
775    #![allow(clippy::dbg_macro)]
776    #![allow(clippy::mixed_attributes_style)]
777    #![allow(clippy::print_stderr)]
778    #![allow(clippy::print_stdout)]
779    #![allow(clippy::single_char_pattern)]
780    #![allow(clippy::unwrap_used)]
781    #![allow(clippy::unchecked_time_subtraction)]
782    #![allow(clippy::useless_vec)]
783    #![allow(clippy::needless_pass_by_value)]
784    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
785
786    use crate::{DispatchTable, InvokeError, Method, NoUpdates, method::RpcMethod, templates::*};
787    use derive_deftly::Deftly;
788    use futures::SinkExt;
789    use futures_await_test::async_test;
790    use std::{
791        collections::HashMap,
792        sync::{Arc, Mutex, RwLock},
793    };
794
795    use super::UpdateSink;
796
797    // Define 3 animals and one brick.
798    #[derive(Clone, Deftly)]
799    #[derive_deftly(Object)]
800    pub(crate) struct Swan;
801    #[derive(Clone, Deftly)]
802    #[derive_deftly(Object)]
803    pub(crate) struct Wombat;
804    #[derive(Clone, Deftly)]
805    #[derive_deftly(Object)]
806    pub(crate) struct Sheep;
807    #[derive(Clone, Deftly)]
808    #[derive_deftly(Object)]
809    pub(crate) struct Brick;
810
811    // Define 2 methods.
812    #[derive(Debug, serde::Deserialize, Deftly)]
813    #[derive_deftly(DynMethod)]
814    #[deftly(rpc(method_name = "x-test:getname"))]
815    pub(crate) struct GetName;
816
817    #[derive(Debug, serde::Deserialize, Deftly)]
818    #[derive_deftly(DynMethod)]
819    #[deftly(rpc(method_name = "x-test:getkids"))]
820    pub(crate) struct GetKids;
821
822    impl RpcMethod for GetName {
823        type Output = Outcome;
824        type Update = NoUpdates;
825    }
826    impl RpcMethod for GetKids {
827        type Output = Outcome;
828        type Update = String;
829    }
830
831    #[derive(serde::Serialize)]
832    pub(crate) struct Outcome {
833        pub(crate) v: String,
834    }
835
836    async fn getname_swan(
837        _obj: Arc<Swan>,
838        _method: Box<GetName>,
839        _ctx: Arc<dyn crate::Context>,
840    ) -> Result<Outcome, crate::RpcError> {
841        Ok(Outcome {
842            v: "swan".to_string(),
843        })
844    }
845    async fn getname_sheep(
846        _obj: Arc<Sheep>,
847        _method: Box<GetName>,
848        _ctx: Arc<dyn crate::Context>,
849    ) -> Result<Outcome, crate::RpcError> {
850        Ok(Outcome {
851            v: "sheep".to_string(),
852        })
853    }
854    async fn getname_wombat(
855        _obj: Arc<Wombat>,
856        _method: Box<GetName>,
857        _ctx: Arc<dyn crate::Context>,
858    ) -> Result<Outcome, crate::RpcError> {
859        Ok(Outcome {
860            v: "wombat".to_string(),
861        })
862    }
863    async fn getname_brick(
864        _obj: Arc<Brick>,
865        _method: Box<GetName>,
866        _ctx: Arc<dyn crate::Context>,
867    ) -> Result<Outcome, crate::RpcError> {
868        Ok(Outcome {
869            v: "brick".to_string(),
870        })
871    }
872    async fn getkids_swan(
873        _obj: Arc<Swan>,
874        _method: Box<GetKids>,
875        _ctx: Arc<dyn crate::Context>,
876    ) -> Result<Outcome, crate::RpcError> {
877        Ok(Outcome {
878            v: "cygnets".to_string(),
879        })
880    }
881    async fn getkids_sheep(
882        _obj: Arc<Sheep>,
883        _method: Box<GetKids>,
884        _ctx: Arc<dyn crate::Context>,
885    ) -> Result<Outcome, crate::RpcError> {
886        Ok(Outcome {
887            v: "lambs".to_string(),
888        })
889    }
890    async fn getkids_wombat(
891        _obj: Arc<Wombat>,
892        _method: Box<GetKids>,
893        _ctx: Arc<dyn crate::Context>,
894        mut sink: UpdateSink<String>,
895    ) -> Result<Outcome, crate::RpcError> {
896        let _ignore = sink.send("brb, burrowing".to_string()).await;
897        Ok(Outcome {
898            v: "joeys".to_string(),
899        })
900    }
901
902    static_rpc_invoke_fn! {
903        getname_swan;
904        getname_sheep;
905        getname_wombat;
906        getname_brick;
907
908        getkids_swan;
909        getkids_sheep;
910        getkids_wombat;
911    }
912
913    pub(crate) struct Ctx {
914        table: Arc<RwLock<DispatchTable>>,
915        map: Arc<Mutex<HashMap<crate::ObjectId, Arc<dyn crate::Object>>>>,
916        next_id: Arc<Mutex<u32>>,
917    }
918    impl From<DispatchTable> for Ctx {
919        fn from(table: DispatchTable) -> Self {
920            Self {
921                table: Arc::new(RwLock::new(table)),
922                map: Arc::new(Mutex::new(HashMap::new())),
923                next_id: Arc::new(Mutex::new(1)),
924            }
925        }
926    }
927
928    impl crate::Context for Ctx {
929        fn lookup_object(
930            &self,
931            id: &crate::ObjectId,
932        ) -> Result<std::sync::Arc<dyn crate::Object>, crate::LookupError> {
933            self.map
934                .lock()
935                .unwrap()
936                .get(id)
937                .cloned()
938                .ok_or_else(|| crate::LookupError::NoObject(id.clone()))
939        }
940        fn register_owned(&self, object: Arc<dyn crate::Object>) -> crate::ObjectId {
941            let mut id_guard = self.next_id.lock().unwrap();
942            let id = *id_guard;
943            *id_guard += 1;
944
945            let id = crate::ObjectId::from(id.to_string());
946            self.map.lock().unwrap().insert(id.clone(), object);
947            id
948        }
949
950        fn register_weak(&self, _object: &Arc<dyn crate::Object>) -> crate::ObjectId {
951            todo!()
952        }
953
954        fn release(&self, _object: &crate::ObjectId) -> Result<(), crate::LookupError> {
955            todo!()
956        }
957
958        fn dispatch_table(&self) -> &Arc<RwLock<crate::DispatchTable>> {
959            &self.table
960        }
961    }
962
963    #[derive(Deftly, Clone)]
964    #[derive_deftly(Object)]
965    struct GenericObj<T, U>
966    where
967        T: Send + Sync + 'static + Clone + ToString,
968        U: Send + Sync + 'static + Clone + ToString,
969    {
970        name: T,
971        kids: U,
972    }
973
974    async fn getname_generic<T, U>(
975        obj: Arc<GenericObj<T, U>>,
976        _method: Box<GetName>,
977        _ctx: Arc<dyn crate::Context>,
978    ) -> Result<Outcome, crate::RpcError>
979    where
980        T: Send + Sync + 'static + Clone + ToString,
981        U: Send + Sync + 'static + Clone + ToString,
982    {
983        Ok(Outcome {
984            v: obj.name.to_string(),
985        })
986    }
987    async fn getkids_generic<T, U>(
988        obj: Arc<GenericObj<T, U>>,
989        _method: Box<GetKids>,
990        _ctx: Arc<dyn crate::Context>,
991    ) -> Result<Outcome, crate::RpcError>
992    where
993        T: Send + Sync + 'static + Clone + ToString,
994        U: Send + Sync + 'static + Clone + ToString,
995    {
996        Ok(Outcome {
997            v: obj.kids.to_string(),
998        })
999    }
1000
1001    // We can also install specific instantiations statically.
1002    static_rpc_invoke_fn! {
1003        getname_generic::<u32,u32>;
1004        getname_generic::<&'static str, &'static str>;
1005        getkids_generic::<u32,u32>;
1006        getkids_generic::<&'static str, &'static str>;
1007    }
1008
1009    // And we can make code to install them dynamically too.
1010    impl<T, U> GenericObj<T, U>
1011    where
1012        T: Send + Sync + 'static + Clone + ToString,
1013        U: Send + Sync + 'static + Clone + ToString,
1014    {
1015        fn install_rpc_functions(table: &mut super::DispatchTable) {
1016            table.insert(invoker_ent!(getname_generic::<T, U>));
1017            table.insert(invoker_ent!(getkids_generic::<T, U>));
1018        }
1019    }
1020
1021    // Define an object with delegation.
1022    #[derive(Clone, Deftly)]
1023    #[derive_deftly(Object)]
1024    #[deftly(rpc(
1025        delegate_with = "|this: &Self| this.contents.clone()",
1026        delegate_type = "dyn crate::Object"
1027    ))]
1028    struct CatCarrier {
1029        contents: Option<Arc<dyn crate::Object>>,
1030    }
1031
1032    #[async_test]
1033    async fn try_invoke() {
1034        use super::*;
1035        fn invoke_helper<O: Object, M: Method>(
1036            ctx: &Arc<dyn Context>,
1037            obj: O,
1038            method: M,
1039        ) -> Result<RpcResultFuture, InvokeError> {
1040            let animal: Arc<dyn crate::Object> = Arc::new(obj);
1041            let request: Box<dyn DynMethod> = Box::new(method);
1042            let discard = Box::pin(futures::sink::drain().sink_err_into());
1043            let id = ctx.register_owned(animal);
1044            crate::invoke_rpc_method(Arc::clone(ctx), &id, request, discard)
1045        }
1046        async fn invoke_ok<O: crate::Object, M: crate::Method>(
1047            table: &Arc<dyn Context>,
1048            obj: O,
1049            method: M,
1050        ) -> String {
1051            let res = invoke_helper(table, obj, method).unwrap().await.unwrap();
1052            serde_json::to_string(&res).unwrap()
1053        }
1054        async fn sentence<O: crate::Object + Clone>(table: &Arc<dyn Context>, obj: O) -> String {
1055            format!(
1056                "Hello I am a friendly {} and these are my lovely {}.",
1057                invoke_ok(table, obj.clone(), GetName).await,
1058                invoke_ok(table, obj, GetKids).await
1059            )
1060        }
1061
1062        let table: Arc<dyn Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1063
1064        assert_eq!(
1065            sentence(&table, Swan).await,
1066            r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1067        );
1068        assert_eq!(
1069            sentence(&table, Sheep).await,
1070            r#"Hello I am a friendly {"v":"sheep"} and these are my lovely {"v":"lambs"}."#
1071        );
1072        assert_eq!(
1073            sentence(&table, Wombat).await,
1074            r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1075        );
1076
1077        assert!(matches!(
1078            invoke_helper(&table, Brick, GetKids),
1079            Err(InvokeError::NoImpl)
1080        ));
1081
1082        /*
1083        install_generic_fns::<&'static str, &'static str>(&mut table);
1084        install_generic_fns::<u32, u32>(&mut table);
1085        */
1086        let obj1 = GenericObj {
1087            name: "nuncle",
1088            kids: "niblings",
1089        };
1090        let obj2 = GenericObj {
1091            name: 1337_u32,
1092            kids: 271828_u32,
1093        };
1094        assert_eq!(
1095            sentence(&table, obj1).await,
1096            r#"Hello I am a friendly {"v":"nuncle"} and these are my lovely {"v":"niblings"}."#
1097        );
1098        assert_eq!(
1099            sentence(&table, obj2).await,
1100            r#"Hello I am a friendly {"v":"1337"} and these are my lovely {"v":"271828"}."#
1101        );
1102
1103        let obj3 = GenericObj {
1104            name: 13371337_u64,
1105            kids: 2718281828_u64,
1106        };
1107        assert!(matches!(
1108            invoke_helper(&table, obj3.clone(), GetKids),
1109            Err(InvokeError::NoImpl)
1110        ));
1111        {
1112            let mut tab = table.dispatch_table().write().unwrap();
1113            GenericObj::<u64, u64>::install_rpc_functions(&mut tab);
1114        }
1115        assert_eq!(
1116            sentence(&table, obj3).await,
1117            r#"Hello I am a friendly {"v":"13371337"} and these are my lovely {"v":"2718281828"}."#
1118        );
1119
1120        // Try with delegation.
1121        let carrier_1 = CatCarrier {
1122            contents: Some(Arc::new(Wombat)),
1123        };
1124        let carrier_2 = CatCarrier {
1125            contents: Some(Arc::new(Swan)),
1126        };
1127        let carrier_3 = CatCarrier {
1128            contents: Some(Arc::new(Brick)),
1129        };
1130        let carrier_4 = CatCarrier { contents: None };
1131        assert_eq!(
1132            sentence(&table, carrier_1).await,
1133            r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1134        );
1135        assert_eq!(
1136            sentence(&table, carrier_2).await,
1137            r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1138        );
1139        assert!(matches!(
1140            invoke_helper(&table, carrier_3, GetKids),
1141            Err(InvokeError::NoImpl)
1142        ));
1143        assert!(matches!(
1144            invoke_helper(&table, carrier_4, GetKids),
1145            Err(InvokeError::NoImpl)
1146        ));
1147    }
1148
1149    // Doesn't implement Deserialize.
1150    #[derive(Debug)]
1151    struct MyObject {}
1152
1153    #[derive(Debug, Deftly)]
1154    #[derive_deftly(DynMethod)]
1155    #[deftly(rpc(no_method_name))]
1156    struct SpecialOnly {}
1157    impl Method for SpecialOnly {
1158        type Output = Result<MyObject, MyObject>; // Doesn't implement deserialize.
1159        type Update = crate::NoUpdates;
1160    }
1161
1162    async fn specialonly_swan(
1163        _obj: Arc<Swan>,
1164        _method: Box<SpecialOnly>,
1165        _ctx: Arc<dyn crate::Context>,
1166    ) -> Result<MyObject, MyObject> {
1167        Ok(MyObject {})
1168    }
1169    static_rpc_invoke_fn! { @special specialonly_swan; }
1170
1171    #[async_test]
1172    async fn try_invoke_special() {
1173        let table = crate::DispatchTable::from_inventory();
1174        let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(table));
1175
1176        let res: Outcome =
1177            crate::invoke_special_method(Arc::clone(&ctx), Arc::new(Swan), Box::new(GetKids))
1178                .await
1179                .unwrap()
1180                .unwrap();
1181
1182        assert_eq!(res.v, "cygnets");
1183
1184        let _an_obj: MyObject = crate::invoke_special_method(
1185            Arc::clone(&ctx),
1186            Arc::new(Swan),
1187            Box::new(SpecialOnly {}),
1188        )
1189        .await
1190        .unwrap()
1191        .unwrap();
1192    }
1193
1194    #[test]
1195    fn invoke_poorly() {
1196        fn is_internal_invoke_err<T>(val: Result<T, InvokeError>) -> bool {
1197            matches!(val, Err(InvokeError::Bug(_)))
1198        }
1199
1200        // Make sure that our invoker function invocations return plausible bugs warnings on
1201        // misuse.
1202        let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1203        let discard = || Box::pin(futures::sink::drain().sink_err_into());
1204
1205        let table = DispatchTable::from_inventory();
1206        let (_swan, ent) = table.resolve_rpc_invoker(Arc::new(Swan), &GetKids).unwrap();
1207
1208        // Wrong method
1209        let bug = ent.invoke(
1210            Arc::new(Swan),
1211            Box::new(GetName),
1212            Arc::clone(&ctx),
1213            discard(),
1214        );
1215        assert!(is_internal_invoke_err(bug));
1216
1217        // Wrong object type
1218        let bug = ent.invoke(
1219            Arc::new(Wombat),
1220            Box::new(GetKids),
1221            Arc::clone(&ctx),
1222            discard(),
1223        );
1224        assert!(is_internal_invoke_err(bug));
1225
1226        // Special: Wrong method.
1227        let bug = ent.invoke_special(Arc::new(Swan), Box::new(GetName), Arc::clone(&ctx));
1228        assert!(is_internal_invoke_err(bug));
1229        // Special: Wrong object type
1230        let bug = ent.invoke_special(Arc::new(Wombat), Box::new(GetKids), Arc::clone(&ctx));
1231        assert!(is_internal_invoke_err(bug));
1232    }
1233
1234    #[test]
1235    fn invoker_ents() {
1236        let ent1 = invoker_ent!(@special specialonly_swan);
1237        let ent1b = invoker_ent!(@special specialonly_swan); // Same as 1, but different declaration.
1238        let ent2 = invoker_ent!(getname_generic::<String, String>);
1239        let ent2b = invoker_ent!(getname_generic::<String, String>);
1240
1241        assert_eq!(ent1.same_decl(&ent1), true);
1242        assert_eq!(ent1.same_decl(&ent1b), false);
1243        assert_eq!(ent1.same_decl(&ent2), false);
1244
1245        assert_eq!(ent2.same_decl(&ent2), true);
1246        assert_eq!(ent2.same_decl(&ent2b), false);
1247
1248        let re = regex::Regex::new(
1249            r#"^Invocable\(.*GetName \(x-test:getname\) for .*GenericObj.*String.*String"#,
1250        )
1251        .unwrap();
1252        let debug_fmt = format!("{:?}", &ent2);
1253        dbg!(&debug_fmt);
1254        assert!(re.is_match(&debug_fmt));
1255    }
1256
1257    #[test]
1258    fn redundant_invoker_ents() {
1259        let ent = invoker_ent!(getname_generic::<String, String>);
1260        let mut table = DispatchTable::from_inventory();
1261
1262        assert_eq!(ent.same_decl(&ent.clone()), true);
1263        table.insert(ent.clone());
1264        table.insert(ent);
1265    }
1266
1267    #[test]
1268    #[should_panic]
1269    fn conflicting_invoker_ents() {
1270        let ent = invoker_ent!(getname_generic::<String, String>);
1271        let ent2 = invoker_ent!(getname_generic::<String, String>);
1272        let mut table = DispatchTable::from_inventory();
1273        table.insert(ent);
1274        table.insert(ent2);
1275    }
1276}