openai_proc_macros 1.0.0-alpha.6

Procedural macros for use in openai crate.
Documentation
use convert_case::{Case, Casing};
use openai_bootstrap::{authorization, ApiResponse, BASE_URL};
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use reqwest::blocking::Client;
use serde::Deserialize;

#[derive(Deserialize)]
struct Models {
    data: Vec<Model>,
}

#[derive(Deserialize)]
struct Model {
    id: String,
}

#[proc_macro]
pub fn generate_model_id_enum(_input: TokenStream) -> TokenStream {
    let client = Client::new();
    let request = client.get(BASE_URL.to_owned() + "models");
    let api_response: ApiResponse<Models> = authorization!(request)
        .send()
        .unwrap_or_else(|error| panic!("{error}"))
        .json()
        .unwrap();

    match api_response {
        ApiResponse::Ok(models) => {
            let mut model_id_idents = Vec::new();
            let mut model_ids = Vec::new();
            let mut model_indexes = Vec::new();
            let mut index: u32 = 0;

            for model in models.data {
                if model.id.contains(':') || model.id.contains("deprecated") {
                    continue;
                }

                model_id_idents.push(format_ident!(
                    "{}",
                    model.id.to_case(Case::Pascal).replace('.', "_")
                ));
                model_ids.push(model.id);
                model_indexes.push(index);

                index += 1;
            }

            quote! {
                use serde::{ Serialize, de };

                #[derive(Debug, PartialEq, Default, Clone)]
                pub enum ModelID {
                    #[default]
                    #(#model_id_idents),*,
                    Custom(String),
                }

                impl Serialize for ModelID {
                    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                    where
                        S: serde::Serializer,
                    {
                        match *self {
                            #( ModelID::#model_id_idents => serializer.serialize_unit_variant("ModelID", #model_indexes, #model_ids) ),*,
                            ModelID::Custom(ref string) => serializer.serialize_str(string),
                        }
                    }
                }

                impl<'de> Deserialize<'de> for ModelID {
                    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                    where
                        D: serde::Deserializer<'de>,
                    {
                        struct ModelIDVisitor;

                        impl<'de> de::Visitor<'de> for ModelIDVisitor {
                            type Value = ModelID;

                            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                                write!(formatter, "one of {}", "".to_owned() + #( " `" + #model_ids + "`" )+*)
                            }

                            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                            where
                                E: de::Error,
                            {
                                match v {
                                    #( #model_ids => Ok(ModelID::#model_id_idents) ),*,
                                    _ => Ok(ModelID::Custom(v.to_string())),
                                }
                            }
                        }

                        deserializer.deserialize_identifier(ModelIDVisitor)
                    }
                }
            }.into()
        }
        ApiResponse::Err { error } => panic!("{error}"),
    }
}