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
2
    fn describe_invocable(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122
2
        let (object_name, method_name) = self.object_and_method_type_names();
123
2
        let rpc_method_name = crate::method::method_info_by_typeid(self.method_type())
124
2
            .map(|mi| mi.method_name)
125
2
            .unwrap_or("???");
126
2
        write!(
127
2
            f,
128
2
            "Invocable({} ({}) for {})",
129
2
            method_name, rpc_method_name, object_name,
130
2
        )
131
2
    }
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
180
            fn object_type(&self) -> any::TypeId {
191
180
                any::TypeId::of::<OBJ>()
192
180
            }
193

            
194
182
            fn method_type(&self) -> any::TypeId {
195
182
                any::TypeId::of::<M>()
196
182
            }
197

            
198
2
            fn object_and_method_type_names(&self) -> (&'static str, &'static str) {
199
2
                (
200
2
                    any::type_name::<OBJ>(),
201
2
                    any::type_name::<M>(),
202
2
                )
203
2
            }
204

            
205
10
            fn invoke_special(
206
10
                &self,
207
10
                obj: Arc<dyn Object>,
208
10
                method: Box<dyn DynMethod>,
209
10
                ctx: Arc<dyn Context>,
210
10
            ) -> Result<SpecialResultFuture, $crate::InvokeError> {
211
                use futures::FutureExt;
212
                #[allow(unused)]
213
                use {tor_async_utils::SinkExt as _, futures::SinkExt as _};
214

            
215
10
                let Ok(obj) = obj.downcast_arc::<OBJ>() else {
216
2
                    return Err(InvokeError::Bug($crate::internal!("Wrong object type")));
217
                 };
218
8
                 let Ok(method) = method.downcast::<M>() else {
219
2
                     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
6
                 Ok(
227
6
                    (self)(obj, method, ctx $(, $sink )? )
228
6
                        .map(|r| Box::new(r) as Box<dyn any::Any>)
229
6
                        .boxed()
230
6
                 )
231
10
            }
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
38
            fn invoke(
249
38
                &self,
250
38
                obj: Arc<dyn Object>,
251
38
                method: Box<dyn DynMethod>,
252
38
                ctx: Arc<dyn Context>,
253
38
                #[allow(unused)]
254
38
                sink: BoxedUpdateSink,
255
38
            ) -> Result<RpcResultFuture, $crate::InvokeError> {
256
                use futures::FutureExt;
257
                #[allow(unused)]
258
                use tor_async_utils::SinkExt as _;
259
38
                let Ok(obj) = obj.downcast_arc::<OBJ>() else {
260
2
                   return Err(InvokeError::Bug($crate::internal!("Wrong object type")));
261
                };
262
36
                let Ok(method) = method.downcast::<M>() else {
263
2
                    return Err(InvokeError::Bug($crate::internal!("Wrong method type")));
264
                };
265
                $(
266
                #[allow(clippy::redundant_closure_call)]
267
4
                let $sink = {
268
4
                    ($sink_fn)(sink)
269
4
                };
270
4
                )?
271
4

            
272
30
                Ok(
273
30
                    (self)(obj, method, ctx $(, $sink)? )
274
34
                        .map(|r| {
275
34
                            let r: RpcResult = match r {
276
34
                                Ok(v) => Ok(Box::new(M::Output::from(v))),
277
                                Err(e) => Err(RpcError::from(e)),
278
                            };
279
34
                            r
280
34
                        })
281
34
                        .boxed()
282
34
                )
283
38
            }
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
4
    sink_fn: |sink:BoxedUpdateSink| Box::pin(
298
4
        sink.with_fn(|update: U| RpcSendResult::Ok(
299
4
            Box::new(M::Update::from(update))
300
4
        )
301
4
    ))
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
16
    fn same_decl(&self, other: &Self) -> bool {
346
16
        self.file == other.file && self.line == other.line && self.function == other.function
347
16
    }
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
2
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
423
2
        self.invoker.describe_invocable(f)
424
2
    }
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
14
    pub fn from_inventory() -> Self {
623
14
        // We want to assert that there are no duplicates, so we can't use "collect"
624
14
        let mut this = Self {
625
14
            map: HashMap::new(),
626
14
        };
627
168
        for ent in inventory::iter::<InvokerEnt>() {
628
168
            let old_val = this.insert_inner(*ent);
629
168
            if old_val.is_some() {
630
                panic!("Tried to insert duplicate entry for {:?}", ent);
631
168
            }
632
        }
633
14
        this
634
14
    }
635

            
636
    /// Add a new entry to this DispatchTable, and return the old value if any.
637
180
    fn insert_inner(&mut self, ent: InvokerEnt) -> Option<InvokerEnt> {
638
180
        self.map.insert(
639
180
            FuncType {
640
180
                obj_id: ent.invoker.object_type(),
641
180
                method_id: ent.invoker.method_type(),
642
180
            },
643
180
            ent,
644
180
        )
645
180
    }
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
12
    pub fn insert(&mut self, ent: InvokerEnt) {
654
12
        if let Some(old_ent) = self.insert_inner(ent) {
655
            // This is not a perfect check by any means; see `same_decl`.
656
4
            assert!(old_ent.same_decl(&ent));
657
8
        }
658
10
    }
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
50
    fn resolve_entry(
678
50
        &self,
679
50
        mut obj: Arc<dyn Object>,
680
50
        method_id: std::any::TypeId,
681
50
    ) -> Result<(Arc<dyn Object>, &InvokerEnt), InvokeError> {
682
        loop {
683
60
            let obj_id = {
684
60
                let dyn_obj: &dyn Object = obj.as_ref();
685
60
                dyn_obj.type_id()
686
60
            };
687
60
            let func_type = FuncType { obj_id, method_id };
688
60
            if let Some(ent) = self.map.get(&func_type) {
689
42
                return Ok((obj, ent));
690
18
            } else if let Some(delegation) = obj.delegate() {
691
10
                obj = delegation;
692
10
            } else {
693
8
                return Err(InvokeError::NoImpl);
694
            }
695
        }
696
50
    }
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
44
    pub(crate) fn resolve_rpc_invoker(
704
44
        &self,
705
44
        obj: Arc<dyn Object>,
706
44
        method: &dyn DynMethod,
707
44
    ) -> Result<(Arc<dyn Object>, &'static dyn RpcInvocable), InvokeError> {
708
44
        let (obj, invoker_ent) = self.resolve_entry(obj, method.type_id())?;
709
36
        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
36
        })?;
714
36
        Ok((obj, rpc_invoker))
715
44
    }
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
6
    pub(crate) fn resolve_special_invoker<M: crate::Method>(
723
6
        &self,
724
6
        obj: Arc<dyn Object>,
725
6
    ) -> Result<(Arc<dyn Object>, &'static dyn Invocable), InvokeError> {
726
6
        let (obj, invoker_ent) = self.resolve_entry(obj, std::any::TypeId::of::<M>())?;
727
6
        Ok((obj, invoker_ent.invoker))
728
6
    }
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 release_owned(&self, _object: &crate::ObjectId) -> Result<(), crate::LookupError> {
925
            todo!()
926
        }
927

            
928
        fn dispatch_table(&self) -> &Arc<RwLock<crate::DispatchTable>> {
929
            &self.table
930
        }
931
    }
932

            
933
    #[derive(Deftly, Clone)]
934
    #[derive_deftly(Object)]
935
    struct GenericObj<T, U>
936
    where
937
        T: Send + Sync + 'static + Clone + ToString,
938
        U: Send + Sync + 'static + Clone + ToString,
939
    {
940
        name: T,
941
        kids: U,
942
    }
943

            
944
    async fn getname_generic<T, U>(
945
        obj: Arc<GenericObj<T, U>>,
946
        _method: Box<GetName>,
947
        _ctx: Arc<dyn crate::Context>,
948
    ) -> Result<Outcome, crate::RpcError>
949
    where
950
        T: Send + Sync + 'static + Clone + ToString,
951
        U: Send + Sync + 'static + Clone + ToString,
952
    {
953
        Ok(Outcome {
954
            v: obj.name.to_string(),
955
        })
956
    }
957
    async fn getkids_generic<T, U>(
958
        obj: Arc<GenericObj<T, U>>,
959
        _method: Box<GetKids>,
960
        _ctx: Arc<dyn crate::Context>,
961
    ) -> Result<Outcome, crate::RpcError>
962
    where
963
        T: Send + Sync + 'static + Clone + ToString,
964
        U: Send + Sync + 'static + Clone + ToString,
965
    {
966
        Ok(Outcome {
967
            v: obj.kids.to_string(),
968
        })
969
    }
970

            
971
    // We can also install specific instantiations statically.
972
    static_rpc_invoke_fn! {
973
        getname_generic::<u32,u32>;
974
        getname_generic::<&'static str, &'static str>;
975
        getkids_generic::<u32,u32>;
976
        getkids_generic::<&'static str, &'static str>;
977
    }
978

            
979
    // And we can make code to install them dynamically too.
980
    impl<T, U> GenericObj<T, U>
981
    where
982
        T: Send + Sync + 'static + Clone + ToString,
983
        U: Send + Sync + 'static + Clone + ToString,
984
    {
985
        fn install_rpc_functions(table: &mut super::DispatchTable) {
986
            table.insert(invoker_ent!(getname_generic::<T, U>));
987
            table.insert(invoker_ent!(getkids_generic::<T, U>));
988
        }
989
    }
990

            
991
    // Define an object with delegation.
992
    #[derive(Clone, Deftly)]
993
    #[derive_deftly(Object)]
994
    #[deftly(rpc(
995
        delegate_with = "|this: &Self| this.contents.clone()",
996
        delegate_type = "dyn crate::Object"
997
    ))]
998
    struct CatCarrier {
999
        contents: Option<Arc<dyn crate::Object>>,
    }
    #[async_test]
    async fn try_invoke() {
        use super::*;
        fn invoke_helper<O: Object, M: Method>(
            ctx: &Arc<dyn Context>,
            obj: O,
            method: M,
        ) -> Result<RpcResultFuture, InvokeError> {
            let animal: Arc<dyn crate::Object> = Arc::new(obj);
            let request: Box<dyn DynMethod> = Box::new(method);
            let discard = Box::pin(futures::sink::drain().sink_err_into());
            crate::invoke_rpc_method(
                Arc::clone(ctx),
                &crate::ObjectId::from("AnimalIdent"),
                animal,
                request,
                discard,
            )
        }
        async fn invoke_ok<O: crate::Object, M: crate::Method>(
            table: &Arc<dyn Context>,
            obj: O,
            method: M,
        ) -> String {
            let res = invoke_helper(table, obj, method).unwrap().await.unwrap();
            serde_json::to_string(&res).unwrap()
        }
        async fn sentence<O: crate::Object + Clone>(table: &Arc<dyn Context>, obj: O) -> String {
            format!(
                "Hello I am a friendly {} and these are my lovely {}.",
                invoke_ok(table, obj.clone(), GetName).await,
                invoke_ok(table, obj, GetKids).await
            )
        }
        let table: Arc<dyn Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
        assert_eq!(
            sentence(&table, Swan).await,
            r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
        );
        assert_eq!(
            sentence(&table, Sheep).await,
            r#"Hello I am a friendly {"v":"sheep"} and these are my lovely {"v":"lambs"}."#
        );
        assert_eq!(
            sentence(&table, Wombat).await,
            r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
        );
        assert!(matches!(
            invoke_helper(&table, Brick, GetKids),
            Err(InvokeError::NoImpl)
        ));
        /*
        install_generic_fns::<&'static str, &'static str>(&mut table);
        install_generic_fns::<u32, u32>(&mut table);
        */
        let obj1 = GenericObj {
            name: "nuncle",
            kids: "niblings",
        };
        let obj2 = GenericObj {
            name: 1337_u32,
            kids: 271828_u32,
        };
        assert_eq!(
            sentence(&table, obj1).await,
            r#"Hello I am a friendly {"v":"nuncle"} and these are my lovely {"v":"niblings"}."#
        );
        assert_eq!(
            sentence(&table, obj2).await,
            r#"Hello I am a friendly {"v":"1337"} and these are my lovely {"v":"271828"}."#
        );
        let obj3 = GenericObj {
            name: 13371337_u64,
            kids: 2718281828_u64,
        };
        assert!(matches!(
            invoke_helper(&table, obj3.clone(), GetKids),
            Err(InvokeError::NoImpl)
        ));
        {
            let mut tab = table.dispatch_table().write().unwrap();
            GenericObj::<u64, u64>::install_rpc_functions(&mut tab);
        }
        assert_eq!(
            sentence(&table, obj3).await,
            r#"Hello I am a friendly {"v":"13371337"} and these are my lovely {"v":"2718281828"}."#
        );
        // Try with delegation.
        let carrier_1 = CatCarrier {
            contents: Some(Arc::new(Wombat)),
        };
        let carrier_2 = CatCarrier {
            contents: Some(Arc::new(Swan)),
        };
        let carrier_3 = CatCarrier {
            contents: Some(Arc::new(Brick)),
        };
        let carrier_4 = CatCarrier { contents: None };
        assert_eq!(
            sentence(&table, carrier_1).await,
            r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
        );
        assert_eq!(
            sentence(&table, carrier_2).await,
            r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
        );
        assert!(matches!(
            invoke_helper(&table, carrier_3, GetKids),
            Err(InvokeError::NoImpl)
        ));
        assert!(matches!(
            invoke_helper(&table, carrier_4, GetKids),
            Err(InvokeError::NoImpl)
        ));
    }
    // Doesn't implement Deserialize.
    #[derive(Debug)]
    struct MyObject {}
    #[derive(Debug, Deftly)]
    #[derive_deftly(DynMethod)]
    #[deftly(rpc(no_method_name))]
    struct SpecialOnly {}
    impl Method for SpecialOnly {
        type Output = Result<MyObject, MyObject>; // Doesn't implement deserialize.
        type Update = crate::NoUpdates;
    }
    async fn specialonly_swan(
        _obj: Arc<Swan>,
        _method: Box<SpecialOnly>,
        _ctx: Arc<dyn crate::Context>,
    ) -> Result<MyObject, MyObject> {
        Ok(MyObject {})
    }
    static_rpc_invoke_fn! { @special specialonly_swan; }
    #[async_test]
    async fn try_invoke_special() {
        let table = crate::DispatchTable::from_inventory();
        let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(table));
        let res: Outcome =
            crate::invoke_special_method(Arc::clone(&ctx), Arc::new(Swan), Box::new(GetKids))
                .await
                .unwrap()
                .unwrap();
        assert_eq!(res.v, "cygnets");
        let _an_obj: MyObject = crate::invoke_special_method(
            Arc::clone(&ctx),
            Arc::new(Swan),
            Box::new(SpecialOnly {}),
        )
        .await
        .unwrap()
        .unwrap();
    }
    #[test]
    fn invoke_poorly() {
        fn is_internal_invoke_err<T>(val: Result<T, InvokeError>) -> bool {
            matches!(val, Err(InvokeError::Bug(_)))
        }
        // Make sure that our invoker function invocations return plausible bugs warnings on
        // misuse.
        let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
        let discard = || Box::pin(futures::sink::drain().sink_err_into());
        let table = DispatchTable::from_inventory();
        let (_swan, ent) = table.resolve_rpc_invoker(Arc::new(Swan), &GetKids).unwrap();
        // Wrong method
        let bug = ent.invoke(
            Arc::new(Swan),
            Box::new(GetName),
            Arc::clone(&ctx),
            discard(),
        );
        assert!(is_internal_invoke_err(bug));
        // Wrong object type
        let bug = ent.invoke(
            Arc::new(Wombat),
            Box::new(GetKids),
            Arc::clone(&ctx),
            discard(),
        );
        assert!(is_internal_invoke_err(bug));
        // Special: Wrong method.
        let bug = ent.invoke_special(Arc::new(Swan), Box::new(GetName), Arc::clone(&ctx));
        assert!(is_internal_invoke_err(bug));
        // Special: Wrong object type
        let bug = ent.invoke_special(Arc::new(Wombat), Box::new(GetKids), Arc::clone(&ctx));
        assert!(is_internal_invoke_err(bug));
    }
    #[test]
    fn invoker_ents() {
        let ent1 = invoker_ent!(@special specialonly_swan);
        let ent1b = invoker_ent!(@special specialonly_swan); // Same as 1, but different declaration.
        let ent2 = invoker_ent!(getname_generic::<String, String>);
        let ent2b = invoker_ent!(getname_generic::<String, String>);
        assert_eq!(ent1.same_decl(&ent1), true);
        assert_eq!(ent1.same_decl(&ent1b), false);
        assert_eq!(ent1.same_decl(&ent2), false);
        assert_eq!(ent2.same_decl(&ent2), true);
        assert_eq!(ent2.same_decl(&ent2b), false);
        let re = regex::Regex::new(
            r#"^Invocable\(.*GetName \(x-test:getname\) for .*GenericObj.*String.*String"#,
        )
        .unwrap();
        let debug_fmt = format!("{:?}", &ent2);
        dbg!(&debug_fmt);
        assert!(re.is_match(&debug_fmt));
    }
    #[test]
    fn redundant_invoker_ents() {
        let ent = invoker_ent!(getname_generic::<String, String>);
        let mut table = DispatchTable::from_inventory();
        assert_eq!(ent.same_decl(&ent.clone()), true);
        table.insert(ent.clone());
        table.insert(ent);
    }
    #[test]
    #[should_panic]
    fn conflicting_invoker_ents() {
        let ent = invoker_ent!(getname_generic::<String, String>);
        let ent2 = invoker_ent!(getname_generic::<String, String>);
        let mut table = DispatchTable::from_inventory();
        table.insert(ent);
        table.insert(ent2);
    }
}