1mod error;
2mod extract_types_for_assertion;
3mod item_story;
4mod local_type_for;
5mod no_foreign_type_validation;
6mod output;
7mod step_attr_syntax;
8mod step_usage;
9mod story_attr_syntax;
10
11use item_story::ItemStory;
12use proc_macro2::TokenStream;
13use story_attr_syntax::StoryAttr;
14use syn::parse_macro_input;
15
16#[proc_macro_attribute]
17pub fn story(
19 attr: proc_macro::TokenStream,
20 input: proc_macro::TokenStream,
21) -> proc_macro::TokenStream {
22 let attr = parse_macro_input!(attr as StoryAttr);
23 let story = parse_macro_input!(input as ItemStory);
24 process_story(attr, story).into()
25}
26
27#[proc_macro_attribute]
28pub fn local_type_for(
31 attr: proc_macro::TokenStream,
32 input: proc_macro::TokenStream,
33) -> proc_macro::TokenStream {
34 let story_name = parse_macro_input!(attr as syn::Ident);
35 let input_item = parse_macro_input!(input as syn::Item);
36
37 local_type_for::generate(&story_name, &input_item).into()
38}
39
40fn process_story(attr: StoryAttr, story: ItemStory) -> TokenStream {
44 output::generate(&attr, &story)
45}
46
47#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub(crate) enum Asyncness {
49 Sync,
50 Async,
51}
52
53impl quote::ToTokens for Asyncness {
54 fn to_tokens(&self, tokens: &mut TokenStream) {
55 match self {
56 Asyncness::Sync => quote::quote!().to_tokens(tokens),
57 Asyncness::Async => quote::quote!(async).to_tokens(tokens),
58 }
59 }
60}
61
62pub(crate) fn collect_format_args(lit_str: &syn::LitStr) -> Vec<String> {
63 lit_str
64 .value()
65 .split("{{")
67 .flat_map(|part| part.split("}}"))
68 .flat_map(|part| part.split('{').skip(1))
70 .filter_map(|part| part.split_once('}').map(|(head, _)| head))
72 .map(|format| {
74 format
75 .split_once(':')
76 .map(|(head, _)| head)
77 .unwrap_or(format)
78 })
79 .map(ToOwned::to_owned)
80 .collect()
81}
82
83struct MakeStaticWalker;
84
85impl syn::visit_mut::VisitMut for MakeStaticWalker {
86 fn visit_type_reference_mut(&mut self, i: &mut syn::TypeReference) {
87 i.lifetime = Some(syn::Lifetime::new(
88 "'static",
89 proc_macro2::Span::mixed_site(),
90 ));
91 self.visit_type_mut(&mut i.elem);
92 }
93}
94
95pub(crate) fn make_static(ty: &syn::Type) -> syn::Type {
96 use syn::visit_mut::VisitMut;
97 let mut walker = MakeStaticWalker;
98 let mut static_ty = ty.clone();
99 walker.visit_type_mut(&mut static_ty);
100 static_ty
101}
102
103pub(crate) fn pretty_print_expr(expr: &syn::Expr) -> String {
104 prettyplease::unparse(
105 &syn::parse_file(
106 "e::quote! {
107 const IDENT: String = #expr;
108 }
109 .to_string(),
110 )
111 .unwrap(),
112 )
113 .replace("const IDENT: String = ", "")
114 .replace(";", "")
115 .trim()
116 .to_string()
117}
118
119pub(crate) fn pretty_print_type(ty: &syn::Type) -> String {
120 prettyplease::unparse(
121 &syn::parse_file(
122 "e::quote! {
123 const IDENT: #ty = 1;
124 }
125 .to_string(),
126 )
127 .unwrap(),
128 )
129 .replace("const IDENT: ", "")
130 .replace(" = 1;", "")
131 .trim()
132 .to_string()
133}