1use crate::{
16 ast,
17 utils::{
18 duplicate_config_err,
19 WhitelistedAttributes,
20 },
21};
22
23#[derive(Debug, Default, PartialEq, Eq)]
25pub struct Config {
26 env: Option<Environment>,
32 whitelisted_attributes: WhitelistedAttributes,
34}
35
36impl TryFrom<ast::AttributeArgs> for Config {
37 type Error = syn::Error;
38
39 fn try_from(args: ast::AttributeArgs) -> Result<Self, Self::Error> {
40 let mut env: Option<(Environment, ast::MetaNameValue)> = None;
41 let mut whitelisted_attributes = WhitelistedAttributes::default();
42
43 for arg in args.into_iter() {
44 if arg.name().is_ident("env") {
45 if let Some((_, ast)) = env {
46 return Err(duplicate_config_err(ast, arg, "env", "contract"));
47 }
48 let env_info = arg
49 .name_value()
50 .zip(arg.value().and_then(ast::MetaValue::as_path));
51 if let Some((name_value, path)) = env_info {
52 env = Some((Environment { path: path.clone() }, name_value.clone()))
53 } else {
54 return Err(format_err_spanned!(
55 arg,
56 "expected a path value for `env` ink! configuration argument",
57 ));
58 }
59 } else if arg.name().is_ident("keep_attr") {
60 if let Some(name_value) = arg.name_value() {
61 whitelisted_attributes.parse_arg_value(name_value)?;
62 } else {
63 return Err(format_err_spanned!(
64 arg,
65 "expected a string literal value for `keep_attr` ink! configuration argument",
66 ));
67 }
68 } else {
69 return Err(format_err_spanned!(
70 arg,
71 "encountered unknown or unsupported ink! configuration argument",
72 ));
73 }
74 }
75 Ok(Config {
76 env: env.map(|(value, _)| value),
77 whitelisted_attributes,
78 })
79 }
80}
81
82impl Config {
83 pub fn env(&self) -> syn::Path {
87 self.env
88 .as_ref()
89 .map(|env| &env.path)
90 .cloned()
91 .unwrap_or(Environment::default().path)
92 }
93
94 pub fn whitelisted_attributes(&self) -> &WhitelistedAttributes {
96 &self.whitelisted_attributes
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
102pub struct Environment {
103 pub path: syn::Path,
105}
106
107impl Default for Environment {
108 fn default() -> Self {
109 Self {
110 path: syn::parse_quote! { ::ink::env::DefaultEnvironment },
111 }
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 fn assert_try_from(
122 input: ast::AttributeArgs,
123 expected: Result<Config, &'static str>,
124 ) {
125 assert_eq!(
126 <Config as TryFrom<ast::AttributeArgs>>::try_from(input)
127 .map_err(|err| err.to_string()),
128 expected.map_err(ToString::to_string),
129 );
130 }
131
132 #[test]
133 fn empty_config_works() {
134 assert_try_from(syn::parse_quote! {}, Ok(Config::default()))
135 }
136
137 #[test]
138 fn env_works() {
139 assert_try_from(
140 syn::parse_quote! {
141 env = ::my::env::Types
142 },
143 Ok(Config {
144 env: Some(Environment {
145 path: syn::parse_quote! { ::my::env::Types },
146 }),
147 whitelisted_attributes: Default::default(),
148 }),
149 )
150 }
151
152 #[test]
153 fn env_invalid_value_fails() {
154 assert_try_from(
155 syn::parse_quote! { env = "invalid" },
156 Err("expected a path value for `env` ink! configuration argument"),
157 );
158 }
159
160 #[test]
161 fn env_missing_value_fails() {
162 assert_try_from(
163 syn::parse_quote! { env },
164 Err("expected a path value for `env` ink! configuration argument"),
165 );
166 }
167
168 #[test]
169 fn unknown_arg_fails() {
170 assert_try_from(
171 syn::parse_quote! { unknown = argument },
172 Err("encountered unknown or unsupported ink! configuration argument"),
173 );
174 }
175
176 #[test]
177 fn duplicate_args_fails() {
178 assert_try_from(
179 syn::parse_quote! {
180 env = ::my::env::Types,
181 env = ::my::other::env::Types,
182 },
183 Err("encountered duplicate ink! contract `env` configuration argument"),
184 );
185 }
186
187 #[test]
188 fn keep_attr_works() {
189 let mut attrs = WhitelistedAttributes::default();
190 attrs.0.insert("foo".to_string(), ());
191 attrs.0.insert("bar".to_string(), ());
192 assert_try_from(
193 syn::parse_quote! {
194 keep_attr = "foo, bar"
195 },
196 Ok(Config {
197 env: None,
198 whitelisted_attributes: attrs,
199 }),
200 )
201 }
202
203 #[test]
204 fn keep_attr_invalid_value_fails() {
205 assert_try_from(
206 syn::parse_quote! { keep_attr = 1u16 },
207 Err("expected a string with attributes separated by `,`"),
208 );
209 }
210
211 #[test]
212 fn keep_attr_missing_value_fails() {
213 assert_try_from(
214 syn::parse_quote! { keep_attr },
215 Err("expected a string literal value for `keep_attr` ink! configuration argument"),
216 );
217 }
218}