use std::collections::{HashMap, HashSet};
use roadblk_attr::ConstraintType;
use serde::{Deserialize, Serialize};
use apidoc_attr::{prop::ParsedApiDocAttr, serde::ParsedSerdeAttr};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ApiNumber {
I8,
I16,
I32,
I64,
I128,
U8,
U16,
U32,
USize,
U64,
U128,
F32,
F64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ApiEnumer {
pub ident: String,
pub name: Option<String>,
pub prop: Option<ParsedApiDocAttr>,
pub serde: Vec<ParsedSerdeAttr>,
pub variants: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ApiNamedField {
pub ident: String,
pub name: Option<String>,
pub prop: Option<ParsedApiDocAttr>,
pub option: bool,
pub ty: ApiTy,
pub constraint: Vec<ConstraintType>,
pub serde: Vec<ParsedSerdeAttr>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ApiUnamedField {
pub index: i32,
pub name: Option<String>,
pub prop: Option<ParsedApiDocAttr>,
pub option: bool,
pub ty: ApiTy,
pub constraint: Vec<ConstraintType>,
pub serde: Vec<ParsedSerdeAttr>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ApiFields {
Named(Vec<ApiNamedField>),
Unnamed(Vec<ApiUnamedField>),
Unit,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ApiModel {
pub ident: String,
pub name: Option<String>,
pub prop: Option<ParsedApiDocAttr>,
pub value: Option<i32>,
pub serde: Vec<ParsedSerdeAttr>,
pub fields: ApiFields,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ApiTy {
Bool,
String,
Number(ApiNumber),
File,
Enumer(Box<ApiEnumer>),
Struct { model_id: String },
Map(Box<ApiTy>, Box<ApiTy>),
Set(Box<ApiTy>),
List(Box<ApiTy>),
}
pub trait ApiTyTrait {
fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy;
fn api_option() -> bool {
false
}
fn api_model_id() -> String {
let type_name = std::any::type_name::<Self>();
type_name.to_string()
}
}
macro_rules! impl_ty_number {
($primite: ident, $item: ident) => {
impl ApiTyTrait for $primite {
fn api_collect_ty(_models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
ApiTy::Number(ApiNumber::$item)
}
}
};
}
impl_ty_number!(i8, I8);
impl_ty_number!(i16, I16);
impl_ty_number!(i32, I32);
impl_ty_number!(i64, I64);
impl_ty_number!(i128, I128);
impl_ty_number!(u8, U8);
impl_ty_number!(usize, USize);
impl_ty_number!(u16, U16);
impl_ty_number!(u32, U32);
impl_ty_number!(u64, U64);
impl_ty_number!(u128, U128);
impl_ty_number!(f32, F32);
impl_ty_number!(f64, F64);
impl ApiTyTrait for String {
fn api_collect_ty(_models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
ApiTy::String
}
}
impl ApiTyTrait for bool {
fn api_collect_ty(_models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
ApiTy::Bool
}
}
impl<T: ApiTyTrait> ApiTyTrait for Option<T> {
fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
T::api_collect_ty(models)
}
fn api_option() -> bool {
true
}
}
impl<T: ApiTyTrait> ApiTyTrait for Vec<T> {
fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
ApiTy::List(Box::new(T::api_collect_ty(models)))
}
}
impl<T: ApiTyTrait> ApiTyTrait for HashSet<T> {
fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
ApiTy::Set(Box::new(T::api_collect_ty(models)))
}
}
impl<K: ApiTyTrait, V: ApiTyTrait> ApiTyTrait for HashMap<K, V> {
fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
ApiTy::Map(
Box::new(K::api_collect_ty(models)),
Box::new(V::api_collect_ty(models)),
)
}
}