Macro tor_rpcbase::decl_object
source · macro_rules! decl_object { {$(@ $flag:ident)* $id:ident $( ; $($rest:tt)* )? } => { ... }; {$(@ $flag:ident)* $id:ident : [$($traitname:path),*] $( ; $($rest:tt)* )? } => { ... }; {$(@ $flag:ident)* $id:ident [$($param:ident),*] [$($wheres:tt)*] : [$($traitname:path),*] $( ; $($rest:tt)* )? } => { ... }; {@@extra_method expose} => { ... }; { } => { ... }; }
Expand description
Declare that one or more space-separated types should be considered as RPC objects.
This macro implements Object (and other necessary traits) for the
target type, and can be used to cause objects to participate in the trait
downcasting system.
You can provide multiple objects in one invocation of this macro;
just separate them with a semicolon (;).
Examples
Simple case, just implements Object.
use tor_rpcbase as rpc;
#[derive(Default)]
struct Houseplant {
oxygen_per_sec: f64,
benign_neglect: u8
}
rpc::decl_object!{Houseplant}
// You can downcast an Object to a concrete type.
use downcast_rs::DowncastSync;
use std::sync::Arc;
let plant_obj: Arc<dyn rpc::Object> = Arc::new(Houseplant::default());
let as_plant: Arc<Houseplant> = plant_obj.downcast_arc().ok().unwrap();With trait downcasting
By default, you can use downcast_rs to downcast a dyn Object to its
concrete type. If you also need to be able to downcast a dyn Object to a given
trait that it implements, you can use this syntax for decl_object to have
it participate in trait downcasting:
use tor_rpcbase as rpc;
struct Frobnitz {}
trait Gizmo {}
trait Doodad {}
impl Gizmo for Frobnitz {}
impl Doodad for Frobnitz {}
rpc::decl_object!{Frobnitz: [Gizmo, Doodad]}
use std::sync::Arc;
use rpc::ObjectRefExt; // for the cast_to method.
let frob_obj: Arc<dyn rpc::Object> = Arc::new(Frobnitz {});
let gizmo: &dyn Gizmo = frob_obj.cast_to_trait().unwrap();
let doodad: &dyn Doodad = frob_obj.cast_to_trait().unwrap();With generic objects
Right now, a generic object can’t participate in our method lookup system, but it can participate in trait downcasting. We’ll try to remove this limitation in the future.
The current syntax is pretty ugly; we may try to improve it in the future.
use tor_rpcbase as rpc;
struct Generic<T,U> where T:Clone, U:PartialEq {
t: T,
u: U,
}
trait ExampleTrait {}
impl<T:Clone,U:PartialEq> ExampleTrait for Generic<T,U> {}
rpc::decl_object!{
Generic
// First, list the generic parameters.
[T,U]
// Then give the contents of the where clause.
// They will need to be `Send + Sync + 'static` or else you
// won't be able to implement `Object`.
[ T:Clone + Send + Sync + 'static,
U:PartialEq + Send + Sync + 'static]
// Finally, list the traits you want to downcast into.
: [ExampleTrait]
}
use std::sync::Arc;
use rpc::ObjectRefExt; // for the cast_to method.
let obj: Arc<dyn rpc::Object> = Arc::new(Generic { t: 42_u8, u: 42_u8 });
let tr: &dyn ExampleTrait = obj.cast_to_trait().unwrap();Making an object “exposed outside of the session”
You flag any kind of Object so that its identifiers will be exported
outside of the local RPC session. (Arti uses this for Objects whose
ObjectId needs to be used as a SOCKS identifier.) To do so,
add @expose before the object’s name:
use tor_rpcbase as rpc;
struct Visible {}
rpc::decl_object!{@expose Visible}