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 }