kittycad_modeling_cmds_macros_impl/
ok_modeling_cmd_response_enum.rs

1use proc_macro2::TokenStream;
2use quote::quote_spanned;
3use syn::{spanned::Spanned, ItemMod};
4
5pub fn generate(input: ItemMod) -> TokenStream {
6    let span = input.span();
7
8    // Parse all items from the module, to discover which enum variants should exist.
9    // Also, create the doc for each enum variant.
10    let items = &input.content.as_ref().unwrap().1;
11    let variants = items
12        .iter()
13        .filter_map(|item| {
14            // All modeling commands are public structs.
15            match item {
16                syn::Item::Struct(item) if matches!(item.vis, syn::Visibility::Public(_)) => Some(&item.ident),
17                _ => None,
18            }
19        })
20        .collect::<Vec<_>>();
21
22    // Output the generated enum.
23    quote_spanned! {span=>
24        // Emit the module again
25        #input
26        /// A successful response from a modeling command.
27        /// This can be one of several types of responses, depending on the command.
28        #[derive(Debug, Clone, Serialize, Deserialize)]
29        #[cfg_attr(feature = "derive-jsonschema-on-enums", derive(schemars::JsonSchema))]
30        #[serde(rename_all = "snake_case", tag = "type", content = "data")]
31        #[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
32        pub enum OkModelingCmdResponse {
33            /// An empty response, used for any command that does not explicitly have a response
34            /// defined here.
35            Empty,
36            #(#[doc = concat!("The response to the '", stringify!(#variants), "' endpoint.")] #variants(output::#variants),)*
37        }
38
39        // Loop over `variants`, generate N different `From` impls on the enum,
40        // each of which corresponds to a variant. This way each individual output can be converted
41        // into the enum.
42        #(
43        impl From<output::#variants> for OkModelingCmdResponse {
44            fn from(x: output::#variants) -> Self {
45                Self::#variants(x)
46            }
47        }
48        )*
49
50        // The `Empty` enum variant is a bit different, doesn't conform to the same pattern.
51        // So define it manually.
52        impl From<()> for OkModelingCmdResponse {
53            fn from(_: ()) -> Self {
54                Self::Empty
55            }
56        }
57    }
58}