1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//! ink! trait definition IR.

use ink_analyzer_macro::{FromInkAttribute, FromSyntax};
use ra_ap_syntax::ast;

use crate::traits::{FromInkAttribute, FromSyntax, IsInkTrait};
use crate::tree::utils;
use crate::{InkArg, InkArgKind, InkAttrData, InkAttribute, Message};

/// An ink! trait definition.
#[derive(Debug, Clone, PartialEq, Eq, FromInkAttribute, FromSyntax)]
pub struct TraitDefinition {
    /// ink! attribute IR data.
    #[macro_kind(TraitDefinition)]
    ink_attr: InkAttrData<ast::Trait>,
    /// ink! messages.
    #[arg_kind(Message)]
    messages: Vec<Message>,
}

impl IsInkTrait for TraitDefinition {
    fn trait_item(&self) -> Option<&ast::Trait> {
        self.ink_attr.parent_ast()
    }
}

impl TraitDefinition {
    /// Returns the ink! namespace argument (if any) for the ink! trait definition.
    pub fn namespace_arg(&self) -> Option<InkArg> {
        utils::ink_arg_by_kind(self.syntax(), InkArgKind::Namespace)
    }

    /// Returns the ink! `keep_attr` argument (if any) for the ink! trait definition.
    pub fn keep_attr_arg(&self) -> Option<InkArg> {
        utils::ink_arg_by_kind(self.syntax(), InkArgKind::KeepAttr)
    }

    /// Returns the ink! messages for the ink! trait definition.
    pub fn messages(&self) -> &[Message] {
        &self.messages
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test_utils::*;
    use test_utils::quote_as_str;

    #[test]
    fn cast_works() {
        let ink_attr = parse_first_ink_attribute(quote_as_str! {
            #[ink::trait_definition(namespace="my_namespace", keep_attr="foo,bar")]
            pub trait MyTrait {
                #[ink(message)]
                fn my_message(&self);

                #[ink(message)]
                fn my_message_mut(&mut self);
            }
        });

        let trait_definition = TraitDefinition::cast(ink_attr).unwrap();

        // `namespace` argument exists.
        assert!(trait_definition.namespace_arg().is_some());

        // `keep_attr` argument exists.
        assert!(trait_definition.keep_attr_arg().is_some());

        // 2 messages.
        assert_eq!(trait_definition.messages().len(), 2);

        // `trait` item exists.
        assert!(trait_definition.trait_item().is_some());
    }
}