torn_api_codegen/model/
union.rs

1use heck::ToSnakeCase;
2use proc_macro2::TokenStream;
3use quote::{format_ident, quote};
4
5use crate::openapi::path::OpenApiResponseBody;
6
7#[derive(Debug, Clone)]
8pub struct Union {
9    pub name: String,
10    pub members: Vec<String>,
11}
12
13impl Union {
14    pub fn from_schema(name: &str, schema: &OpenApiResponseBody) -> Option<Self> {
15        let members = match schema {
16            OpenApiResponseBody::Union { any_of } => {
17                any_of.iter().map(|l| l.ref_path.to_owned()).collect()
18            }
19            _ => return None,
20        };
21        let name = name.to_owned();
22
23        Some(Self { name, members })
24    }
25
26    pub fn codegen(&self) -> Option<TokenStream> {
27        let name = format_ident!("{}", self.name);
28        let mut variants = Vec::new();
29
30        for member in &self.members {
31            let variant_name = member.strip_prefix("#/components/schemas/")?;
32            let accessor_name = format_ident!("{}", variant_name.to_snake_case());
33            let ty_name = format_ident!("{}", variant_name);
34            variants.push(quote! {
35                pub fn #accessor_name(&self) -> Result<crate::models::#ty_name, serde_json::Error> {
36                    <crate::models::#ty_name as serde::Deserialize>::deserialize(&self.0)
37                }
38            });
39        }
40
41        Some(quote! {
42            #[derive(Debug, Clone, serde::Deserialize)]
43            pub struct #name(serde_json::Value);
44
45            impl #name {
46                #(#variants)*
47            }
48        })
49    }
50}