ink_ir/ir/storage_item/
config.rs1use syn::spanned::Spanned;
16
17use crate::{
18 ast,
19 utils::duplicate_config_err,
20};
21
22#[derive(Debug, PartialEq, Eq)]
24pub struct StorageItemConfig {
25 packed: bool,
29 derive: bool,
34}
35
36impl Default for StorageItemConfig {
37 fn default() -> Self {
38 Self {
39 packed: false,
40 derive: true,
41 }
42 }
43}
44
45impl TryFrom<ast::AttributeArgs> for StorageItemConfig {
46 type Error = syn::Error;
47
48 fn try_from(args: ast::AttributeArgs) -> Result<Self, Self::Error> {
49 let mut packed: Option<syn::Path> = None;
50 let mut derive: Option<syn::LitBool> = None;
51 let args_span = args.span();
52 for arg in args {
53 if arg.name().is_ident("packed") {
54 if let Some(path) = packed {
55 return Err(duplicate_config_err(path, arg, "packed", "storage item"));
56 }
57 if let ast::Meta::Path(path) = arg {
58 packed = Some(path)
59 } else {
60 return Err(format_err_spanned!(
61 arg,
62 "encountered an unexpected value for `packed` ink! storage item configuration argument. \
63 Did you mean `#[ink::storage_item(packed)]` ?",
64 ));
65 }
66 } else if arg.name().is_ident("derive") {
67 if let Some(lit_bool) = derive {
68 return Err(duplicate_config_err(
69 lit_bool,
70 arg,
71 "derive",
72 "storage item",
73 ));
74 }
75 if let Some(lit_bool) = arg.value().and_then(ast::MetaValue::as_lit_bool)
76 {
77 derive = Some(lit_bool.clone())
78 } else {
79 return Err(format_err_spanned!(
80 arg,
81 "expected a bool literal value for `derive` ink! storage item configuration argument",
82 ));
83 }
84 } else {
85 return Err(format_err_spanned!(
86 arg,
87 "encountered unknown or unsupported ink! storage item configuration argument",
88 ));
89 }
90 }
91
92 let (packed, derive) = match (packed, derive.map(|lit_bool| lit_bool.value)) {
94 (Some(_), Some(false)) => {
97 return Err(format_err!(
98 args_span,
99 "cannot use `derive = false` with `packed` flag",
100 ))
101 }
102 (packed, derive) => (packed.is_some(), derive.unwrap_or(true)),
106 };
107
108 Ok(StorageItemConfig { packed, derive })
109 }
110}
111
112impl StorageItemConfig {
113 pub fn packed(&self) -> bool {
115 self.packed
116 }
117
118 pub fn derive(&self) -> bool {
120 self.derive
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use quote::quote;
128
129 #[test]
130 fn valid_args_works() {
131 for (config, packed, derive) in [
132 (quote!(), false, true),
135 (quote! { packed }, true, true),
137 (quote! { packed, derive = true }, true, true),
138 (quote! { derive = true }, false, true),
141 (quote! { derive = false }, false, false),
142 ] {
143 let parsed_config = syn::parse2::<crate::ast::AttributeArgs>(config).unwrap();
144 let result = StorageItemConfig::try_from(parsed_config);
145 assert!(result.is_ok());
146 let storage_item_config = result.unwrap();
147 assert_eq!(storage_item_config.packed(), packed);
148 assert_eq!(storage_item_config.derive(), derive);
149 }
150 }
151
152 #[test]
153 #[should_panic = "cannot use `derive = false` with `packed` flag"]
154 fn conflicting_args_fails() {
155 let config = quote! {
156 packed, derive = false
158 };
159 let parsed_config = syn::parse2::<crate::ast::AttributeArgs>(config).unwrap();
160 StorageItemConfig::try_from(parsed_config).unwrap();
161 }
162
163 #[test]
164 #[should_panic = "encountered an unexpected value for `packed` ink! storage item configuration argument. Did you mean `#[ink::storage_item(packed)]` ?"]
165 fn invalid_packed_value_fails() {
166 let config = quote! {
167 packed = true
169 };
170 let parsed_config = syn::parse2::<crate::ast::AttributeArgs>(config).unwrap();
171 StorageItemConfig::try_from(parsed_config).unwrap();
172 }
173}