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 use crate::{DispatchTable, InvokeError, Method, NoUpdates, method::RpcMethod, templates::*};
787 use derive_deftly::Deftly;
788 use futures::SinkExt;
789 use futures_await_test::async_test;
790 use std::{
791 collections::HashMap,
792 sync::{Arc, Mutex, RwLock},
793 };
794
795 use super::UpdateSink;
796
797 #[derive(Clone, Deftly)]
799 #[derive_deftly(Object)]
800 pub(crate) struct Swan;
801 #[derive(Clone, Deftly)]
802 #[derive_deftly(Object)]
803 pub(crate) struct Wombat;
804 #[derive(Clone, Deftly)]
805 #[derive_deftly(Object)]
806 pub(crate) struct Sheep;
807 #[derive(Clone, Deftly)]
808 #[derive_deftly(Object)]
809 pub(crate) struct Brick;
810
811 #[derive(Debug, serde::Deserialize, Deftly)]
813 #[derive_deftly(DynMethod)]
814 #[deftly(rpc(method_name = "x-test:getname"))]
815 pub(crate) struct GetName;
816
817 #[derive(Debug, serde::Deserialize, Deftly)]
818 #[derive_deftly(DynMethod)]
819 #[deftly(rpc(method_name = "x-test:getkids"))]
820 pub(crate) struct GetKids;
821
822 impl RpcMethod for GetName {
823 type Output = Outcome;
824 type Update = NoUpdates;
825 }
826 impl RpcMethod for GetKids {
827 type Output = Outcome;
828 type Update = String;
829 }
830
831 #[derive(serde::Serialize)]
832 pub(crate) struct Outcome {
833 pub(crate) v: String,
834 }
835
836 async fn getname_swan(
837 _obj: Arc<Swan>,
838 _method: Box<GetName>,
839 _ctx: Arc<dyn crate::Context>,
840 ) -> Result<Outcome, crate::RpcError> {
841 Ok(Outcome {
842 v: "swan".to_string(),
843 })
844 }
845 async fn getname_sheep(
846 _obj: Arc<Sheep>,
847 _method: Box<GetName>,
848 _ctx: Arc<dyn crate::Context>,
849 ) -> Result<Outcome, crate::RpcError> {
850 Ok(Outcome {
851 v: "sheep".to_string(),
852 })
853 }
854 async fn getname_wombat(
855 _obj: Arc<Wombat>,
856 _method: Box<GetName>,
857 _ctx: Arc<dyn crate::Context>,
858 ) -> Result<Outcome, crate::RpcError> {
859 Ok(Outcome {
860 v: "wombat".to_string(),
861 })
862 }
863 async fn getname_brick(
864 _obj: Arc<Brick>,
865 _method: Box<GetName>,
866 _ctx: Arc<dyn crate::Context>,
867 ) -> Result<Outcome, crate::RpcError> {
868 Ok(Outcome {
869 v: "brick".to_string(),
870 })
871 }
872 async fn getkids_swan(
873 _obj: Arc<Swan>,
874 _method: Box<GetKids>,
875 _ctx: Arc<dyn crate::Context>,
876 ) -> Result<Outcome, crate::RpcError> {
877 Ok(Outcome {
878 v: "cygnets".to_string(),
879 })
880 }
881 async fn getkids_sheep(
882 _obj: Arc<Sheep>,
883 _method: Box<GetKids>,
884 _ctx: Arc<dyn crate::Context>,
885 ) -> Result<Outcome, crate::RpcError> {
886 Ok(Outcome {
887 v: "lambs".to_string(),
888 })
889 }
890 async fn getkids_wombat(
891 _obj: Arc<Wombat>,
892 _method: Box<GetKids>,
893 _ctx: Arc<dyn crate::Context>,
894 mut sink: UpdateSink<String>,
895 ) -> Result<Outcome, crate::RpcError> {
896 let _ignore = sink.send("brb, burrowing".to_string()).await;
897 Ok(Outcome {
898 v: "joeys".to_string(),
899 })
900 }
901
902 static_rpc_invoke_fn! {
903 getname_swan;
904 getname_sheep;
905 getname_wombat;
906 getname_brick;
907
908 getkids_swan;
909 getkids_sheep;
910 getkids_wombat;
911 }
912
913 pub(crate) struct Ctx {
914 table: Arc<RwLock<DispatchTable>>,
915 map: Arc<Mutex<HashMap<crate::ObjectId, Arc<dyn crate::Object>>>>,
916 next_id: Arc<Mutex<u32>>,
917 }
918 impl From<DispatchTable> for Ctx {
919 fn from(table: DispatchTable) -> Self {
920 Self {
921 table: Arc::new(RwLock::new(table)),
922 map: Arc::new(Mutex::new(HashMap::new())),
923 next_id: Arc::new(Mutex::new(1)),
924 }
925 }
926 }
927
928 impl crate::Context for Ctx {
929 fn lookup_object(
930 &self,
931 id: &crate::ObjectId,
932 ) -> Result<std::sync::Arc<dyn crate::Object>, crate::LookupError> {
933 self.map
934 .lock()
935 .unwrap()
936 .get(id)
937 .cloned()
938 .ok_or_else(|| crate::LookupError::NoObject(id.clone()))
939 }
940 fn register_owned(&self, object: Arc<dyn crate::Object>) -> crate::ObjectId {
941 let mut id_guard = self.next_id.lock().unwrap();
942 let id = *id_guard;
943 *id_guard += 1;
944
945 let id = crate::ObjectId::from(id.to_string());
946 self.map.lock().unwrap().insert(id.clone(), object);
947 id
948 }
949
950 fn register_weak(&self, _object: &Arc<dyn crate::Object>) -> crate::ObjectId {
951 todo!()
952 }
953
954 fn release(&self, _object: &crate::ObjectId) -> Result<(), crate::LookupError> {
955 todo!()
956 }
957
958 fn dispatch_table(&self) -> &Arc<RwLock<crate::DispatchTable>> {
959 &self.table
960 }
961 }
962
963 #[derive(Deftly, Clone)]
964 #[derive_deftly(Object)]
965 struct GenericObj<T, U>
966 where
967 T: Send + Sync + 'static + Clone + ToString,
968 U: Send + Sync + 'static + Clone + ToString,
969 {
970 name: T,
971 kids: U,
972 }
973
974 async fn getname_generic<T, U>(
975 obj: Arc<GenericObj<T, U>>,
976 _method: Box<GetName>,
977 _ctx: Arc<dyn crate::Context>,
978 ) -> Result<Outcome, crate::RpcError>
979 where
980 T: Send + Sync + 'static + Clone + ToString,
981 U: Send + Sync + 'static + Clone + ToString,
982 {
983 Ok(Outcome {
984 v: obj.name.to_string(),
985 })
986 }
987 async fn getkids_generic<T, U>(
988 obj: Arc<GenericObj<T, U>>,
989 _method: Box<GetKids>,
990 _ctx: Arc<dyn crate::Context>,
991 ) -> Result<Outcome, crate::RpcError>
992 where
993 T: Send + Sync + 'static + Clone + ToString,
994 U: Send + Sync + 'static + Clone + ToString,
995 {
996 Ok(Outcome {
997 v: obj.kids.to_string(),
998 })
999 }
1000
1001 static_rpc_invoke_fn! {
1003 getname_generic::<u32,u32>;
1004 getname_generic::<&'static str, &'static str>;
1005 getkids_generic::<u32,u32>;
1006 getkids_generic::<&'static str, &'static str>;
1007 }
1008
1009 impl<T, U> GenericObj<T, U>
1011 where
1012 T: Send + Sync + 'static + Clone + ToString,
1013 U: Send + Sync + 'static + Clone + ToString,
1014 {
1015 fn install_rpc_functions(table: &mut super::DispatchTable) {
1016 table.insert(invoker_ent!(getname_generic::<T, U>));
1017 table.insert(invoker_ent!(getkids_generic::<T, U>));
1018 }
1019 }
1020
1021 #[derive(Clone, Deftly)]
1023 #[derive_deftly(Object)]
1024 #[deftly(rpc(
1025 delegate_with = "|this: &Self| this.contents.clone()",
1026 delegate_type = "dyn crate::Object"
1027 ))]
1028 struct CatCarrier {
1029 contents: Option<Arc<dyn crate::Object>>,
1030 }
1031
1032 #[async_test]
1033 async fn try_invoke() {
1034 use super::*;
1035 fn invoke_helper<O: Object, M: Method>(
1036 ctx: &Arc<dyn Context>,
1037 obj: O,
1038 method: M,
1039 ) -> Result<RpcResultFuture, InvokeError> {
1040 let animal: Arc<dyn crate::Object> = Arc::new(obj);
1041 let request: Box<dyn DynMethod> = Box::new(method);
1042 let discard = Box::pin(futures::sink::drain().sink_err_into());
1043 let id = ctx.register_owned(animal);
1044 crate::invoke_rpc_method(Arc::clone(ctx), &id, request, discard)
1045 }
1046 async fn invoke_ok<O: crate::Object, M: crate::Method>(
1047 table: &Arc<dyn Context>,
1048 obj: O,
1049 method: M,
1050 ) -> String {
1051 let res = invoke_helper(table, obj, method).unwrap().await.unwrap();
1052 serde_json::to_string(&res).unwrap()
1053 }
1054 async fn sentence<O: crate::Object + Clone>(table: &Arc<dyn Context>, obj: O) -> String {
1055 format!(
1056 "Hello I am a friendly {} and these are my lovely {}.",
1057 invoke_ok(table, obj.clone(), GetName).await,
1058 invoke_ok(table, obj, GetKids).await
1059 )
1060 }
1061
1062 let table: Arc<dyn Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1063
1064 assert_eq!(
1065 sentence(&table, Swan).await,
1066 r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1067 );
1068 assert_eq!(
1069 sentence(&table, Sheep).await,
1070 r#"Hello I am a friendly {"v":"sheep"} and these are my lovely {"v":"lambs"}."#
1071 );
1072 assert_eq!(
1073 sentence(&table, Wombat).await,
1074 r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1075 );
1076
1077 assert!(matches!(
1078 invoke_helper(&table, Brick, GetKids),
1079 Err(InvokeError::NoImpl)
1080 ));
1081
1082 let obj1 = GenericObj {
1087 name: "nuncle",
1088 kids: "niblings",
1089 };
1090 let obj2 = GenericObj {
1091 name: 1337_u32,
1092 kids: 271828_u32,
1093 };
1094 assert_eq!(
1095 sentence(&table, obj1).await,
1096 r#"Hello I am a friendly {"v":"nuncle"} and these are my lovely {"v":"niblings"}."#
1097 );
1098 assert_eq!(
1099 sentence(&table, obj2).await,
1100 r#"Hello I am a friendly {"v":"1337"} and these are my lovely {"v":"271828"}."#
1101 );
1102
1103 let obj3 = GenericObj {
1104 name: 13371337_u64,
1105 kids: 2718281828_u64,
1106 };
1107 assert!(matches!(
1108 invoke_helper(&table, obj3.clone(), GetKids),
1109 Err(InvokeError::NoImpl)
1110 ));
1111 {
1112 let mut tab = table.dispatch_table().write().unwrap();
1113 GenericObj::<u64, u64>::install_rpc_functions(&mut tab);
1114 }
1115 assert_eq!(
1116 sentence(&table, obj3).await,
1117 r#"Hello I am a friendly {"v":"13371337"} and these are my lovely {"v":"2718281828"}."#
1118 );
1119
1120 let carrier_1 = CatCarrier {
1122 contents: Some(Arc::new(Wombat)),
1123 };
1124 let carrier_2 = CatCarrier {
1125 contents: Some(Arc::new(Swan)),
1126 };
1127 let carrier_3 = CatCarrier {
1128 contents: Some(Arc::new(Brick)),
1129 };
1130 let carrier_4 = CatCarrier { contents: None };
1131 assert_eq!(
1132 sentence(&table, carrier_1).await,
1133 r#"Hello I am a friendly {"v":"wombat"} and these are my lovely {"v":"joeys"}."#
1134 );
1135 assert_eq!(
1136 sentence(&table, carrier_2).await,
1137 r#"Hello I am a friendly {"v":"swan"} and these are my lovely {"v":"cygnets"}."#
1138 );
1139 assert!(matches!(
1140 invoke_helper(&table, carrier_3, GetKids),
1141 Err(InvokeError::NoImpl)
1142 ));
1143 assert!(matches!(
1144 invoke_helper(&table, carrier_4, GetKids),
1145 Err(InvokeError::NoImpl)
1146 ));
1147 }
1148
1149 #[derive(Debug)]
1151 struct MyObject {}
1152
1153 #[derive(Debug, Deftly)]
1154 #[derive_deftly(DynMethod)]
1155 #[deftly(rpc(no_method_name))]
1156 struct SpecialOnly {}
1157 impl Method for SpecialOnly {
1158 type Output = Result<MyObject, MyObject>; type Update = crate::NoUpdates;
1160 }
1161
1162 async fn specialonly_swan(
1163 _obj: Arc<Swan>,
1164 _method: Box<SpecialOnly>,
1165 _ctx: Arc<dyn crate::Context>,
1166 ) -> Result<MyObject, MyObject> {
1167 Ok(MyObject {})
1168 }
1169 static_rpc_invoke_fn! { @special specialonly_swan; }
1170
1171 #[async_test]
1172 async fn try_invoke_special() {
1173 let table = crate::DispatchTable::from_inventory();
1174 let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(table));
1175
1176 let res: Outcome =
1177 crate::invoke_special_method(Arc::clone(&ctx), Arc::new(Swan), Box::new(GetKids))
1178 .await
1179 .unwrap()
1180 .unwrap();
1181
1182 assert_eq!(res.v, "cygnets");
1183
1184 let _an_obj: MyObject = crate::invoke_special_method(
1185 Arc::clone(&ctx),
1186 Arc::new(Swan),
1187 Box::new(SpecialOnly {}),
1188 )
1189 .await
1190 .unwrap()
1191 .unwrap();
1192 }
1193
1194 #[test]
1195 fn invoke_poorly() {
1196 fn is_internal_invoke_err<T>(val: Result<T, InvokeError>) -> bool {
1197 matches!(val, Err(InvokeError::Bug(_)))
1198 }
1199
1200 let ctx: Arc<dyn crate::Context> = Arc::new(Ctx::from(DispatchTable::from_inventory()));
1203 let discard = || Box::pin(futures::sink::drain().sink_err_into());
1204
1205 let table = DispatchTable::from_inventory();
1206 let (_swan, ent) = table.resolve_rpc_invoker(Arc::new(Swan), &GetKids).unwrap();
1207
1208 let bug = ent.invoke(
1210 Arc::new(Swan),
1211 Box::new(GetName),
1212 Arc::clone(&ctx),
1213 discard(),
1214 );
1215 assert!(is_internal_invoke_err(bug));
1216
1217 let bug = ent.invoke(
1219 Arc::new(Wombat),
1220 Box::new(GetKids),
1221 Arc::clone(&ctx),
1222 discard(),
1223 );
1224 assert!(is_internal_invoke_err(bug));
1225
1226 let bug = ent.invoke_special(Arc::new(Swan), Box::new(GetName), Arc::clone(&ctx));
1228 assert!(is_internal_invoke_err(bug));
1229 let bug = ent.invoke_special(Arc::new(Wombat), Box::new(GetKids), Arc::clone(&ctx));
1231 assert!(is_internal_invoke_err(bug));
1232 }
1233
1234 #[test]
1235 fn invoker_ents() {
1236 let ent1 = invoker_ent!(@special specialonly_swan);
1237 let ent1b = invoker_ent!(@special specialonly_swan); let ent2 = invoker_ent!(getname_generic::<String, String>);
1239 let ent2b = invoker_ent!(getname_generic::<String, String>);
1240
1241 assert_eq!(ent1.same_decl(&ent1), true);
1242 assert_eq!(ent1.same_decl(&ent1b), false);
1243 assert_eq!(ent1.same_decl(&ent2), false);
1244
1245 assert_eq!(ent2.same_decl(&ent2), true);
1246 assert_eq!(ent2.same_decl(&ent2b), false);
1247
1248 let re = regex::Regex::new(
1249 r#"^Invocable\(.*GetName \(x-test:getname\) for .*GenericObj.*String.*String"#,
1250 )
1251 .unwrap();
1252 let debug_fmt = format!("{:?}", &ent2);
1253 dbg!(&debug_fmt);
1254 assert!(re.is_match(&debug_fmt));
1255 }
1256
1257 #[test]
1258 fn redundant_invoker_ents() {
1259 let ent = invoker_ent!(getname_generic::<String, String>);
1260 let mut table = DispatchTable::from_inventory();
1261
1262 assert_eq!(ent.same_decl(&ent.clone()), true);
1263 table.insert(ent.clone());
1264 table.insert(ent);
1265 }
1266
1267 #[test]
1268 #[should_panic]
1269 fn conflicting_invoker_ents() {
1270 let ent = invoker_ent!(getname_generic::<String, String>);
1271 let ent2 = invoker_ent!(getname_generic::<String, String>);
1272 let mut table = DispatchTable::from_inventory();
1273 table.insert(ent);
1274 table.insert(ent2);
1275 }
1276}