1use std::collections::{HashMap, HashSet};
2
3use roadblk_attr::ConstraintType;
4use serde::{Deserialize, Serialize};
5
6use apidoc_attr::{prop::ParsedApiDocAttr, serde::ParsedSerdeAttr};
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9pub enum ApiNumber {
10 I8,
11 I16,
12 I32,
13 I64,
14 I128,
15 U8,
16 U16,
17 U32,
18 USize,
19 U64,
20 U128,
21 F32,
22 F64,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
26pub struct ApiEnumer {
27 pub ident: String,
29
30 pub name: Option<String>,
32
33 pub prop: Option<ParsedApiDocAttr>,
35
36 pub serde: Vec<ParsedSerdeAttr>,
38
39 pub variants: Vec<String>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub struct ApiNamedField {
45 pub ident: String,
47
48 pub name: Option<String>,
50
51 pub prop: Option<ParsedApiDocAttr>,
53
54 pub option: bool,
56
57 pub ty: ApiTy,
59
60 pub constraint: Vec<ConstraintType>,
62
63 pub serde: Vec<ParsedSerdeAttr>,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
68pub struct ApiUnamedField {
69 pub index: i32,
71
72 pub name: Option<String>,
74
75 pub prop: Option<ParsedApiDocAttr>,
77
78 pub option: bool,
80
81 pub ty: ApiTy,
83
84 pub constraint: Vec<ConstraintType>,
86
87 pub serde: Vec<ParsedSerdeAttr>,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
92pub enum ApiFields {
93 Named(Vec<ApiNamedField>),
94 Unnamed(Vec<ApiUnamedField>),
95 Unit,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
99pub struct ApiModel {
100 pub ident: String,
102
103 pub name: Option<String>,
105
106 pub prop: Option<ParsedApiDocAttr>,
108
109 pub value: Option<i32>,
111
112 pub serde: Vec<ParsedSerdeAttr>,
114
115 pub fields: ApiFields,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
120pub enum ApiTy {
121 Bool,
122
123 String,
124
125 Number(ApiNumber),
126
127 File,
128
129 Enumer(Box<ApiEnumer>),
130
131 Struct { model_id: String },
132
133 Map(Box<ApiTy>, Box<ApiTy>),
134
135 Set(Box<ApiTy>),
136
137 List(Box<ApiTy>),
138}
139
140pub trait ApiTyTrait {
141 fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy;
142
143 fn api_option() -> bool {
144 false
145 }
146
147 fn api_model_id() -> String {
148 let type_name = std::any::type_name::<Self>();
149 type_name.to_string()
150 }
151}
152
153macro_rules! impl_ty_number {
154 ($primite: ident, $item: ident) => {
155 impl ApiTyTrait for $primite {
156 fn api_collect_ty(_models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
157 ApiTy::Number(ApiNumber::$item)
158 }
159 }
160 };
161}
162impl_ty_number!(i8, I8);
163impl_ty_number!(i16, I16);
164impl_ty_number!(i32, I32);
165impl_ty_number!(i64, I64);
166impl_ty_number!(i128, I128);
167impl_ty_number!(u8, U8);
168impl_ty_number!(usize, USize);
169impl_ty_number!(u16, U16);
170impl_ty_number!(u32, U32);
171impl_ty_number!(u64, U64);
172impl_ty_number!(u128, U128);
173impl_ty_number!(f32, F32);
174impl_ty_number!(f64, F64);
175
176impl ApiTyTrait for String {
177 fn api_collect_ty(_models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
178 ApiTy::String
179 }
180}
181impl ApiTyTrait for bool {
182 fn api_collect_ty(_models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
183 ApiTy::Bool
184 }
185}
186impl<T: ApiTyTrait> ApiTyTrait for Option<T> {
187 fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
188 T::api_collect_ty(models)
189 }
190
191 fn api_option() -> bool {
192 true
193 }
194}
195impl<T: ApiTyTrait> ApiTyTrait for Vec<T> {
196 fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
197 ApiTy::List(Box::new(T::api_collect_ty(models)))
198 }
199}
200impl<T: ApiTyTrait> ApiTyTrait for HashSet<T> {
201 fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
202 ApiTy::Set(Box::new(T::api_collect_ty(models)))
203 }
204}
205impl<K: ApiTyTrait, V: ApiTyTrait> ApiTyTrait for HashMap<K, V> {
206 fn api_collect_ty(models: &mut HashMap<String, Option<ApiModel>>) -> ApiTy {
207 ApiTy::Map(
208 Box::new(K::api_collect_ty(models)),
209 Box::new(V::api_collect_ty(models)),
210 )
211 }
212}