use heck::ToSnakeCase;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::openapi::path::OpenApiResponseBody;
use super::WarningReporter;
#[derive(Debug, Clone)]
pub struct Union {
pub name: String,
pub members: Vec<String>,
}
impl Union {
pub fn from_schema(
name: &str,
schema: &OpenApiResponseBody,
warnings: WarningReporter,
) -> Option<Self> {
let members = match schema {
OpenApiResponseBody::Union { any_of } => {
let mut members = Vec::with_capacity(any_of.len());
for l in any_of {
let path = l.ref_path.to_owned();
if members.contains(&path) {
warnings.push(format!("Duplicate member: {path}"));
} else {
members.push(path);
}
}
members
}
_ => return None,
};
let name = name.to_owned();
Some(Self { name, members })
}
pub fn codegen(&self) -> Option<TokenStream> {
let name = format_ident!("{}", self.name);
let mut variants = Vec::new();
for member in &self.members {
let variant_name = member.strip_prefix("#/components/schemas/")?;
let accessor_name = format_ident!("{}", variant_name.to_snake_case());
let ty_name = format_ident!("{}", variant_name);
variants.push(quote! {
pub fn #accessor_name(&self) -> Result<crate::models::#ty_name, serde_json::Error> {
self.deserialize()
}
});
}
Some(quote! {
#[derive(Debug, Clone, serde::Deserialize)]
pub struct #name(serde_json::Value);
impl #name {
pub fn deserialize<'de, T>(&'de self) -> Result<T, serde_json::Error>
where
T: serde::Deserialize<'de>,
{
T::deserialize(&self.0)
}
#(#variants)*
}
})
}
}