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
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! Augments `syn`'s AST with helper methods to deal with Near SDK definitions.

use syn::{
    Attribute, FnArg, ImplItem, ImplItemMethod, ItemEnum, ItemImpl, ItemStruct, Meta, MetaList,
    NestedMeta, Visibility,
};

/// Defines standard attributes found in the Near SDK.
pub trait NearImpl {
    /// Returns whether the given `self` implementation is marked as `near_bindgen`.
    fn is_bindgen(&self) -> bool;

    /// Returns whether the given `self` implementation has any exported method.
    fn has_exported_methods(&self) -> bool;
}

impl NearImpl for ItemImpl {
    fn is_bindgen(&self) -> bool {
        has_attr(&self.attrs, "near_bindgen")
    }

    fn has_exported_methods(&self) -> bool {
        for impl_item in self.items.iter() {
            if let ImplItem::Method(method) = impl_item {
                if method.is_exported(self) {
                    return true;
                }
            }
        }
        false
    }
}

/// Defines standard attributes and helper methods used when exporting a contract.
pub trait NearMethod {
    /// Returns whether the given `self` method is declared as `pub`.
    fn is_public(&self) -> bool;

    /// Returns whether the given `self` method is declared as `mut`.
    fn is_mut(&self) -> bool;

    /// Returns whether the given `self` method is marked as `init`.
    fn is_init(&self) -> bool;

    /// Returns whether the given `self` method is marked as `payable`.
    fn is_payable(&self) -> bool;

    /// Returns whether the given `self` method is marked as `private`.
    fn is_private(&self) -> bool;

    /// Returns whether the given `self` method in `input` impl is being exported.
    fn is_exported(&self, input: &ItemImpl) -> bool;
}

impl NearMethod for ImplItemMethod {
    fn is_public(self: &ImplItemMethod) -> bool {
        match self.vis {
            Visibility::Public(_) => true,
            _ => false,
        }
    }

    fn is_mut(&self) -> bool {
        if let Some(FnArg::Receiver(r)) = self.sig.inputs.iter().next() {
            r.mutability.is_some()
        } else {
            false
        }
    }

    fn is_init(&self) -> bool {
        has_attr(&self.attrs, "init")
    }

    fn is_payable(&self) -> bool {
        has_attr(&self.attrs, "payable")
    }

    fn is_private(self: &ImplItemMethod) -> bool {
        has_attr(&self.attrs, "private")
    }

    fn is_exported(&self, input: &ItemImpl) -> bool {
        (self.is_public() || input.trait_.is_some()) && !self.is_private()
    }
}

/// Defines methods to deal with serde's declarations in `struct`s or `enum`s.
pub trait NearSerde {
    /// Returns whether the given `self` item derives `serde::Serialize`.
    fn is_serialize(&self) -> bool;

    /// Returns whether the given `self` item derives `serde::Deserialize`.
    fn is_deserialize(&self) -> bool;

    /// Returns whether the given `self` item derives either `serde::Serialize` or `serde::Deserialize`.
    fn is_serde(&self) -> bool;
}

impl<I: NearAttributable> NearSerde for I {
    fn is_serialize(&self) -> bool {
        derives(&self.attrs(), "Serialize")
    }

    fn is_deserialize(&self) -> bool {
        derives(&self.attrs(), "Deserialize")
    }

    fn is_serde(&self) -> bool {
        self.is_serialize() || self.is_deserialize()
    }
}

/// Any Rust item, *e.g.*, `struct` or `enum` to which attributes can attached to.
pub trait NearAttributable {
    /// The attributes of this item.
    fn attrs(&self) -> &Vec<Attribute>;
}

impl NearAttributable for ItemStruct {
    fn attrs(&self) -> &Vec<Attribute> {
        &self.attrs
    }
}

impl NearAttributable for ItemEnum {
    fn attrs(&self) -> &Vec<Attribute> {
        &self.attrs
    }
}

/// Returns `true` if `attrs` contain `attr_name`.
/// Returns `false` otherwise.
fn has_attr(attrs: &Vec<Attribute>, attr_name: &str) -> bool {
    for attr in attrs {
        if attr.path.is_ident(attr_name) {
            return true;
        }
    }
    false
}

/// Returns `true` if any of the attributes under item derive from `macro_name`.
/// Returns `false` otherwise.
fn derives(attrs: &Vec<Attribute>, macro_name: &str) -> bool {
    for attr in attrs {
        if attr.path.is_ident("derive") {
            if let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() {
                for elem in nested {
                    if let NestedMeta::Meta(meta) = elem {
                        if meta.path().is_ident(macro_name) {
                            return true;
                        }
                    }
                }
            } else {
                panic!("not expected");
            }
        }
    }
    false
}