1use std::any;
51use std::collections::HashMap;
52use std::pin::Pin;
53use std::sync::Arc;
54
55use futures::Sink;
56use futures::future::BoxFuture;
57
58use tor_error::internal;
59use void::Void;
60
61#[cfg(feature = "describe-methods")]
62pub(crate) mod description;
63
64#[cfg(not(feature = "describe-methods"))]
65#[macro_export]
66#[doc(hidden)]
67macro_rules! register_delegation_note {
68 { $from_type:ty, $to_type:ty } => {
69 }
70}
71
72use crate::{Context, DynMethod, Object, RpcError, SendUpdateError};
73
74#[doc(hidden)]
76pub type RpcValue = Box<dyn erased_serde::Serialize + Send + 'static>;
77
78#[doc(hidden)]
80pub type RpcResult = Result<RpcValue, RpcError>;
81
82#[doc(hidden)]
84pub type RpcSendResult = Result<RpcValue, SendUpdateError>;
85
86pub type RpcResultFuture = BoxFuture<'static, RpcResult>;
88
89pub type BoxedUpdateSink = Pin<Box<dyn Sink<RpcValue, Error = SendUpdateError> + Send>>;
91
92pub type UpdateSink<U> = Pin<Box<dyn Sink<U, Error = SendUpdateError> + Send + 'static>>;
99
100type SpecialResultFuture = BoxFuture<'static, Box<dyn any::Any>>;
103
104pub trait Invocable: Send + Sync + 'static {
112 fn object_type(&self) -> any::TypeId;
114 fn method_type(&self) -> any::TypeId;
116 fn object_and_method_type_names(&self) -> (&'static str, &'static str);
120 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 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
149pub trait RpcInvocable: Invocable {
151 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
164macro_rules! declare_invocable_impl {
170 {
171 $( update_gen: $update_gen:ident,
174 update_arg: { $sink:ident: $update_arg:ty } ,
175 update_arg_where: { $($update_arg_where:tt)+ } ,
176 sink_fn: $sink_fn:expr
177 )?
178 } => {
179 impl<M, OBJ, Fut, S, E, $($update_gen)?> Invocable
180 for fn(Arc<OBJ>, Box<M>, Arc<dyn Context + 'static> $(, $update_arg )? ) -> Fut
181 where
182 M: crate::Method,
183 OBJ: Object,
184 S: 'static,
185 E: 'static,
186 Fut: futures::Future<Output = Result<S,E>> + Send + 'static,
187 $( M::Update: From<$update_gen>, )?
188 $( $($update_arg_where)+ )?
189 {
190 fn object_type(&self) -> any::TypeId {
191 any::TypeId::of::<OBJ>()
192 }
193
194 fn method_type(&self) -> any::TypeId {
195 any::TypeId::of::<M>()
196 }
197
198 fn object_and_method_type_names(&self) -> (&'static str, &'static str) {
199 (
200 any::type_name::<OBJ>(),
201 any::type_name::<M>(),
202 )
203 }
204
205 fn invoke_special(
206 &self,
207 obj: Arc<dyn Object>,
208 method: Box<dyn DynMethod>,
209 ctx: Arc<dyn Context>,
210 ) -> Result<SpecialResultFuture, $crate::InvokeError> {
211 use futures::FutureExt;
212 #[allow(unused)]
213 use {tor_async_utils::SinkExt as _, futures::SinkExt as _};
214
215 let Ok(obj) = obj.downcast_arc::<OBJ>() else {
216 return Err(InvokeError::Bug($crate::internal!("Wrong object type")));
217 };
218 let Ok(method) = method.downcast::<M>() else {
219 return Err(InvokeError::Bug($crate::internal!("Wrong method type")));
220 };
221
222 $(
223 let $sink = Box::pin(futures::sink::drain().sink_err_into());
224 )?
225
226 Ok(
227 (self)(obj, method, ctx $(, $sink )? )
228 .map(|r| Box::new(r) as Box<dyn any::Any>)
229 .boxed()
230 )
231 }
232 }
233
234 impl<M, OBJ, Fut, S, E, $($update_gen)?> RpcInvocable
235 for fn(Arc<OBJ>, Box<M>, Arc<dyn Context + 'static> $(, $update_arg )? ) -> Fut
236 where
237 M: crate::RpcMethod,
238 M::Output: serde::Serialize,
239 S: 'static,
240 E: 'static,
241 OBJ: Object,
242 Fut: futures::Future<Output = Result<S, E>> + Send + 'static,
243 M::Output: From<S>,
244 RpcError: From<E>,
245 $( M::Update: From<$update_gen>, )?
246 $( $($update_arg_where)+ )?
247 {
248 fn invoke(
249 &self,
250 obj: Arc<dyn Object>,
251 method: Box<dyn DynMethod>,
252 ctx: Arc<dyn Context>,
253 #[allow(unused)]
254 sink: BoxedUpdateSink,
255 ) -> Result<RpcResultFuture, $crate::InvokeError> {
256 use futures::FutureExt;
257 #[allow(unused)]
258 use tor_async_utils::SinkExt as _;
259 let Ok(obj) = obj.downcast_arc::<OBJ>() else {
260 return Err(InvokeError::Bug($crate::internal!("Wrong object type")));
261 };
262 let Ok(method) = method.downcast::<M>() else {
263 return Err(InvokeError::Bug($crate::internal!("Wrong method type")));
264 };
265 $(
266 #[allow(clippy::redundant_closure_call)]
267 let $sink = {
268 ($sink_fn)(sink)
269 };
270 )?
271
272 Ok(
273 (self)(obj, method, ctx $(, $sink)? )
274 .map(|r| {
275 let r: RpcResult = match r {
276 Ok(v) => Ok(Box::new(M::Output::from(v))),
277 Err(e) => Err(RpcError::from(e)),
278 };
279 r
280 })
281 .boxed()
282 )
283 }
284 }
285 }
286}
287
288declare_invocable_impl! {}
289
290declare_invocable_impl! {
291 update_gen: U,
292 update_arg: { sink: UpdateSink<U> },
293 update_arg_where: {
294 U: 'static + Send,
295 M::Update: serde::Serialize
296 },
297 sink_fn: |sink:BoxedUpdateSink| Box::pin(
298 sink.with_fn(|update: U| RpcSendResult::Ok(
299 Box::new(M::Update::from(update))
300 )
301 ))
302}
303
304#[allow(clippy::exhaustive_structs)]
308#[derive(Clone, Copy)]
309#[must_use]
310pub struct InvokerEnt {
311 #[doc(hidden)]
315 pub invoker: &'static dyn Invocable,
316
317 #[doc(hidden)]
323 pub rpc_invoker: Option<&'static dyn RpcInvocable>,
324
325 #[doc(hidden)]
330 pub file: &'static str,
331 #[doc(hidden)]
332 pub line: u32,
333 #[doc(hidden)]
334 pub function: &'static str,
335}
336impl InvokerEnt {
337 fn same_decl(&self, other: &Self) -> bool {
346 self.file == other.file && self.line == other.line && self.function == other.function
347 }
348}
349
350#[macro_export]
368macro_rules! invoker_ent {
369 { $func:expr } => {
370 $crate::invoker_ent!{ @@impl
371 func: ($func),
372 rpc_invoker:
373 (Some($crate::invocable_func_as_dyn_invocable!($func, $crate::dispatch::RpcInvocable))),
374 }
375 };
376 { @special $func:expr } => {
377 $crate::invoker_ent!{ @@impl
378 func: ($func),
379 rpc_invoker: (None),
380 }
381 };
382 { @@impl
383 func: ($func:expr),
384 rpc_invoker: ($rpc_invoker:expr),
385 } => {
386 $crate::dispatch::InvokerEnt {
387 invoker: $crate::invocable_func_as_dyn_invocable!($func, $crate::dispatch::Invocable),
388 rpc_invoker: $rpc_invoker,
389 file: file!(),
390 line: line!(),
391 function: stringify!($func)
392 }
393 };
394}
395
396#[macro_export]
411macro_rules! invoker_ent_list {
412 { $($(@$tag:ident)* $func:expr),* $(,)? } => {
413 vec![
414 $(
415 $crate::invoker_ent!($(@$tag)* $func)
416 ),*
417 ]
418 }
419}
420
421impl std::fmt::Debug for InvokerEnt {
422 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
423 self.invoker.describe_invocable(f)
424 }
425}
426inventory::collect!(InvokerEnt);
427
428#[macro_export]
510macro_rules! static_rpc_invoke_fn {
511 {
512 $( $(@$tag:ident)* $func:expr; )*
513 } => {$crate::paste::paste!{ $(
514 $crate::inventory::submit!{
515 $crate::invoker_ent!($(@$tag)* $func)
516 }
517 )* }};
518}
519
520#[doc(hidden)]
525#[macro_export]
526macro_rules! invocable_func_as_dyn_invocable { { $f:expr, $trait:path } => { {
527 let f = &($f as _);
528 if let Some(v) = None {
535 let _: [_; 2] = [*f, $crate::dispatch::obtain_fn_type_for($f, v)];
546 }
547 f as &'static dyn $trait
550} } }
551
552#[doc(hidden)]
557pub trait FnTypeOfFnTrait<X> {
558 type FnType;
560}
561#[doc(hidden)]
563macro_rules! impl_fn_type_of_fn_trait { { $($arg:ident)* } => {
564 impl<Func, Ret, $($arg),*> FnTypeOfFnTrait<(Ret, $($arg),*)> for Func
565 where Func: Fn($($arg),*) -> Ret {
566 type FnType = fn($($arg),*) -> Ret;
567 }
568} }
569impl_fn_type_of_fn_trait!();
570impl_fn_type_of_fn_trait!(A);
571impl_fn_type_of_fn_trait!(A B);
572impl_fn_type_of_fn_trait!(A B C);
573impl_fn_type_of_fn_trait!(A B C D);
574impl_fn_type_of_fn_trait!(A B C D E);
575impl_fn_type_of_fn_trait!(A B C D E F);
576
577#[doc(hidden)]
589pub const fn obtain_fn_type_for<X, F: FnTypeOfFnTrait<X>>(_: F, v: Void) -> F::FnType {
590 match v {}
591}
592
593#[derive(Eq, PartialEq, Clone, Debug, Hash)]
595struct FuncType {
596 obj_id: any::TypeId,
598 method_id: any::TypeId,
600}
601
602#[derive(Debug, Clone)]
609pub struct DispatchTable {
610 map: HashMap<FuncType, InvokerEnt>,
613}
614
615impl DispatchTable {
616 pub fn from_inventory() -> Self {
623 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 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 pub fn insert(&mut self, ent: InvokerEnt) {
654 if let Some(old_ent) = self.insert_inner(ent) {
655 assert!(old_ent.same_decl(&ent));
657 }
658 }
659
660 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 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 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 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#[derive(Debug, Clone, thiserror::Error)]
733#[non_exhaustive]
734pub enum InvokeError {
735 #[error("No implementation for provided object and method types.")]
738 NoImpl,
739
740 #[error("Target object did not exist: {0}")]
745 NoObject(crate::LookupError),
746
747 #[error("Called invoke_without_dispatch on a regular RPC method")]
750 NoDispatchBypass,
751
752 #[error("Internal error")]
754 Bug(#[from] tor_error::Bug),
755}
756
757impl From<InvokeError> for RpcError {
758 fn from(err: InvokeError) -> Self {
759 use crate::RpcErrorKind as EK;
760 let kind = match &err {
761 InvokeError::NoImpl => EK::MethodNotImpl,
762 InvokeError::NoObject(e) => e.rpc_error_kind(),
763 InvokeError::NoDispatchBypass => EK::InternalError,
764 InvokeError::Bug(_) => EK::InternalError,
765 };
766 RpcError::new(err.to_string(), kind)
767 }
768}
769
770#[cfg(test)]
771pub(crate) mod test {
772 #![allow(clippy::bool_assert_comparison)]
774 #![allow(clippy::clone_on_copy)]
775 #![allow(clippy::dbg_macro)]
776 #![allow(clippy::mixed_attributes_style)]
777 #![allow(clippy::print_stderr)]
778 #![allow(clippy::print_stdout)]
779 #![allow(clippy::single_char_pattern)]
780 #![allow(clippy::unwrap_used)]
781 #![allow(clippy::unchecked_time_subtraction)]
782 #![allow(clippy::useless_vec)]
783 #![allow(clippy::needless_pass_by_value)]
784 #![allow(clippy::string_slice)] use crate::{DispatchTable, InvokeError, Method, NoUpdates, method::RpcMethod, templates::*};
788 use derive_deftly::Deftly;
789 use futures::SinkExt;
790 use futures_await_test::async_test;
791 use std::{
792 collections::HashMap,
793 sync::{Arc, Mutex, RwLock},
794 };
795
796 use super::UpdateSink;
797
798 #[derive(Clone, Deftly)]
800 #[derive_deftly(Object)]
801 pub(crate) struct Swan;
802 #[derive(Clone, Deftly)]
803 #[derive_deftly(Object)]
804 pub(crate) struct Wombat;
805 #[derive(Clone, Deftly)]
806 #[derive_deftly(Object)]
807 pub(crate) struct Sheep;
808 #[derive(Clone, Deftly)]
809 #[derive_deftly(Object)]
810 pub(crate) struct Brick;
811
812 #[derive(Debug, serde::Deserialize, Deftly)]
814 #[derive_deftly(DynMethod)]
815 #[deftly(rpc(method_name = "x-test:getname"))]
816 pub(crate) struct GetName;
817
818 #[derive(Debug, serde::Deserialize, Deftly)]
819 #[derive_deftly(DynMethod)]
820 #[deftly(rpc(method_name = "x-test:getkids"))]
821 pub(crate) struct GetKids;
822
823 impl RpcMethod for GetName {
824 type Output = Outcome;
825 type Update = NoUpdates;
826 }
827 impl RpcMethod for GetKids {
828 type Output = Outcome;
829 type Update = String;
830 }
831
832 #[derive(serde::Serialize)]
833 pub(crate) struct Outcome {
834 pub(crate) v: String,
835 }
836
837 async fn getname_swan(
838 _obj: Arc<Swan>,
839 _method: Box<GetName>,
840 _ctx: Arc<dyn crate::Context>,
841 ) -> Result<Outcome, crate::RpcError> {
842 Ok(Outcome {
843 v: "swan".to_string(),
844 })
845 }
846 async fn getname_sheep(
847 _obj: Arc<Sheep>,
848 _method: Box<GetName>,
849 _ctx: Arc<dyn crate::Context>,
850 ) -> Result<Outcome, crate::RpcError> {
851 Ok(Outcome {
852 v: "sheep".to_string(),
853 })
854 }
855 async fn getname_wombat(
856 _obj: Arc<Wombat>,
857 _method: Box<GetName>,
858 _ctx: Arc<dyn crate::Context>,
859 ) -> Result<Outcome, crate::RpcError> {
860 Ok(Outcome {
861 v: "wombat".to_string(),
862 })
863 }
864 async fn getname_brick(
865 _obj: Arc<Brick>,
866 _method: Box<GetName>,
867 _ctx: Arc<dyn crate::Context>,
868 ) -> Result<Outcome, crate::RpcError> {
869 Ok(Outcome {
870 v: "brick".to_string(),
871 })
872 }
873 async fn getkids_swan(
874 _obj: Arc<Swan>,
875 _method: Box<GetKids>,
876 _ctx: Arc<dyn crate::Context>,
877 ) -> Result<Outcome, crate::RpcError> {
878 Ok(Outcome {
879 v: "cygnets".to_string(),
880 })
881 }
882 async fn getkids_sheep(
883 _obj: Arc<Sheep>,
884 _method: Box<GetKids>,
885 _ctx: Arc<dyn crate::Context>,
886 ) -> Result<Outcome, crate::RpcError> {
887 Ok(Outcome {
888 v: "lambs".to_string(),
889 })
890 }
891 async fn getkids_wombat(
892 _obj: Arc<Wombat>,
893 _method: Box<GetKids>,
894 _ctx: Arc<dyn crate::Context>,
895 mut sink: UpdateSink<String>,
896 ) -> Result<Outcome, crate::RpcError> {
897 let _ignore = sink.send("brb, burrowing".to_string()).await;
898 Ok(Outcome {
899 v: "joeys".to_string(),
900 })
901 }
902
903 static_rpc_invoke_fn! {
904 getname_swan;
905 getname_sheep;
906 getname_wombat;
907 getname_brick;
908
909 getkids_swan;
910 getkids_sheep;
911 getkids_wombat;
912 }
913
914 pub(crate) struct Ctx {
915 table: Arc<RwLock<DispatchTable>>,
916 map: Arc<Mutex<HashMap<crate::ObjectId, Arc<dyn crate::Object>>>>,
917 next_id: Arc<Mutex<u32>>,
918 }
919 impl From<DispatchTable> for Ctx {
920 fn from(table: DispatchTable) -> Self {
921 Self {
922 table: Arc::new(RwLock::new(table)),
923 map: Arc::new(Mutex::new(HashMap::new())),
924 next_id: Arc::new(Mutex::new(1)),
925 }
926 }
927 }
928
929 impl crate::Context for Ctx {
930 fn lookup_object(
931 &self,
932 id: &crate::ObjectId,
933 ) -> Result<std::sync::Arc<dyn crate::Object>, crate::LookupError> {
934 self.map
935 .lock()
936 .unwrap()
937 .get(id)
938 .cloned()
939 .ok_or_else(|| crate::LookupError::NoObject(id.clone()))
940 }
941 fn register_owned(&self, object: Arc<dyn crate::Object>) -> crate::ObjectId {
942 let mut id_guard = self.next_id.lock().unwrap();
943 let id = *id_guard;
944 *id_guard += 1;
945
946 let id = crate::ObjectId::from(id.to_string());
947 self.map.lock().unwrap().insert(id.clone(), object);
948 id
949 }
950
951 fn register_weak(&self, _object: &Arc<dyn crate::Object>) -> crate::ObjectId {
952 todo!()
953 }
954
955 fn release(&self, _object: &crate::ObjectId) -> Result<(), crate::LookupError> {
956 todo!()
957 }
958
959 fn dispatch_table(&self) -> &Arc<RwLock<crate::DispatchTable>> {
960 &self.table
961 }
962 }
963
964 #[derive(Deftly, Clone)]
965 #[derive_deftly(Object)]
966 struct GenericObj<T, U>
967 where
968 T: Send + Sync + 'static + Clone + ToString,
969 U: Send + Sync + 'static + Clone + ToString,
970 {
971 name: T,
972 kids: U,
973 }
974
975 async fn getname_generic<T, U>(
976 obj: Arc<GenericObj<T, U>>,
977 _method: Box<GetName>,
978 _ctx: Arc<dyn crate::Context>,
979 ) -> Result<Outcome, crate::RpcError>
980 where
981 T: Send + Sync + 'static + Clone + ToString,
982 U: Send + Sync + 'static + Clone + ToString,
983 {
984 Ok(Outcome {
985 v: obj.name.to_string(),
986 })
987 }
988 async fn getkids_generic<T, U>(
989 obj: Arc<GenericObj<T, U>>,
990 _method: Box<GetKids>,
991 _ctx: Arc<dyn crate::Context>,
992 ) -> Result<Outcome, crate::RpcError>
993 where
994 T: Send + Sync + 'static + Clone + ToString,
995 U: Send + Sync + 'static + Clone + ToString,
996 {
997 Ok(Outcome {
998 v: obj.kids.to_string(),
999 })
1000 }
1001
1002 static_rpc_invoke_fn! {
1004 getname_generic::<u32,u32>;
1005 getname_generic::<&'static str, &'static str>;
1006 getkids_generic::<u32,u32>;
1007 getkids_generic::<&'static str, &'static str>;
1008 }
1009
1010 impl<T, U> GenericObj<T, U>
1012 where
1013 T: Send + Sync + 'static + Clone + ToString,
1014 U: Send + Sync + 'static + Clone + ToString,
1015 {
1016 fn install_rpc_functions(table: &mut super::DispatchTable) {
1017 table.insert(invoker_ent!(getname_generic::<T, U>));
1018 table.insert(invoker_ent!(getkids_generic::<T, U>));
1019 }
1020 }
1021
1022 #[derive(Clone, Deftly)]
1024 #[derive_deftly(Object)]
1025 #[deftly(rpc(
1026 delegate_with = "|this: &Self| this.contents.clone()",
1027 delegate_type = "dyn crate::Object"
1028 ))]
1029 struct CatCarrier {
1030 contents: Option<Arc<dyn crate::Object>>,
1031 }
1032
1033 #[async_test]
1034 async fn try_invoke() {
1035 use super::*;
1036 fn invoke_helper<O: Object, M: Method>(
1037 ctx: &Arc<dyn Context>,
1038 obj: O,
1039 method: M,
1040 ) -> Result<RpcResultFuture, InvokeError> {
1041 let animal: Arc<dyn crate::Object> = Arc::new(obj);
1042 let request: Box<dyn DynMethod> = Box::new(method);
1043 let discard = Box::pin(futures::sink::drain().sink_err_into());
1044 let id = ctx.register_owned(animal);
1045 crate::invoke_rpc_method(Arc::clone(ctx), &id, request, discard)
1046 }
1047 async fn invoke_ok<O: crate::Object, M: crate::Method>(
1048 table: &Arc<dyn Context>,
1049 obj: O,
1050 method: M,
1051 ) -> String {
1052 let res = invoke_helper(table, obj, method).unwrap().await.unwrap();
1053 serde_json::to_string(&res).unwrap()
1054 }
1055 async fn sentence<O: crate::Object + Clone>(table: &Arc<dyn Context>, obj: O) -> String {
1056 format!(
1057 "Hello I am a friendly {} and these are my lovely {}.",
1058 invoke_ok(table, obj.clone(), GetName).await,
1059 invoke_ok(table, obj, GetKids).await
1060 )
1061 }
1062
1063 let table: Arc<dyn Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1064
1065 assert_eq!(
1066 sentence(&table, Swan).await,
1067 r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1068 );
1069 assert_eq!(
1070 sentence(&table, Sheep).await,
1071 r#"Hello I am a friendly {"v":"sheep"} and these are my lovely {"v":"lambs"}."#
1072 );
1073 assert_eq!(
1074 sentence(&table, Wombat).await,
1075 r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1076 );
1077
1078 assert!(matches!(
1079 invoke_helper(&table, Brick, GetKids),
1080 Err(InvokeError::NoImpl)
1081 ));
1082
1083 let obj1 = GenericObj {
1088 name: "nuncle",
1089 kids: "niblings",
1090 };
1091 let obj2 = GenericObj {
1092 name: 1337_u32,
1093 kids: 271828_u32,
1094 };
1095 assert_eq!(
1096 sentence(&table, obj1).await,
1097 r#"Hello I am a friendly {"v":"nuncle"} and these are my lovely {"v":"niblings"}."#
1098 );
1099 assert_eq!(
1100 sentence(&table, obj2).await,
1101 r#"Hello I am a friendly {"v":"1337"} and these are my lovely {"v":"271828"}."#
1102 );
1103
1104 let obj3 = GenericObj {
1105 name: 13371337_u64,
1106 kids: 2718281828_u64,
1107 };
1108 assert!(matches!(
1109 invoke_helper(&table, obj3.clone(), GetKids),
1110 Err(InvokeError::NoImpl)
1111 ));
1112 {
1113 let mut tab = table.dispatch_table().write().unwrap();
1114 GenericObj::<u64, u64>::install_rpc_functions(&mut tab);
1115 }
1116 assert_eq!(
1117 sentence(&table, obj3).await,
1118 r#"Hello I am a friendly {"v":"13371337"} and these are my lovely {"v":"2718281828"}."#
1119 );
1120
1121 let carrier_1 = CatCarrier {
1123 contents: Some(Arc::new(Wombat)),
1124 };
1125 let carrier_2 = CatCarrier {
1126 contents: Some(Arc::new(Swan)),
1127 };
1128 let carrier_3 = CatCarrier {
1129 contents: Some(Arc::new(Brick)),
1130 };
1131 let carrier_4 = CatCarrier { contents: None };
1132 assert_eq!(
1133 sentence(&table, carrier_1).await,
1134 r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1135 );
1136 assert_eq!(
1137 sentence(&table, carrier_2).await,
1138 r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1139 );
1140 assert!(matches!(
1141 invoke_helper(&table, carrier_3, GetKids),
1142 Err(InvokeError::NoImpl)
1143 ));
1144 assert!(matches!(
1145 invoke_helper(&table, carrier_4, GetKids),
1146 Err(InvokeError::NoImpl)
1147 ));
1148 }
1149
1150 #[derive(Debug)]
1152 struct MyObject {}
1153
1154 #[derive(Debug, Deftly)]
1155 #[derive_deftly(DynMethod)]
1156 #[deftly(rpc(no_method_name))]
1157 struct SpecialOnly {}
1158 impl Method for SpecialOnly {
1159 type Output = Result<MyObject, MyObject>; type Update = crate::NoUpdates;
1161 }
1162
1163 async fn specialonly_swan(
1164 _obj: Arc<Swan>,
1165 _method: Box<SpecialOnly>,
1166 _ctx: Arc<dyn crate::Context>,
1167 ) -> Result<MyObject, MyObject> {
1168 Ok(MyObject {})
1169 }
1170 static_rpc_invoke_fn! { @special specialonly_swan; }
1171
1172 #[async_test]
1173 async fn try_invoke_special() {
1174 let table = crate::DispatchTable::from_inventory();
1175 let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(table));
1176
1177 let res: Outcome =
1178 crate::invoke_special_method(Arc::clone(&ctx), Arc::new(Swan), Box::new(GetKids))
1179 .await
1180 .unwrap()
1181 .unwrap();
1182
1183 assert_eq!(res.v, "cygnets");
1184
1185 let _an_obj: MyObject = crate::invoke_special_method(
1186 Arc::clone(&ctx),
1187 Arc::new(Swan),
1188 Box::new(SpecialOnly {}),
1189 )
1190 .await
1191 .unwrap()
1192 .unwrap();
1193 }
1194
1195 #[test]
1196 fn invoke_poorly() {
1197 fn is_internal_invoke_err<T>(val: Result<T, InvokeError>) -> bool {
1198 matches!(val, Err(InvokeError::Bug(_)))
1199 }
1200
1201 let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1204 let discard = || Box::pin(futures::sink::drain().sink_err_into());
1205
1206 let table = DispatchTable::from_inventory();
1207 let (_swan, ent) = table.resolve_rpc_invoker(Arc::new(Swan), &GetKids).unwrap();
1208
1209 let bug = ent.invoke(
1211 Arc::new(Swan),
1212 Box::new(GetName),
1213 Arc::clone(&ctx),
1214 discard(),
1215 );
1216 assert!(is_internal_invoke_err(bug));
1217
1218 let bug = ent.invoke(
1220 Arc::new(Wombat),
1221 Box::new(GetKids),
1222 Arc::clone(&ctx),
1223 discard(),
1224 );
1225 assert!(is_internal_invoke_err(bug));
1226
1227 let bug = ent.invoke_special(Arc::new(Swan), Box::new(GetName), Arc::clone(&ctx));
1229 assert!(is_internal_invoke_err(bug));
1230 let bug = ent.invoke_special(Arc::new(Wombat), Box::new(GetKids), Arc::clone(&ctx));
1232 assert!(is_internal_invoke_err(bug));
1233 }
1234
1235 #[test]
1236 fn invoker_ents() {
1237 let ent1 = invoker_ent!(@special specialonly_swan);
1238 let ent1b = invoker_ent!(@special specialonly_swan); let ent2 = invoker_ent!(getname_generic::<String, String>);
1240 let ent2b = invoker_ent!(getname_generic::<String, String>);
1241
1242 assert_eq!(ent1.same_decl(&ent1), true);
1243 assert_eq!(ent1.same_decl(&ent1b), false);
1244 assert_eq!(ent1.same_decl(&ent2), false);
1245
1246 assert_eq!(ent2.same_decl(&ent2), true);
1247 assert_eq!(ent2.same_decl(&ent2b), false);
1248
1249 let re = regex::Regex::new(
1250 r#"^Invocable\(.*GetName \(x-test:getname\) for .*GenericObj.*String.*String"#,
1251 )
1252 .unwrap();
1253 let debug_fmt = format!("{:?}", &ent2);
1254 dbg!(&debug_fmt);
1255 assert!(re.is_match(&debug_fmt));
1256 }
1257
1258 #[test]
1259 fn redundant_invoker_ents() {
1260 let ent = invoker_ent!(getname_generic::<String, String>);
1261 let mut table = DispatchTable::from_inventory();
1262
1263 assert_eq!(ent.same_decl(&ent.clone()), true);
1264 table.insert(ent.clone());
1265 table.insert(ent);
1266 }
1267
1268 #[test]
1269 #[should_panic]
1270 fn conflicting_invoker_ents() {
1271 let ent = invoker_ent!(getname_generic::<String, String>);
1272 let ent2 = invoker_ent!(getname_generic::<String, String>);
1273 let mut table = DispatchTable::from_inventory();
1274 table.insert(ent);
1275 table.insert(ent2);
1276 }
1277}