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