1use proc_macro::TokenStream;
2use syn::{DeriveInput, Ident};
3
4#[cfg(feature = "egui")]
5fn build_enum_variant_builder(v: &syn::Variant) -> proc_macro2::TokenStream {
6 let sident = proc_macro2::Ident::new("Self", proc_macro2::Span::call_site());
7 match &v.fields {
8 syn::Fields::Named(f) => {
9 let mut def: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
10 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
11 for f in f.named.iter() {
12 tokens.extend([proc_macro2::TokenTree::Ident(
13 f.ident.as_ref().unwrap().clone(),
14 )]);
15 let ftype = &f.ty;
16 let val = quote::quote!(<#ftype as core::default::Default>::default());
17 tokens.extend([proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
18 ':',
19 proc_macro2::Spacing::Alone,
20 ))]);
21 tokens.extend(val);
22 tokens.extend([proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
23 ',',
24 proc_macro2::Spacing::Alone,
25 ))]);
26 }
27 def.extend(tokens);
28
29 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
30 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
31 tokens.extend([
32 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
33 ':',
34 proc_macro2::Spacing::Joint,
35 )),
36 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
37 ':',
38 proc_macro2::Spacing::Alone,
39 )),
40 ]);
41 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
42 tokens.extend([proc_macro2::TokenTree::Group(proc_macro2::Group::new(
43 proc_macro2::Delimiter::Brace,
44 def,
45 ))]);
46 tokens
47 }
48 syn::Fields::Unnamed(f) => {
49 let mut def: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
50 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
51 for (i, f) in f.unnamed.iter().enumerate() {
52 let ty = &f.ty;
53 tokens.extend(quote::quote!(<#ty as core::default::Default>::default()));
54 tokens.extend([proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
55 ',',
56 proc_macro2::Spacing::Alone,
57 ))]);
58 }
59 def.extend(tokens);
60
61 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
62 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
63 tokens.extend([
64 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
65 ':',
66 proc_macro2::Spacing::Joint,
67 )),
68 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
69 ':',
70 proc_macro2::Spacing::Alone,
71 )),
72 ]);
73 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
74 tokens.extend([proc_macro2::TokenTree::Group(proc_macro2::Group::new(
75 proc_macro2::Delimiter::Parenthesis,
76 def,
77 ))]);
78 tokens
79 }
80 syn::Fields::Unit => {
81 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
82 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
83 tokens.extend([
84 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
85 ':',
86 proc_macro2::Spacing::Joint,
87 )),
88 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
89 ':',
90 proc_macro2::Spacing::Alone,
91 )),
92 ]);
93 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
94 tokens
95 }
96 }
97}
98
99#[cfg(feature = "egui")]
101fn build_enum_variant_to_fields(v: &syn::Variant) -> (proc_macro2::TokenStream, Vec<&syn::Field>) {
102 let sident = proc_macro2::Ident::new("Self", proc_macro2::Span::call_site());
103 let mut fields = Vec::new();
104 let q: proc_macro2::TokenStream = match &v.fields {
105 syn::Fields::Named(f) => {
106 let mut def: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
107 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
108 for f in f.named.iter() {
109 tokens.extend([proc_macro2::TokenTree::Ident(
110 f.ident.as_ref().unwrap().clone(),
111 )]);
112 tokens.extend([proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
113 ',',
114 proc_macro2::Spacing::Alone,
115 ))]);
116 fields.push(f);
117 }
118 def.extend(tokens);
119
120 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
121 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
122 tokens.extend([
123 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
124 ':',
125 proc_macro2::Spacing::Joint,
126 )),
127 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
128 ':',
129 proc_macro2::Spacing::Alone,
130 )),
131 ]);
132 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
133 tokens.extend([proc_macro2::TokenTree::Group(proc_macro2::Group::new(
134 proc_macro2::Delimiter::Brace,
135 def,
136 ))]);
137 tokens
138 }
139 syn::Fields::Unnamed(f) => {
140 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
141 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
142 tokens.extend([
143 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
144 ':',
145 proc_macro2::Spacing::Joint,
146 )),
147 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
148 ':',
149 proc_macro2::Spacing::Alone,
150 )),
151 ]);
152 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
153 let mut tokens2: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
154 for (i, f) in f.unnamed.iter().enumerate() {
155 let varname = quote::format_ident!("a_{}", i);
156 tokens2.extend([proc_macro2::TokenTree::Ident(varname)]);
157 tokens2.extend([proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
158 ',',
159 proc_macro2::Spacing::Alone,
160 ))]);
161 fields.push(f);
162 }
163 quote::quote! {#tokens (#tokens2)}
164 }
165 syn::Fields::Unit => {
166 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
167 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
168 tokens.extend([
169 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
170 ':',
171 proc_macro2::Spacing::Joint,
172 )),
173 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
174 ':',
175 proc_macro2::Spacing::Alone,
176 )),
177 ]);
178 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
179 tokens
180 }
181 };
182 (q, fields)
183}
184
185#[cfg(feature = "egui")]
187fn build_enum_variant_to_string(v: &syn::Variant) -> (proc_macro2::TokenStream, String) {
188 let sident = proc_macro2::Ident::new("Self", proc_macro2::Span::call_site());
189 let text2 = v.ident.to_string();
190 let q: proc_macro2::TokenStream = match &v.fields {
191 syn::Fields::Named(f) => {
192 let mut def: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
193 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
194 for f in f.named.iter() {
195 tokens.extend([proc_macro2::TokenTree::Ident(
196 f.ident.as_ref().unwrap().clone(),
197 )]);
198 tokens.extend([proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
199 ',',
200 proc_macro2::Spacing::Alone,
201 ))]);
202 }
203 def.extend(tokens);
204
205 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
206 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
207 tokens.extend([
208 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
209 ':',
210 proc_macro2::Spacing::Joint,
211 )),
212 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
213 ':',
214 proc_macro2::Spacing::Alone,
215 )),
216 ]);
217 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
218 tokens.extend([proc_macro2::TokenTree::Group(proc_macro2::Group::new(
219 proc_macro2::Delimiter::Brace,
220 def,
221 ))]);
222 tokens
223 }
224 syn::Fields::Unnamed(f) => {
225 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
226 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
227 tokens.extend([
228 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
229 ':',
230 proc_macro2::Spacing::Joint,
231 )),
232 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
233 ':',
234 proc_macro2::Spacing::Alone,
235 )),
236 ]);
237 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
238 let mut tokens2: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
239 for (i, _f) in f.unnamed.iter().enumerate() {
240 let varname = quote::format_ident!("a_{}", i);
241 tokens2.extend([proc_macro2::TokenTree::Ident(varname)]);
242 tokens2.extend([proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
243 ',',
244 proc_macro2::Spacing::Alone,
245 ))]);
246 }
247 quote::quote! {#tokens (#tokens2)}
248 }
249 syn::Fields::Unit => {
250 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
251 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
252 tokens.extend([
253 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
254 ':',
255 proc_macro2::Spacing::Joint,
256 )),
257 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
258 ':',
259 proc_macro2::Spacing::Alone,
260 )),
261 ]);
262 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
263 tokens
264 }
265 };
266 (q, text2)
267}
268
269#[cfg(feature = "egui")]
270#[proc_macro_derive(EguiPrompting)]
271pub fn derive_egui_prompting(input: TokenStream) -> TokenStream {
272 use std::any::Any;
273
274 let input = syn::parse_macro_input!(input as DeriveInput);
275 let sident = input.ident;
276 let expanded: TokenStream;
277
278 match &input.data {
279 syn::Data::Enum(e) => {
280 let mut field_stuff: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
281 let q: proc_macro2::TokenStream = quote::quote! {
282 let combobox = if let Some(name) = name {
283 let mut s = "Select a ".to_string();
284 s.push_str(&name);
285 egui::ComboBox::from_label(s)
286 } else {
287 egui::ComboBox::from_label("Select")
288 };
289 };
290 field_stuff.extend(q);
291
292 let mut match_stuff: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
293 for v in &e.variants {
294 let (q, t) = build_enum_variant_to_string(v);
295 match_stuff.extend(quote::quote! {
296 #q => #t,
297 });
298 }
299
300 let q_start: proc_macro2::TokenStream = quote::quote! {
301 let val = match self {
302 #match_stuff
303 };
304 };
305 field_stuff.extend(q_start);
306
307 let mut combo_stuff: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
308 for v in &e.variants {
309 let text = v.ident.to_string();
310 let assign = build_enum_variant_builder(v);
311 let t = v.type_id();
312 let q: proc_macro2::TokenStream = quote::quote! {
313 if ui.selectable_label(false, #text).clicked() {
314 *self = #assign;
315 }
316 };
317 combo_stuff.extend(q);
318 }
319
320 let mut option_prompt: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
321 for v in &e.variants {
322 let (q, f) = build_enum_variant_to_fields(v);
323 let mut option_code: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
324 if !f.is_empty() {
325 for (i, f) in f.iter().enumerate() {
326 if let Some(ident) = &f.ident {
327 let varname = quote::format_ident!("{}", ident);
328 let text = ident.to_string();
329 let q: proc_macro2::TokenStream = quote::quote! {
330 let subname = format!("{}/{}", name.unwrap_or(""), #text);
331 #varname.build_gui(ui, Some(&subname))?;
332 };
333 option_code.extend(q);
334 } else {
335 let varname = quote::format_ident!("a_{}", i);
336 let text = format!("{}", i);
337 let q: proc_macro2::TokenStream = quote::quote! {
338 let subname = format!("{}/{}", name.unwrap_or(""), #text);
339 #varname.build_gui(ui, Some(&subname))?;
340 };
341 option_code.extend(q);
342 }
343 }
344 option_prompt.extend(quote::quote! {
345 #q => { #option_code },
346 });
347 }
348 }
349
350 expanded = quote::quote! {
351 impl userprompt::EguiPrompting for #sident {
352 fn build_gui(&mut self, ui: &mut egui::Ui, name: Option<&str>) -> Result<(), String> {
353 #field_stuff
354 combobox.selected_text(val)
355 .show_ui(ui, |ui| { #combo_stuff });
356 match self {
357 #option_prompt
358 _ => {}
359 }
360 Ok(())
361 }
362 }
363 }
364 .into();
365 }
366 syn::Data::Struct(s) => {
367 let fields = &s.fields;
368 let mut field_stuff: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
369
370 let q: proc_macro2::TokenStream = quote::quote! {
371 if let Some(name) = name {
372 ui.label(name);
373 }
374 };
375 field_stuff.extend(q);
376
377 if let syn::Fields::Named(n) = fields {
378 for n in n.named.iter() {
379 if let Some(ident) = &n.ident {
380 let text = ident.to_string();
381 let varname = quote::format_ident!("{}", ident);
382 let q: proc_macro2::TokenStream = quote::quote! {
383 let subname = format!("{}/{}", name.unwrap_or(""), #text);
384 self.#varname.build_gui(ui, Some(&subname))?;
385 };
386 field_stuff.extend(q);
387 }
388 }
389
390 let mut q2s: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
391
392 for (i, n) in n.named.iter().enumerate() {
393 if let Some(ident) = &n.ident {
394 let name = Ident::new(&format!("a_{}", i), proc_macro2::Span::call_site());
395 let q2: proc_macro2::TokenStream = quote::quote! {
396 #ident: #name,
397 };
398 q2s.extend(q2);
399 }
400 }
401
402 let q: proc_macro2::TokenStream = quote::quote! {
403 Ok(())
404 };
405 field_stuff.extend(q);
406 }
407 expanded = quote::quote! {
408 impl userprompt::EguiPrompting for #sident {
409 fn build_gui(&mut self, ui: &mut egui::Ui, name: Option<&str>) -> Result<(), String> {
410 #field_stuff
411 }
412 }
413 }
414 .into();
415 }
416 _ => panic!("Unhandled object type"),
417 };
418 TokenStream::from(expanded)
419}
420
421#[proc_macro_derive(Prompting)]
422pub fn derive_prompting(input: TokenStream) -> TokenStream {
423 let input = syn::parse_macro_input!(input as DeriveInput);
424 let sident = input.ident;
425 let expanded: TokenStream;
426 match &input.data {
427 syn::Data::Enum(e) => {
428 let mut field_stuff: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
429 let q: proc_macro2::TokenStream = quote::quote! {
430 if let Some(name) = name {
431 println!("[{}]", name);
432 }
433 };
434 field_stuff.extend(q);
435
436 let q: proc_macro2::TokenStream = quote::quote! {
437 println!("Enter the variant type, valid options are listed below");
438 };
439 field_stuff.extend(q);
440
441 for v in &e.variants {
442 let text = v.ident.to_string();
443 let q: proc_macro2::TokenStream = quote::quote! {
444 println!("\t{}", #text);
445 };
446 field_stuff.extend(q);
447 }
448
449 let name = Ident::new(&format!("a"), proc_macro2::Span::call_site());
450 let q: proc_macro2::TokenStream = quote::quote! {
451 let #name = <String as userprompt::Prompting>::prompt(None)?;
452 };
453 field_stuff.extend(q);
454
455 let mut match_stuff: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
456 for v in &e.variants {
457 let text2 = v.ident.to_string();
458 let q: proc_macro2::TokenStream = match &v.fields {
459 syn::Fields::Named(f) => {
460 let mut def: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
461 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
462 for (i, f) in f.named.iter().enumerate() {
463 if i != 0 {
464 tokens.extend([proc_macro2::TokenTree::Punct(
465 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
466 )]);
467 }
468 tokens.extend([proc_macro2::TokenTree::Ident(
469 f.ident.as_ref().unwrap().clone(),
470 )]);
471 let ftype = &f.ty;
472 let text = f.ident.as_ref().unwrap().to_string();
473 let val = quote::quote!(<#ftype as userprompt::Prompting>::prompt(Some(#text))?);
474 tokens.extend([proc_macro2::TokenTree::Punct(
475 proc_macro2::Punct::new(':', proc_macro2::Spacing::Alone),
476 )]);
477 tokens.extend(val);
478 }
479 def.extend(tokens);
480
481 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
482 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
483 tokens.extend([
484 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
485 ':',
486 proc_macro2::Spacing::Joint,
487 )),
488 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
489 ':',
490 proc_macro2::Spacing::Alone,
491 )),
492 ]);
493 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
494 tokens.extend([proc_macro2::TokenTree::Group(proc_macro2::Group::new(
495 proc_macro2::Delimiter::Brace,
496 def,
497 ))]);
498 quote::quote! {
499 #text2 => { return Ok(#tokens); }
500 }
501 }
502 syn::Fields::Unnamed(f) => {
503 let mut def: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
504 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
505 for (i, f) in f.unnamed.iter().enumerate() {
506 if i != 0 {
507 tokens.extend([proc_macro2::TokenTree::Punct(
508 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
509 )]);
510 }
511 tokens.extend([proc_macro2::TokenTree::Literal(
512 proc_macro2::Literal::usize_unsuffixed(i),
513 )]);
514 let ftype = &f.ty;
515 let val = quote::quote!(<#ftype as userprompt::Prompting>::prompt(Some(&format!("{}", #i)))?);
516 tokens.extend([proc_macro2::TokenTree::Punct(
517 proc_macro2::Punct::new(':', proc_macro2::Spacing::Alone),
518 )]);
519 tokens.extend(val);
520 }
521 def.extend(tokens);
522
523 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
524 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
525 tokens.extend([
526 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
527 ':',
528 proc_macro2::Spacing::Joint,
529 )),
530 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
531 ':',
532 proc_macro2::Spacing::Alone,
533 )),
534 ]);
535 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
536 tokens.extend([proc_macro2::TokenTree::Group(proc_macro2::Group::new(
537 proc_macro2::Delimiter::Brace,
538 def,
539 ))]);
540 quote::quote! {
541 #text2 => { return Ok(#tokens); }
542 }
543 }
544 syn::Fields::Unit => {
545 let mut tokens: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
546 tokens.extend([proc_macro2::TokenTree::Ident(sident.clone())]);
547 tokens.extend([
548 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
549 ':',
550 proc_macro2::Spacing::Joint,
551 )),
552 proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
553 ':',
554 proc_macro2::Spacing::Alone,
555 )),
556 ]);
557 tokens.extend([proc_macro2::TokenTree::Ident(v.ident.clone())]);
558 quote::quote! {
559 #text2 => { return Ok(#tokens); }
560 }
561 }
562 };
563 match_stuff.extend(q);
564 }
565
566 let match_else: proc_macro2::TokenStream =
567 quote::quote!(_ => println!("Invalid option"),);
568
569 let q_start: proc_macro2::TokenStream = quote::quote! {
570 match a.as_str() {
571 #match_stuff
572 #match_else
573 }
574 };
575 field_stuff.extend(q_start);
576
577 expanded = quote::quote! {
578 impl userprompt::Prompting for #sident {
579 fn prompt(name: Option<&str>) -> Result<Self, userprompt::Error> {
580 loop {
581 #field_stuff
582 }
583 }
584 }
585 }
586 .into();
587 }
588 syn::Data::Struct(s) => {
589 let fields = &s.fields;
590 let mut field_stuff: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
591
592 let q: proc_macro2::TokenStream = quote::quote! {
593 if let Some(name) = name {
594 println!("[{}]", name);
595 }
596 };
597 field_stuff.extend(q);
598
599 if let syn::Fields::Named(n) = fields {
600 for (i, n) in n.named.iter().enumerate() {
601 let ftype = &n.ty;
602 if let Some(ident) = &n.ident {
603 let name = Ident::new(&format!("a_{}", i), proc_macro2::Span::call_site());
604 let text = ident.to_string();
605 let q: proc_macro2::TokenStream = quote::quote! {
606 let #name = <#ftype as userprompt::Prompting>::prompt(Some(#text))?;
607 };
608 field_stuff.extend(q);
609 }
610 }
611
612 let mut q2s: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
613
614 for (i, n) in n.named.iter().enumerate() {
615 if let Some(ident) = &n.ident {
616 let name = Ident::new(&format!("a_{}", i), proc_macro2::Span::call_site());
617 let q2: proc_macro2::TokenStream = quote::quote! {
618 #ident: #name,
619 };
620 q2s.extend(q2);
621 }
622 }
623
624 let q: proc_macro2::TokenStream = quote::quote! {
625 Ok(Self {
626 #q2s
627 })
628 };
629 field_stuff.extend(q);
630 }
631 expanded = quote::quote! {
632 impl userprompt::Prompting for #sident {
633 fn prompt(name: Option<&str>) -> Result<Self, userprompt::Error> {
634 #field_stuff
635 }
636 }
637 }
638 .into();
639 }
640 _ => panic!("Unhandled object type"),
641 };
642 TokenStream::from(expanded)
643}