1use proc_macro2::{TokenStream, TokenTree};
7
8use crate::{
9 generate::{
10 arrow, braces, brackets, fat_arrow, ident, literal_str, literal_usize, parens, path, path_sep, punct,
11 punct_joint, underscore,
12 },
13 parse::{ParsedField, ParsedStruct},
14};
15
16pub fn expand(parsed: ParsedStruct) -> TokenStream {
18 let struct_name = parsed.name.to_string();
19 let struct_name_lit = literal_str(&struct_name);
20 let crate_path = &parsed.crate_path;
21
22 let mut tokens = Vec::new();
23
24 tokens.push(ident("impl"));
26 tokens.extend(path(&["", crate_path, "FromFrame"]));
27 tokens.push(ident("for"));
28 tokens.push(TokenTree::Ident(parsed.name.clone()));
29
30 let impl_body = generate_from_frame_impl(&parsed.fields, &struct_name_lit, crate_path);
32 tokens.push(braces(impl_body));
33
34 tokens.into_iter().collect()
38}
39
40fn generate_from_frame_impl(fields: &[ParsedField], struct_name_lit: &TokenTree, crate_path: &str) -> Vec<TokenTree> {
42 let mut tokens = Vec::new();
43
44 tokens.push(ident("fn"));
46 tokens.push(ident("from_frame"));
47 tokens.push(parens([ident("frame"), punct(':'), punct('&')]
48 .into_iter()
49 .chain(path(&["", crate_path, "Frame"]))));
50 tokens.extend(arrow());
51 tokens.push(ident("Result"));
52 tokens.push(punct('<'));
53 tokens.push(ident("Vec"));
54 tokens.push(punct('<'));
55 tokens.push(ident("Self"));
56 tokens.push(punct('>'));
57 tokens.push(punct(','));
58 tokens.extend(path(&["", crate_path, "FromFrameError"]));
59 tokens.push(punct('>'));
60
61 let mut body = Vec::new();
63
64 for field in fields {
66 if field.attrs.skip {
67 continue;
68 }
69 body.extend(generate_column_lookup(field, struct_name_lit, crate_path));
70 }
71
72 body.push(ident("let"));
74 body.push(ident("row_count"));
75 body.push(punct('='));
76 body.push(ident("frame"));
77 body.push(punct('.'));
78 body.push(ident("columns"));
79 body.push(punct('.'));
80 body.push(ident("first"));
81 body.push(parens([]));
82 body.push(punct('.'));
83 body.push(ident("map"));
84 body.push(parens([
85 punct('|'),
86 ident("c"),
87 punct('|'),
88 ident("c"),
89 punct('.'),
90 ident("data"),
91 punct('.'),
92 ident("len"),
93 parens([]),
94 ]));
95 body.push(punct('.'));
96 body.push(ident("unwrap_or"));
97 body.push(parens([literal_usize(0)]));
98 body.push(punct(';'));
99
100 for field in fields {
102 if field.attrs.skip {
103 continue;
104 }
105 body.extend(generate_field_extraction(field, crate_path));
106 }
107
108 body.push(ident("let"));
110 body.push(ident("mut"));
111 body.push(ident("result"));
112 body.push(punct('='));
113 body.push(ident("Vec"));
114 body.extend(path_sep());
115 body.push(ident("with_capacity"));
116 body.push(parens([ident("row_count")]));
117 body.push(punct(';'));
118
119 body.push(ident("for"));
121 body.push(ident("i"));
122 body.push(ident("in"));
123 body.push(literal_usize(0));
124 body.extend([punct_joint('.'), punct('.')]);
125 body.push(ident("row_count"));
126
127 let mut loop_body = Vec::new();
129 loop_body.push(ident("result"));
130 loop_body.push(punct('.'));
131 loop_body.push(ident("push"));
132
133 let mut constructor = vec![ident("Self")];
135 let mut field_inits = Vec::new();
136 for (i, field) in fields.iter().enumerate() {
137 if i > 0 {
138 field_inits.push(punct(','));
139 }
140 field_inits.push(TokenTree::Ident(field.name.clone()));
141 field_inits.push(punct(':'));
142 if field.attrs.skip {
143 field_inits.extend(path(&["", "std", "default", "Default", "default"]));
144 field_inits.push(parens([]));
145 } else {
146 let values_var = format!("values_{}", field.safe_name());
147 field_inits.push(ident(&values_var));
148 field_inits.push(brackets([ident("i")]));
149 field_inits.push(punct('.'));
150 field_inits.push(ident("clone"));
151 field_inits.push(parens([]));
152 }
153 }
154 constructor.push(braces(field_inits));
155 loop_body.push(parens(constructor));
156 loop_body.push(punct(';'));
157
158 body.push(braces(loop_body));
159
160 body.push(ident("Ok"));
162 body.push(parens([ident("result")]));
163
164 tokens.push(braces(body));
165 tokens
166}
167
168fn generate_column_lookup(field: &ParsedField, struct_name_lit: &TokenTree, crate_path: &str) -> Vec<TokenTree> {
170 let mut tokens = Vec::new();
171 let column_name = field.column_name();
172 let col_var = format!("col_{}", field.safe_name());
173
174 tokens.push(ident("let"));
175 tokens.push(ident(&col_var));
176 tokens.push(punct(':'));
177
178 if field.attrs.optional {
179 tokens.push(ident("Option"));
181 tokens.push(punct('<'));
182 tokens.push(punct('&'));
183 tokens.extend(path(&["", crate_path, "FrameColumn"]));
184 tokens.push(punct('>'));
185 tokens.push(punct('='));
186 tokens.push(ident("frame"));
187 tokens.push(punct('.'));
188 tokens.push(ident("columns"));
189 tokens.push(punct('.'));
190 tokens.push(ident("iter"));
191 tokens.push(parens([]));
192 tokens.push(punct('.'));
193 tokens.push(ident("find"));
194 tokens.push(parens([
195 punct('|'),
196 ident("c"),
197 punct('|'),
198 ident("c"),
199 punct('.'),
200 ident("name"),
201 punct_joint('='),
202 punct('='),
203 literal_str(&column_name),
204 ]));
205 } else {
206 tokens.push(punct('&'));
208 tokens.extend(path(&["", crate_path, "FrameColumn"]));
209 tokens.push(punct('='));
210 tokens.push(ident("frame"));
211 tokens.push(punct('.'));
212 tokens.push(ident("columns"));
213 tokens.push(punct('.'));
214 tokens.push(ident("iter"));
215 tokens.push(parens([]));
216 tokens.push(punct('.'));
217 tokens.push(ident("find"));
218 tokens.push(parens([
219 punct('|'),
220 ident("c"),
221 punct('|'),
222 ident("c"),
223 punct('.'),
224 ident("name"),
225 punct_joint('='),
226 punct('='),
227 literal_str(&column_name),
228 ]));
229 tokens.push(punct('.'));
230 tokens.push(ident("ok_or_else"));
231
232 let mut error_closure = Vec::new();
234 error_closure.extend([punct('|'), punct('|')]);
235 error_closure.extend(path(&["", crate_path, "FromFrameError", "MissingColumn"]));
236 error_closure.push(braces([
237 ident("column"),
238 punct(':'),
239 literal_str(&column_name),
240 punct('.'),
241 ident("to_string"),
242 parens([]),
243 punct(','),
244 ident("struct_name"),
245 punct(':'),
246 struct_name_lit.clone(),
247 punct(','),
248 ]));
249 tokens.push(parens(error_closure));
250 tokens.push(punct('?'));
251 }
252
253 tokens.push(punct(';'));
254 tokens
255}
256
257fn generate_field_extraction(field: &ParsedField, crate_path: &str) -> Vec<TokenTree> {
259 let mut tokens = Vec::new();
260 let column_name = field.column_name();
261 let col_var = format!("col_{}", field.safe_name());
262 let values_var = format!("values_{}", field.safe_name());
263
264 tokens.push(ident("let"));
265 tokens.push(ident(&values_var));
266 tokens.push(punct(':'));
267
268 tokens.push(ident("Vec"));
270 tokens.push(punct('<'));
271 tokens.extend(field.ty.iter().cloned());
272 tokens.push(punct('>'));
273
274 let trait_name = if field.attrs.coerce {
275 "TryFromValueCoerce"
276 } else {
277 "TryFromValue"
278 };
279
280 let method_name = if field.attrs.coerce {
281 "try_from_value_coerce"
282 } else {
283 "try_from_value"
284 };
285
286 if field.attrs.optional {
287 tokens.push(punct('='));
289
290 tokens.push(ident("match"));
292 tokens.push(ident(&col_var));
293
294 let mut match_body = Vec::new();
295
296 match_body.push(ident("Some"));
298 match_body.push(parens([ident("col")]));
299 match_body.extend(fat_arrow());
300
301 let mut some_body = Vec::new();
302 some_body.push(ident("col"));
303 some_body.push(punct('.'));
304 some_body.push(ident("data"));
305 some_body.push(punct('.'));
306 some_body.push(ident("iter"));
307 some_body.push(parens([]));
308 some_body.push(punct('.'));
309 some_body.push(ident("enumerate"));
310 some_body.push(parens([]));
311 some_body.push(punct('.'));
312 some_body.push(ident("map"));
313 some_body.push(parens(generate_optional_map_closure(
314 trait_name,
315 method_name,
316 &column_name,
317 crate_path,
318 )));
319 some_body.push(punct('.'));
320 some_body.push(ident("collect"));
321 some_body.extend(path_sep());
323 some_body.push(punct('<'));
324 some_body.push(ident("Result"));
325 some_body.push(punct('<'));
326 some_body.push(underscore());
327 some_body.push(punct(','));
328 some_body.extend(path(&["", crate_path, "FromFrameError"]));
329 some_body.push(punct('>'));
330 some_body.push(punct('>'));
331 some_body.push(parens([]));
332 some_body.push(punct('?'));
333
334 match_body.push(braces(some_body));
335 match_body.push(punct(','));
336
337 match_body.push(ident("None"));
339 match_body.extend(fat_arrow());
340 match_body.push(ident("vec"));
341 match_body.push(punct('!'));
342 match_body.push(brackets([ident("None"), punct(';'), ident("row_count")]));
343 match_body.push(punct(','));
344
345 tokens.push(braces(match_body));
346 } else {
347 tokens.push(punct('='));
349
350 tokens.push(ident(&col_var));
351 tokens.push(punct('.'));
352 tokens.push(ident("data"));
353 tokens.push(punct('.'));
354 tokens.push(ident("iter"));
355 tokens.push(parens([]));
356 tokens.push(punct('.'));
357 tokens.push(ident("enumerate"));
358 tokens.push(parens([]));
359 tokens.push(punct('.'));
360 tokens.push(ident("map"));
361 tokens.push(parens(generate_required_map_closure(
362 trait_name,
363 method_name,
364 &column_name,
365 &field.ty,
366 crate_path,
367 )));
368 tokens.push(punct('.'));
369 tokens.push(ident("collect"));
370 tokens.extend(path_sep());
372 tokens.push(punct('<'));
373 tokens.push(ident("Result"));
374 tokens.push(punct('<'));
375 tokens.push(underscore());
376 tokens.push(punct(','));
377 tokens.extend(path(&["", crate_path, "FromFrameError"]));
378 tokens.push(punct('>'));
379 tokens.push(punct('>'));
380 tokens.push(parens([]));
381 tokens.push(punct('?'));
382 }
383
384 tokens.push(punct(';'));
385 tokens
386}
387
388fn generate_optional_map_closure(
390 trait_name: &str,
391 method_name: &str,
392 column_name: &str,
393 crate_path: &str,
394) -> Vec<TokenTree> {
395 let mut tokens = Vec::new();
396
397 tokens.push(punct('|'));
399 tokens.push(parens([ident("row"), punct(','), ident("v")]));
400 tokens.push(punct('|'));
401
402 let mut body = Vec::new();
403
404 body.push(ident("if"));
406 body.push(ident("matches"));
407 body.push(punct('!'));
408 body.push(parens([ident("v"), punct(',')].into_iter().chain(path(&["", crate_path, "Value", "Undefined"]))));
409
410 body.push(braces([ident("Ok"), parens([ident("None")])]));
412
413 body.push(ident("else"));
415
416 let mut else_body = Vec::new();
417 else_body.push(punct('<'));
418 else_body.push(underscore());
419 else_body.push(ident("as"));
420 else_body.extend(path(&["", crate_path, trait_name]));
421 else_body.push(punct('>'));
422 else_body.extend(path_sep());
423 else_body.push(ident(method_name));
424 else_body.push(parens([punct('&'), ident("v")]));
425 else_body.push(punct('.'));
426 else_body.push(ident("map"));
427 else_body.push(parens([ident("Some")]));
428 else_body.push(punct('.'));
429 else_body.push(ident("map_err"));
430 else_body.push(parens(generate_error_closure(column_name, crate_path)));
431
432 body.push(braces(else_body));
433
434 tokens.push(braces(body));
435 tokens
436}
437
438fn generate_required_map_closure(
440 trait_name: &str,
441 method_name: &str,
442 column_name: &str,
443 field_ty: &[TokenTree],
444 crate_path: &str,
445) -> Vec<TokenTree> {
446 let mut tokens = Vec::new();
447
448 tokens.push(punct('|'));
450 tokens.push(parens([ident("row"), punct(','), ident("v")]));
451 tokens.push(punct('|'));
452
453 let mut body = Vec::new();
454 body.push(punct('<'));
455 body.extend(field_ty.iter().cloned());
456 body.push(ident("as"));
457 body.extend(path(&["", crate_path, trait_name]));
458 body.push(punct('>'));
459 body.extend(path_sep());
460 body.push(ident(method_name));
461 body.push(parens([punct('&'), ident("v")]));
462 body.push(punct('.'));
463 body.push(ident("map_err"));
464 body.push(parens(generate_error_closure(column_name, crate_path)));
465
466 tokens.push(braces(body));
467 tokens
468}
469
470fn generate_error_closure(column_name: &str, crate_path: &str) -> Vec<TokenTree> {
472 let mut tokens = Vec::new();
473
474 tokens.push(punct('|'));
476 tokens.push(ident("e"));
477 tokens.push(punct('|'));
478 tokens.extend(path(&["", crate_path, "FromFrameError", "ValueError"]));
479 tokens.push(braces([
480 ident("column"),
481 punct(':'),
482 literal_str(column_name),
483 punct('.'),
484 ident("to_string"),
485 parens([]),
486 punct(','),
487 ident("row"),
488 punct(','),
489 ident("error"),
490 punct(':'),
491 ident("e"),
492 punct(','),
493 ]));
494
495 tokens
496}