1pub use syner_derive::Syner;
2
3pub mod __private {
4 pub use proc_macro2;
5 pub use syn;
6}
7
8pub trait Syner {
9 fn parse_attrs<'a>(
11 attrs: impl IntoIterator<Item = &'a syn::Attribute> + 'a,
12 ) -> Result<Self, Vec<syn::Error>>
13 where
14 Self: Sized;
15
16 fn parse_meta(input: &syn::Meta) -> Result<Self, Vec<syn::Error>>
18 where
19 Self: Sized;
20
21 fn expected() -> String;
23
24 fn expected_meta() -> String;
26
27 fn name() -> &'static str;
29}
30
31#[cfg(test)]
32mod tests {
33 use syn::{parse_quote, DeriveInput};
34
35 use super::*;
36
37 mod syner {
39 pub use crate::Syner;
40 pub use crate::__private;
41 }
42
43 #[derive(Syner)]
44 #[syner(name = "test_attribute")]
45 struct Test {
46 pub some: String,
47 pub maybe: Option<String>,
48 #[syner(default)]
49 pub is_default: bool,
50 #[syner(default = "String::from(\"default\")")]
51 pub default: String,
52 pub inner: Inner,
53 pub inner_list: Vec<Inner>,
54 pub inner_bools: Vec<bool>,
55 pub inner_maybe: Option<Inner>,
56 }
57
58 #[derive(Syner, PartialEq, Debug)]
59 struct Inner {
60 pub some: String,
61 pub is_default: bool,
62 }
63
64 #[test]
65 fn test_correct() {
66 let input: DeriveInput = parse_quote! {
67 #[test_attribute(
68 some = "hello",
69 inner(
70 some = "inner",
71 is_default = true
72 ),
73 inner_list(
74 inner(
75 some = "inner_list0",
76 is_default = true
77 ),
78 inner(
79 some = "inner_list1",
80 is_default = false
81 ),
82 inner(
83 some = "inner_list2",
84 is_default = true
85 )
86 ),
87 inner_bools(true, false, true)
88 )]
89 struct Test;
90 };
91 let test = Test::parse_attrs(&input.attrs).unwrap();
92 assert_eq!(test.some, "hello");
93 assert_eq!(test.maybe, None);
94 assert_eq!(test.is_default, false);
95 assert_eq!(test.default, "default");
96 assert_eq!(test.inner.some, "inner");
97 assert_eq!(test.inner.is_default, true);
98 assert_eq!(test.inner_list.len(), 3);
99 assert_eq!(test.inner_list[0].some, "inner_list0");
100 assert_eq!(test.inner_list[0].is_default, true);
101 assert_eq!(test.inner_list[1].some, "inner_list1");
102 assert_eq!(test.inner_list[1].is_default, false);
103 assert_eq!(test.inner_list[2].some, "inner_list2");
104 assert_eq!(test.inner_list[2].is_default, true);
105 assert_eq!(test.inner_bools.len(), 3);
106 assert_eq!(test.inner_bools[0], true);
107 assert_eq!(test.inner_bools[1], false);
108 assert_eq!(test.inner_bools[2], true);
109 assert_eq!(test.inner_maybe, None);
110 }
111
112 #[test]
113 fn test_duplicate() {
114 let input: DeriveInput = parse_quote! {
115 #[test_attribute(
116 some = "hello",
117 some = "hello",
118 inner(
119 some = "inner",
120 is_default = true
121 ),
122 inner(
123 some = "inner",
124 is_default = true
125 )
126 )]
127 struct Test;
128 };
129 let test = Test::parse_attrs(&input.attrs);
130 assert!(test.is_err());
131 assert_eq!(test.err().unwrap().len(), 2);
132 }
133
134 #[test]
135 fn test_missing() {
136 let input: DeriveInput = parse_quote! {
137 #[test_attribute(
138 inner(
139 some = "inner",
140 is_default = true
141 ),
142 inner_list(
143 inner(
144 some = "inner_list0",
145 is_default = true
146 ),
147 inner(
148 some = "inner_list1",
149 is_default = false
150 ),
151 inner(
152 some = "inner_list2",
153 is_default = true
154 )
155 ),
156 inner_bools(true, false, true)
157 )]
158 struct Test;
159 };
160 let test = Test::parse_attrs(&input.attrs);
161 assert!(test.is_err());
162 assert_eq!(test.err().unwrap().len(), 1);
163 }
164
165 #[test]
166 fn test_wrong_type() {
167 let input: DeriveInput = parse_quote! {
168 #[test_attribute(
169 some = "hello",
170 inner(
171 some = "inner",
172 is_default = true
173 ),
174 inner_list(
175 inner(
176 some = "inner_list0",
177 is_default = true
178 ),
179 inner(
180 some = "inner_list1",
181 is_default = false
182 ),
183 inner(
184 some = "inner_list2",
185 is_default = true
186 )
187 ),
188 inner_bools(true, false, true),
189 inner_maybe = "hello"
190 )]
191 struct Test;
192 };
193 let test = Test::parse_attrs(&input.attrs);
194 assert!(test.is_err());
195 assert_eq!(test.err().unwrap().len(), 1);
196 }
197
198 #[test]
199 fn test_wrong_type_meta() {
200 let input: DeriveInput = parse_quote! {
201 #[test_attribute(
202 some = "hello",
203 inner(
204 some = "inner",
205 is_default = true
206 ),
207 inner_list(
208 inner(
209 some = "inner_list0",
210 is_default = true
211 ),
212 inner(
213 some = "inner_list1",
214 is_default = false
215 ),
216 inner(
217 some = "inner_list2",
218 is_default = true
219 )
220 ),
221 inner_bools(meta(true), false, true),
222 )]
223 struct Test;
224 };
225 let test = Test::parse_attrs(&input.attrs);
226 assert!(test.is_err());
227 assert_eq!(test.err().unwrap().len(), 1);
228 }
229}