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