1use super::{
16 ensure_callable_invariants,
17 Callable,
18 CallableKind,
19 InputsIter,
20 Visibility,
21};
22use crate::ir::{
23 self,
24 attrs::SelectorOrWildcard,
25 utils,
26 utils::{
27 extract_cfg_attributes,
28 extract_cfg_syn_attributes,
29 },
30};
31use proc_macro2::{
32 Ident,
33 Span,
34 TokenStream,
35};
36use syn::spanned::Spanned as _;
37
38#[derive(Debug, Copy, Clone, PartialEq, Eq)]
40pub enum Receiver {
41 Ref,
43 RefMut,
45}
46
47impl quote::ToTokens for Receiver {
48 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
49 let receiver = match self {
50 Self::Ref => quote::quote! { &self },
51 Self::RefMut => quote::quote! { &mut self },
52 };
53 tokens.extend(receiver);
54 }
55}
56
57impl Receiver {
58 pub fn is_ref(self) -> bool {
60 matches!(self, Self::Ref)
61 }
62
63 pub fn is_ref_mut(self) -> bool {
65 matches!(self, Self::RefMut)
66 }
67}
68
69#[derive(Debug, PartialEq, Eq)]
101pub struct Message {
102 pub(super) item: syn::ImplItemFn,
104 is_payable: bool,
106 is_default: bool,
108 selector: Option<SelectorOrWildcard>,
115 name: Option<String>,
122}
123
124impl quote::ToTokens for Message {
125 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
128 self.item.to_tokens(tokens)
129 }
130}
131
132impl Message {
133 fn self_ref_receiver(
142 method_item: &syn::ImplItemFn,
143 ) -> Result<&syn::Receiver, syn::Error> {
144 let mut fn_args = method_item.sig.inputs.iter();
145 fn bail(span: Span) -> syn::Error {
146 format_err!(
147 span,
148 "ink! messages must have `&self` or `&mut self` receiver",
149 )
150 }
151 match fn_args.next() {
152 None => Err(bail(method_item.span())),
153 Some(syn::FnArg::Typed(pat_typed)) => Err(bail(pat_typed.span())),
154 Some(syn::FnArg::Receiver(receiver)) => {
155 match receiver.reference {
156 None => Err(bail(receiver.span())),
157 Some(_) => Ok(receiver),
158 }
159 }
160 }
161 }
162
163 fn ensure_not_return_self(method_item: &syn::ImplItemFn) -> Result<(), syn::Error> {
169 match &method_item.sig.output {
170 syn::ReturnType::Default => (),
171 syn::ReturnType::Type(_arrow, ret_type) => {
172 if let syn::Type::Path(type_path) = &**ret_type {
173 if type_path.path.is_ident("Self") {
174 return Err(format_err!(
175 ret_type,
176 "ink! messages must not return `Self`"
177 ))
178 }
179 }
180 }
181 }
182 Ok(())
183 }
184
185 fn sanitize_attributes(
189 method_item: &syn::ImplItemFn,
190 ) -> Result<(ir::InkAttribute, Vec<syn::Attribute>), syn::Error> {
191 ir::sanitize_attributes(
192 method_item.span(),
193 method_item.attrs.clone(),
194 &ir::AttributeArgKind::Message,
195 |arg| {
196 match arg.kind() {
197 ir::AttributeArg::Message
198 | ir::AttributeArg::Payable
199 | ir::AttributeArg::Default
200 | ir::AttributeArg::Selector(_)
201 | ir::AttributeArg::Name(_) => Ok(()),
202 _ => Err(None),
203 }
204 },
205 )
206 }
207}
208
209impl TryFrom<syn::ImplItemFn> for Message {
210 type Error = syn::Error;
211
212 fn try_from(method_item: syn::ImplItemFn) -> Result<Self, Self::Error> {
213 ensure_callable_invariants(&method_item, CallableKind::Message)?;
214 let self_ref_receiver = Self::self_ref_receiver(&method_item)?;
217 Self::ensure_not_return_self(&method_item)?;
218 let (ink_attrs, other_attrs) = Self::sanitize_attributes(&method_item)?;
219 let is_payable = ink_attrs.is_payable();
220 let is_default = ink_attrs.is_default();
221 let selector = ink_attrs.selector();
222 let name = ink_attrs.name();
223 if is_payable && self_ref_receiver.mutability.is_none() {
225 return Err(format_err!(
226 method_item.span(),
227 "ink! messages with a `payable` attribute argument must have a `&mut self` receiver",
228 ));
229 }
230 Ok(Self {
231 is_payable,
232 is_default,
233 selector,
234 name,
235 item: syn::ImplItemFn {
236 attrs: other_attrs,
237 ..method_item
238 },
239 })
240 }
241}
242
243impl Callable for Message {
244 fn kind(&self) -> CallableKind {
245 CallableKind::Message
246 }
247
248 fn ident(&self) -> &Ident {
249 &self.item.sig.ident
250 }
251
252 fn user_provided_selector(&self) -> Option<&ir::Selector> {
253 if let Some(SelectorOrWildcard::UserProvided(selector)) = self.selector.as_ref() {
254 return Some(selector)
255 }
256 None
257 }
258
259 fn has_wildcard_selector(&self) -> bool {
260 matches!(self.selector, Some(SelectorOrWildcard::Wildcard))
261 }
262
263 fn has_wildcard_complement_selector(&self) -> bool {
264 self.selector == Some(SelectorOrWildcard::wildcard_complement())
265 }
266
267 fn is_payable(&self) -> bool {
268 self.is_payable
269 }
270
271 fn is_default(&self) -> bool {
272 self.is_default
273 }
274
275 fn visibility(&self) -> Visibility {
276 match &self.item.vis {
277 syn::Visibility::Public(vis_public) => Visibility::Public(*vis_public),
278 syn::Visibility::Inherited => Visibility::Inherited,
279 _ => unreachable!("encountered invalid visibility for ink! message"),
280 }
281 }
282
283 fn inputs(&self) -> InputsIter<'_> {
284 InputsIter::from(self)
285 }
286
287 fn inputs_span(&self) -> Span {
288 self.item.sig.inputs.span()
289 }
290
291 fn statements(&self) -> &[syn::Stmt] {
292 &self.item.block.stmts
293 }
294
295 fn name(&self) -> Option<&str> {
296 self.name.as_deref()
297 }
298}
299
300impl Message {
301 pub fn attrs(&self) -> &[syn::Attribute] {
303 &self.item.attrs
304 }
305
306 pub fn get_cfg_attrs(&self, span: Span) -> Vec<TokenStream> {
308 extract_cfg_attributes(self.attrs(), span)
309 }
310
311 pub fn get_cfg_syn_attrs(&self) -> Vec<syn::Attribute> {
313 extract_cfg_syn_attributes(self.attrs())
314 }
315
316 pub fn receiver(&self) -> Receiver {
318 match self.item.sig.inputs.iter().next() {
319 Some(syn::FnArg::Receiver(receiver)) => {
320 debug_assert!(receiver.reference.is_some());
321 if receiver.mutability.is_some() {
322 Receiver::RefMut
323 } else {
324 Receiver::Ref
325 }
326 }
327 _ => unreachable!("encountered invalid receiver argument for ink! message"),
328 }
329 }
330
331 pub fn output(&self) -> Option<&syn::Type> {
333 match &self.item.sig.output {
334 syn::ReturnType::Default => None,
335 syn::ReturnType::Type(_, return_type) => Some(return_type),
336 }
337 }
338
339 pub fn wrapped_output(&self) -> syn::Type {
344 let return_type = self
345 .output()
346 .map(quote::ToTokens::to_token_stream)
347 .unwrap_or_else(|| quote::quote! { () });
348
349 syn::parse_quote! {
350 ::ink::MessageResult<#return_type>
351 }
352 }
353
354 pub fn local_id(&self) -> u32 {
363 utils::local_message_id(self.ident())
364 }
365
366 pub fn try_ident(&self) -> Ident {
368 quote::format_ident!("try_{}", self.ident())
369 }
370
371 pub fn name(&self) -> Option<&str> {
373 self.name.as_deref()
374 }
375}
376
377#[cfg(test)]
378mod tests {
379 use super::*;
380
381 #[test]
382 fn output_works() {
383 let test_inputs: Vec<(Option<syn::Type>, syn::ImplItemFn)> = vec![
384 (
385 None,
387 syn::parse_quote! {
388 #[ink(message)]
389 fn my_message(&self) {}
390 },
391 ),
392 (
393 Some(syn::parse_quote! { i32 }),
395 syn::parse_quote! {
396 #[ink(message)]
397 fn my_message(&self) -> i32 {}
398 },
399 ),
400 (
401 Some(syn::parse_quote! { (i32, u64, bool) }),
403 syn::parse_quote! {
404 #[ink(message)]
405 fn my_message(&self) -> (i32, u64, bool) {}
406 },
407 ),
408 ];
409 for (expected_output, item_method) in test_inputs {
410 let actual_output = <ir::Message as TryFrom<_>>::try_from(item_method)
411 .unwrap()
412 .output()
413 .cloned();
414 assert_eq!(actual_output, expected_output);
415 }
416 }
417
418 #[test]
419 fn inputs_works() {
420 macro_rules! expected_input {
421 ( mut $name:ident: $ty:ty ) => {{
422 syn::parse_quote! {
423 mut $name: $ty
424 }
425 }};
426 ( $name:ident: $ty:ty ) => {{
427 syn::parse_quote! {
428 $name: $ty
429 }
430 }};
431 }
432 macro_rules! expected_inputs {
433 ( $( $($ts:ident)+: $ty:ty ),* ) => {{
434 vec![
435 $(
436 expected_input!($($ts)+: $ty)
437 ),*
438 ]
439 }};
440 }
441 let test_inputs: Vec<(Vec<syn::FnArg>, syn::ImplItemFn)> = vec![
442 (
443 expected_inputs!(),
445 syn::parse_quote! {
446 #[ink(message)]
447 fn my_message(&self) {}
448 },
449 ),
450 (
451 expected_inputs!(a: i32),
453 syn::parse_quote! {
454 #[ink(message)]
455 fn my_message(&self, a: i32) {}
456 },
457 ),
458 (
459 expected_inputs!(mut a: i32),
461 syn::parse_quote! {
462 #[ink(message)]
463 fn my_message(&self, mut a: i32) {}
464 },
465 ),
466 (
467 expected_inputs!(a: i32, b: u64, mut c: [u8; 32]),
469 syn::parse_quote! {
470 #[ink(message)]
471 fn my_message(&self, a: i32, b: u64, mut c: [u8; 32]) {}
472 },
473 ),
474 ];
475 for (expected_inputs, item_method) in test_inputs {
476 let actual_inputs = <ir::Message as TryFrom<_>>::try_from(item_method)
477 .unwrap()
478 .inputs()
479 .cloned()
480 .map(syn::FnArg::Typed)
481 .collect::<Vec<_>>();
482 assert_eq!(actual_inputs, expected_inputs);
483 }
484 }
485
486 #[test]
487 fn is_payable_works() {
488 let test_inputs: Vec<(bool, syn::ImplItemFn)> = vec![
489 (
491 false,
492 syn::parse_quote! {
493 #[ink(message)]
494 fn my_message(&self) {}
495 },
496 ),
497 (
499 true,
500 syn::parse_quote! {
501 #[ink(message, payable)]
502 pub fn my_message(&mut self) {}
503 },
504 ),
505 (
507 true,
508 syn::parse_quote! {
509 #[ink(message)]
510 #[ink(payable)]
511 pub fn my_message(&mut self) {}
512 },
513 ),
514 (
516 true,
517 syn::parse_quote! {
518 #[ink(message)]
519 #[ink(selector = 0xDEADBEEF, payable)]
520 pub fn my_message(&mut self) {}
521 },
522 ),
523 ];
524 for (expect_payable, item_method) in test_inputs {
525 let is_payable = <ir::Message as TryFrom<_>>::try_from(item_method)
526 .unwrap()
527 .is_payable();
528 assert_eq!(is_payable, expect_payable);
529 }
530 }
531
532 #[test]
533 fn is_default_works() {
534 let test_inputs: Vec<(bool, syn::ImplItemFn)> = vec![
535 (
537 false,
538 syn::parse_quote! {
539 #[ink(message)]
540 fn my_message(&self) {}
541 },
542 ),
543 (
545 true,
546 syn::parse_quote! {
547 #[ink(message, payable, default)]
548 pub fn my_message(&mut self) {}
549 },
550 ),
551 ];
552 for (expect_default, item_method) in test_inputs {
553 let is_default = <ir::Message as TryFrom<_>>::try_from(item_method)
554 .unwrap()
555 .is_default();
556 assert_eq!(is_default, expect_default);
557 }
558 }
559
560 #[test]
561 fn name_override_works() {
562 let test_inputs: Vec<(Option<&str>, syn::ImplItemFn)> = vec![
563 (
565 None,
566 syn::parse_quote! {
567 #[ink(message)]
568 fn my_message(&self) {}
569 },
570 ),
571 (
573 Some("myMessage"),
574 syn::parse_quote! {
575 #[ink(message, name = "myMessage")]
576 pub fn my_message(&mut self) {}
577 },
578 ),
579 ];
580 for (expected_name, item_method) in test_inputs {
581 let message = <ir::Message as TryFrom<_>>::try_from(item_method).unwrap();
582 assert_eq!(message.name(), expected_name);
583 }
584 }
585
586 #[test]
587 fn receiver_works() {
588 let test_inputs: Vec<(Receiver, syn::ImplItemFn)> = vec![
589 (
590 Receiver::Ref,
591 syn::parse_quote! {
592 #[ink(message)]
593 fn my_message(&self) {}
594 },
595 ),
596 (
597 Receiver::RefMut,
598 syn::parse_quote! {
599 #[ink(message, payable)]
600 fn my_message(&mut self) {}
601 },
602 ),
603 ];
604 for (expected_receiver, item_method) in test_inputs {
605 let actual_receiver = <ir::Message as TryFrom<_>>::try_from(item_method)
606 .unwrap()
607 .receiver();
608 assert_eq!(actual_receiver, expected_receiver);
609 }
610 }
611
612 #[test]
613 fn visibility_works() {
614 let test_inputs: Vec<(bool, syn::ImplItemFn)> = vec![
615 (
617 false,
618 syn::parse_quote! {
619 #[ink(message)]
620 fn my_message(&self) {}
621 },
622 ),
623 (
625 true,
626 syn::parse_quote! {
627 #[ink(message)]
628 pub fn my_message(&self) {}
629 },
630 ),
631 (
633 false,
634 syn::parse_quote! {
635 #[ink(message)]
636 fn my_message(&mut self) {}
637 },
638 ),
639 (
641 true,
642 syn::parse_quote! {
643 #[ink(message)]
644 pub fn my_message(&mut self) {}
645 },
646 ),
647 ];
648 for (is_pub, item_method) in test_inputs {
649 let visibility = <ir::Message as TryFrom<_>>::try_from(item_method)
650 .unwrap()
651 .visibility();
652 assert_eq!(visibility.is_pub(), is_pub);
653 assert_eq!(visibility.is_inherited(), !is_pub);
654 }
655 }
656
657 #[test]
658 fn try_from_works() {
659 let item_methods: Vec<syn::ImplItemFn> = vec![
660 syn::parse_quote! {
662 #[ink(message)]
663 fn my_message(&self) {}
664 },
665 syn::parse_quote! {
667 #[ink(message)]
668 pub fn my_message(&self) {}
669 },
670 syn::parse_quote! {
672 #[ink(message)]
673 fn my_message(&mut self) {}
674 },
675 syn::parse_quote! {
677 #[ink(message)]
678 pub fn my_message(&mut self) {}
679 },
680 syn::parse_quote! {
682 #[ink(message, payable)]
683 fn my_message(&mut self) {}
684 },
685 syn::parse_quote! {
687 #[ink(message, payable)]
688 fn my_message(&mut self) {}
689 },
690 syn::parse_quote! {
692 #[ink(message)]
693 fn my_message(&self, input1: i32, input2: i64, input3: u32, input4: u64) -> bool {}
694 },
695 syn::parse_quote! {
697 #[ink(message)]
698 fn my_message(&mut self, input1: i32, input2: i64, input3: u32, input4: u64) -> bool {}
699 },
700 ];
701 for item_method in item_methods {
702 assert!(<ir::Message as TryFrom<_>>::try_from(item_method).is_ok());
703 }
704 }
705
706 fn assert_try_from_fails(item_method: syn::ImplItemFn, expected_err: &str) {
707 assert_eq!(
708 <ir::Message as TryFrom<_>>::try_from(item_method)
709 .map_err(|err| err.to_string()),
710 Err(expected_err.to_string()),
711 );
712 }
713
714 #[test]
715 fn try_from_generics_fails() {
716 let item_methods: Vec<syn::ImplItemFn> = vec![
717 syn::parse_quote! {
718 #[ink(message)]
719 fn my_message<T>(&self) {}
720 },
721 syn::parse_quote! {
722 #[ink(message)]
723 pub fn my_message<T>(&self) {}
724 },
725 syn::parse_quote! {
726 #[ink(message)]
727 fn my_message<T>(&mut self) {}
728 },
729 syn::parse_quote! {
730 #[ink(message)]
731 pub fn my_message<T>(&mut self) {}
732 },
733 ];
734 for item_method in item_methods {
735 assert_try_from_fails(item_method, "ink! messages must not be generic")
736 }
737 }
738
739 #[test]
740 fn try_from_receiver_fails() {
741 let item_methods: Vec<syn::ImplItemFn> = vec![
742 syn::parse_quote! {
743 #[ink(message)]
744 fn my_message() {}
745 },
746 syn::parse_quote! {
747 #[ink(message)]
748 fn my_message(self) {}
749 },
750 syn::parse_quote! {
751 #[ink(message)]
752 pub fn my_message(mut self) {}
753 },
754 syn::parse_quote! {
755 #[ink(message)]
756 fn my_message(this: &Self) {}
757 },
758 syn::parse_quote! {
759 #[ink(message)]
760 pub fn my_message(this: &mut Self) {}
761 },
762 ];
763 for item_method in item_methods {
764 assert_try_from_fails(
765 item_method,
766 "ink! messages must have `&self` or `&mut self` receiver",
767 )
768 }
769 }
770
771 #[test]
772 fn try_from_const_fails() {
773 let item_methods: Vec<syn::ImplItemFn> = vec![
774 syn::parse_quote! {
776 #[ink(message)]
777 const fn my_message(&self) {}
778 },
779 syn::parse_quote! {
781 #[ink(message)]
782 const fn my_message(&mut self) {}
783 },
784 ];
785 for item_method in item_methods {
786 assert_try_from_fails(item_method, "ink! messages must not be const")
787 }
788 }
789
790 #[test]
791 fn try_from_async_fails() {
792 let item_methods: Vec<syn::ImplItemFn> = vec![
793 syn::parse_quote! {
795 #[ink(message)]
796 async fn my_message(&self) {}
797 },
798 syn::parse_quote! {
800 #[ink(message)]
801 async fn my_message(&mut self) {}
802 },
803 ];
804 for item_method in item_methods {
805 assert_try_from_fails(item_method, "ink! messages must not be async")
806 }
807 }
808
809 #[test]
810 fn try_from_unsafe_fails() {
811 let item_methods: Vec<syn::ImplItemFn> = vec![
812 syn::parse_quote! {
814 #[ink(message)]
815 unsafe fn my_message(&self) {}
816 },
817 syn::parse_quote! {
819 #[ink(message)]
820 unsafe fn my_message(&mut self) {}
821 },
822 ];
823 for item_method in item_methods {
824 assert_try_from_fails(item_method, "ink! messages must not be unsafe")
825 }
826 }
827
828 #[test]
829 fn try_from_explicit_abi_fails() {
830 let item_methods: Vec<syn::ImplItemFn> = vec![
831 syn::parse_quote! {
833 #[ink(message)]
834 extern "C" fn my_message(&self) {}
835 },
836 syn::parse_quote! {
838 #[ink(message)]
839 extern "C" fn my_message(&mut self) {}
840 },
841 ];
842 for item_method in item_methods {
843 assert_try_from_fails(item_method, "ink! messages must not have explicit ABI")
844 }
845 }
846
847 #[test]
848 fn try_from_variadic_fails() {
849 let item_methods: Vec<syn::ImplItemFn> = vec![
850 syn::parse_quote! {
852 #[ink(message)]
853 fn my_message(&self, ...) {}
854 },
855 syn::parse_quote! {
857 #[ink(message)]
858 fn my_message(&mut self, ...) {}
859 },
860 ];
861 for item_method in item_methods {
862 assert_try_from_fails(item_method, "ink! messages must not be variadic")
863 }
864 }
865
866 #[test]
867 fn try_from_visibility_fails() {
868 let item_methods: Vec<syn::ImplItemFn> = vec![
869 syn::parse_quote! {
871 #[ink(message)]
872 pub(crate) fn my_message(&self) {}
873 },
874 syn::parse_quote! {
876 #[ink(message)]
877 pub(crate) fn my_message(&mut self) {}
878 },
879 syn::parse_quote! {
881 #[ink(message)]
882 pub(in my::path) fn my_message(&self) {}
883 },
884 syn::parse_quote! {
886 #[ink(message)]
887 pub(in my::path) fn my_message(&mut self) {}
888 },
889 ];
890 for item_method in item_methods {
891 assert_try_from_fails(
892 item_method,
893 "ink! messages must have public or inherited visibility",
894 )
895 }
896 }
897
898 #[test]
899 fn conflicting_attributes_fails() {
900 let item_methods: Vec<syn::ImplItemFn> = vec![
901 syn::parse_quote! {
903 #[ink(message, storage)]
904 fn my_message(&self) {}
905 },
906 syn::parse_quote! {
908 #[ink(message, namespace = "my_namespace")]
909 fn my_message(&self) {}
910 },
911 syn::parse_quote! {
913 #[ink(message)]
914 #[ink(event)]
915 fn my_message(&self) {}
916 },
917 ];
918 for item_method in item_methods {
919 assert_try_from_fails(
920 item_method,
921 "encountered conflicting ink! attribute argument",
922 )
923 }
924 }
925}