torn-api-codegen 0.8.1

Contains the v2 torn API model descriptions and codegen for the bindings
Documentation
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)*
            }
        })
    }
}