/ crates / tor-rpcbase / src / dispatch.rs
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  
  50  use std::any;
  51  use std::collections::HashMap;
  52  use std::pin::Pin;
  53  use std::sync::Arc;
  54  
  55  use futures::future::BoxFuture;
  56  use futures::Sink;
  57  
  58  use tor_error::internal;
  59  use void::Void;
  60  
  61  #[cfg(feature = "describe-methods")]
  62  pub(crate) mod description;
  63  
  64  #[cfg(not(feature = "describe-methods"))]
  65  #[macro_export]
  66  #[doc(hidden)]
  67  macro_rules! register_delegation_note {
  68      { $from_type:ty, $to_type:ty } => {
  69      }
  70  }
  71  
  72  use crate::{Context, DynMethod, Object, RpcError, SendUpdateError};
  73  
  74  /// A type-erased serializable value.
  75  #[doc(hidden)]
  76  pub type RpcValue = Box<dyn erased_serde::Serialize + Send + 'static>;
  77  
  78  /// The return type from an RPC function.
  79  #[doc(hidden)]
  80  pub type RpcResult = Result<RpcValue, RpcError>;
  81  
  82  /// The return type from sending an update.
  83  #[doc(hidden)]
  84  pub type RpcSendResult = Result<RpcValue, SendUpdateError>;
  85  
  86  /// A boxed future holding the result of an RPC method.
  87  pub type RpcResultFuture = BoxFuture<'static, RpcResult>;
  88  
  89  /// A boxed sink on which updates can be sent.
  90  pub 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.
  98  pub 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.
 102  type 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.)
 111  pub 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.
 150  pub 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.
 169  macro_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  
 288  declare_invocable_impl! {}
 289  
 290  declare_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]
 310  pub 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  }
 336  impl 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]
 368  macro_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]
 411  macro_rules! invoker_ent_list {
 412      { $($(@$tag:ident)* $func:expr),* $(,)? } => {
 413          vec![
 414              $(
 415                  $crate::invoker_ent!($(@$tag)* $func)
 416              ),*
 417          ]
 418      }
 419  }
 420  
 421  impl 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  }
 426  inventory::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]
 510  macro_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]
 526  macro_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)]
 557  pub 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)]
 563  macro_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  } }
 569  impl_fn_type_of_fn_trait!();
 570  impl_fn_type_of_fn_trait!(A);
 571  impl_fn_type_of_fn_trait!(A B);
 572  impl_fn_type_of_fn_trait!(A B C);
 573  impl_fn_type_of_fn_trait!(A B C D);
 574  impl_fn_type_of_fn_trait!(A B C D E);
 575  impl_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)]
 589  pub 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)]
 595  struct 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)]
 609  pub 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  
 615  impl 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]
 734  pub 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  
 750  impl 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)]
 763  pub(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 register_weak(&self, _object: Arc<dyn crate::Object>) -> crate::ObjectId {
 925              todo!()
 926          }
 927  
 928          fn release_owned(&self, _object: &crate::ObjectId) -> Result<(), crate::LookupError> {
 929              todo!()
 930          }
 931  
 932          fn dispatch_table(&self) -> &Arc<RwLock<crate::DispatchTable>> {
 933              &self.table
 934          }
 935      }
 936  
 937      #[derive(Deftly, Clone)]
 938      #[derive_deftly(Object)]
 939      struct GenericObj<T, U>
 940      where
 941          T: Send + Sync + 'static + Clone + ToString,
 942          U: Send + Sync + 'static + Clone + ToString,
 943      {
 944          name: T,
 945          kids: U,
 946      }
 947  
 948      async fn getname_generic<T, U>(
 949          obj: Arc<GenericObj<T, U>>,
 950          _method: Box<GetName>,
 951          _ctx: Arc<dyn crate::Context>,
 952      ) -> Result<Outcome, crate::RpcError>
 953      where
 954          T: Send + Sync + 'static + Clone + ToString,
 955          U: Send + Sync + 'static + Clone + ToString,
 956      {
 957          Ok(Outcome {
 958              v: obj.name.to_string(),
 959          })
 960      }
 961      async fn getkids_generic<T, U>(
 962          obj: Arc<GenericObj<T, U>>,
 963          _method: Box<GetKids>,
 964          _ctx: Arc<dyn crate::Context>,
 965      ) -> Result<Outcome, crate::RpcError>
 966      where
 967          T: Send + Sync + 'static + Clone + ToString,
 968          U: Send + Sync + 'static + Clone + ToString,
 969      {
 970          Ok(Outcome {
 971              v: obj.kids.to_string(),
 972          })
 973      }
 974  
 975      // We can also install specific instantiations statically.
 976      static_rpc_invoke_fn! {
 977          getname_generic::<u32,u32>;
 978          getname_generic::<&'static str, &'static str>;
 979          getkids_generic::<u32,u32>;
 980          getkids_generic::<&'static str, &'static str>;
 981      }
 982  
 983      // And we can make code to install them dynamically too.
 984      impl<T, U> GenericObj<T, U>
 985      where
 986          T: Send + Sync + 'static + Clone + ToString,
 987          U: Send + Sync + 'static + Clone + ToString,
 988      {
 989          fn install_rpc_functions(table: &mut super::DispatchTable) {
 990              table.insert(invoker_ent!(getname_generic::<T, U>));
 991              table.insert(invoker_ent!(getkids_generic::<T, U>));
 992          }
 993      }
 994  
 995      // Define an object with delegation.
 996      #[derive(Clone, Deftly)]
 997      #[derive_deftly(Object)]
 998      #[deftly(rpc(
 999          delegate_with = "|this: &Self| this.contents.clone()",
1000          delegate_type = "dyn crate::Object"
1001      ))]
1002      struct CatCarrier {
1003          contents: Option<Arc<dyn crate::Object>>,
1004      }
1005  
1006      #[async_test]
1007      async fn try_invoke() {
1008          use super::*;
1009          fn invoke_helper<O: Object, M: Method>(
1010              ctx: &Arc<dyn Context>,
1011              obj: O,
1012              method: M,
1013          ) -> Result<RpcResultFuture, InvokeError> {
1014              let animal: Arc<dyn crate::Object> = Arc::new(obj);
1015              let request: Box<dyn DynMethod> = Box::new(method);
1016              let discard = Box::pin(futures::sink::drain().sink_err_into());
1017              crate::invoke_rpc_method(
1018                  Arc::clone(ctx),
1019                  &crate::ObjectId::from("AnimalIdent"),
1020                  animal,
1021                  request,
1022                  discard,
1023              )
1024          }
1025          async fn invoke_ok<O: crate::Object, M: crate::Method>(
1026              table: &Arc<dyn Context>,
1027              obj: O,
1028              method: M,
1029          ) -> String {
1030              let res = invoke_helper(table, obj, method).unwrap().await.unwrap();
1031              serde_json::to_string(&res).unwrap()
1032          }
1033          async fn sentence<O: crate::Object + Clone>(table: &Arc<dyn Context>, obj: O) -> String {
1034              format!(
1035                  "Hello I am a friendly {} and these are my lovely {}.",
1036                  invoke_ok(table, obj.clone(), GetName).await,
1037                  invoke_ok(table, obj, GetKids).await
1038              )
1039          }
1040  
1041          let table: Arc<dyn Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1042  
1043          assert_eq!(
1044              sentence(&table, Swan).await,
1045              r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1046          );
1047          assert_eq!(
1048              sentence(&table, Sheep).await,
1049              r#"Hello I am a friendly {"v":"sheep"} and these are my lovely {"v":"lambs"}."#
1050          );
1051          assert_eq!(
1052              sentence(&table, Wombat).await,
1053              r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1054          );
1055  
1056          assert!(matches!(
1057              invoke_helper(&table, Brick, GetKids),
1058              Err(InvokeError::NoImpl)
1059          ));
1060  
1061          /*
1062          install_generic_fns::<&'static str, &'static str>(&mut table);
1063          install_generic_fns::<u32, u32>(&mut table);
1064          */
1065          let obj1 = GenericObj {
1066              name: "nuncle",
1067              kids: "niblings",
1068          };
1069          let obj2 = GenericObj {
1070              name: 1337_u32,
1071              kids: 271828_u32,
1072          };
1073          assert_eq!(
1074              sentence(&table, obj1).await,
1075              r#"Hello I am a friendly {"v":"nuncle"} and these are my lovely {"v":"niblings"}."#
1076          );
1077          assert_eq!(
1078              sentence(&table, obj2).await,
1079              r#"Hello I am a friendly {"v":"1337"} and these are my lovely {"v":"271828"}."#
1080          );
1081  
1082          let obj3 = GenericObj {
1083              name: 13371337_u64,
1084              kids: 2718281828_u64,
1085          };
1086          assert!(matches!(
1087              invoke_helper(&table, obj3.clone(), GetKids),
1088              Err(InvokeError::NoImpl)
1089          ));
1090          {
1091              let mut tab = table.dispatch_table().write().unwrap();
1092              GenericObj::<u64, u64>::install_rpc_functions(&mut tab);
1093          }
1094          assert_eq!(
1095              sentence(&table, obj3).await,
1096              r#"Hello I am a friendly {"v":"13371337"} and these are my lovely {"v":"2718281828"}."#
1097          );
1098  
1099          // Try with delegation.
1100          let carrier_1 = CatCarrier {
1101              contents: Some(Arc::new(Wombat)),
1102          };
1103          let carrier_2 = CatCarrier {
1104              contents: Some(Arc::new(Swan)),
1105          };
1106          let carrier_3 = CatCarrier {
1107              contents: Some(Arc::new(Brick)),
1108          };
1109          let carrier_4 = CatCarrier { contents: None };
1110          assert_eq!(
1111              sentence(&table, carrier_1).await,
1112              r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1113          );
1114          assert_eq!(
1115              sentence(&table, carrier_2).await,
1116              r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1117          );
1118          assert!(matches!(
1119              invoke_helper(&table, carrier_3, GetKids),
1120              Err(InvokeError::NoImpl)
1121          ));
1122          assert!(matches!(
1123              invoke_helper(&table, carrier_4, GetKids),
1124              Err(InvokeError::NoImpl)
1125          ));
1126      }
1127  
1128      // Doesn't implement Deserialize.
1129      #[derive(Debug)]
1130      struct MyObject {}
1131  
1132      #[derive(Debug, Deftly)]
1133      #[derive_deftly(DynMethod)]
1134      #[deftly(rpc(no_method_name))]
1135      struct SpecialOnly {}
1136      impl Method for SpecialOnly {
1137          type Output = Result<MyObject, MyObject>; // Doesn't implement deserialize.
1138          type Update = crate::NoUpdates;
1139      }
1140  
1141      async fn specialonly_swan(
1142          _obj: Arc<Swan>,
1143          _method: Box<SpecialOnly>,
1144          _ctx: Arc<dyn crate::Context>,
1145      ) -> Result<MyObject, MyObject> {
1146          Ok(MyObject {})
1147      }
1148      static_rpc_invoke_fn! { @special specialonly_swan; }
1149  
1150      #[async_test]
1151      async fn try_invoke_special() {
1152          let table = crate::DispatchTable::from_inventory();
1153          let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(table));
1154  
1155          let res: Outcome =
1156              crate::invoke_special_method(Arc::clone(&ctx), Arc::new(Swan), Box::new(GetKids))
1157                  .await
1158                  .unwrap()
1159                  .unwrap();
1160  
1161          assert_eq!(res.v, "cygnets");
1162  
1163          let _an_obj: MyObject = crate::invoke_special_method(
1164              Arc::clone(&ctx),
1165              Arc::new(Swan),
1166              Box::new(SpecialOnly {}),
1167          )
1168          .await
1169          .unwrap()
1170          .unwrap();
1171      }
1172  
1173      #[test]
1174      fn invoke_poorly() {
1175          fn is_internal_invoke_err<T>(val: Result<T, InvokeError>) -> bool {
1176              matches!(val, Err(InvokeError::Bug(_)))
1177          }
1178  
1179          // Make sure that our invoker function invocations return plausible bugs warnings on
1180          // misuse.
1181          let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1182          let discard = || Box::pin(futures::sink::drain().sink_err_into());
1183  
1184          let table = DispatchTable::from_inventory();
1185          let (_swan, ent) = table.resolve_rpc_invoker(Arc::new(Swan), &GetKids).unwrap();
1186  
1187          // Wrong method
1188          let bug = ent.invoke(
1189              Arc::new(Swan),
1190              Box::new(GetName),
1191              Arc::clone(&ctx),
1192              discard(),
1193          );
1194          assert!(is_internal_invoke_err(bug));
1195  
1196          // Wrong object type
1197          let bug = ent.invoke(
1198              Arc::new(Wombat),
1199              Box::new(GetKids),
1200              Arc::clone(&ctx),
1201              discard(),
1202          );
1203          assert!(is_internal_invoke_err(bug));
1204  
1205          // Special: Wrong method.
1206          let bug = ent.invoke_special(Arc::new(Swan), Box::new(GetName), Arc::clone(&ctx));
1207          assert!(is_internal_invoke_err(bug));
1208          // Special: Wrong object type
1209          let bug = ent.invoke_special(Arc::new(Wombat), Box::new(GetKids), Arc::clone(&ctx));
1210          assert!(is_internal_invoke_err(bug));
1211      }
1212  
1213      #[test]
1214      fn invoker_ents() {
1215          let ent1 = invoker_ent!(@special specialonly_swan);
1216          let ent1b = invoker_ent!(@special specialonly_swan); // Same as 1, but different declaration.
1217          let ent2 = invoker_ent!(getname_generic::<String, String>);
1218          let ent2b = invoker_ent!(getname_generic::<String, String>);
1219  
1220          assert_eq!(ent1.same_decl(&ent1), true);
1221          assert_eq!(ent1.same_decl(&ent1b), false);
1222          assert_eq!(ent1.same_decl(&ent2), false);
1223  
1224          assert_eq!(ent2.same_decl(&ent2), true);
1225          assert_eq!(ent2.same_decl(&ent2b), false);
1226  
1227          let re = regex::Regex::new(
1228              r#"^Invocable\(.*GetName \(x-test:getname\) for .*GenericObj.*String.*String"#,
1229          )
1230          .unwrap();
1231          let debug_fmt = format!("{:?}", &ent2);
1232          dbg!(&debug_fmt);
1233          assert!(re.is_match(&debug_fmt));
1234      }
1235  
1236      #[test]
1237      fn redundant_invoker_ents() {
1238          let ent = invoker_ent!(getname_generic::<String, String>);
1239          let mut table = DispatchTable::from_inventory();
1240  
1241          assert_eq!(ent.same_decl(&ent.clone()), true);
1242          table.insert(ent.clone());
1243          table.insert(ent);
1244      }
1245  
1246      #[test]
1247      #[should_panic]
1248      fn conflicting_invoker_ents() {
1249          let ent = invoker_ent!(getname_generic::<String, String>);
1250          let ent2 = invoker_ent!(getname_generic::<String, String>);
1251          let mut table = DispatchTable::from_inventory();
1252          table.insert(ent);
1253          table.insert(ent2);
1254      }
1255  }