1use serde::{Deserialize, Serialize};
4use serde_json;
5
6pub trait ToSchema {
10 fn schema() -> Schema;
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "lowercase")]
17pub enum SchemaType {
18 String,
20 Integer,
22 Number,
24 Boolean,
26 Array,
28 Object,
30 Null,
32}
33
34impl Default for SchemaType {
35 fn default() -> Self {
37 Self::Object
38 }
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
43pub struct Schema {
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub title: Option<String>,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub description: Option<String>,
50 #[serde(rename = "type")]
52 pub schema_type: SchemaType,
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub properties: Option<std::collections::BTreeMap<String, Schema>>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub required: Option<Vec<String>>,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub items: Option<Box<Schema>>,
62 #[serde(rename = "enum")]
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub enum_values: Option<Vec<serde_json::Value>>,
66 #[serde(skip_serializing_if = "Option::is_none")]
68 pub default: Option<serde_json::Value>,
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub example: Option<serde_json::Value>,
72 #[serde(default)]
74 pub nullable: bool,
75 #[serde(default)]
77 pub read_only: bool,
78 #[serde(default)]
80 pub write_only: bool,
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub minimum: Option<f64>,
84 #[serde(skip_serializing_if = "Option::is_none")]
86 pub maximum: Option<f64>,
87 #[serde(skip_serializing_if = "Option::is_none")]
89 pub min_length: Option<usize>,
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub max_length: Option<usize>,
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub pattern: Option<String>,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub format: Option<String>,
99 #[serde(rename = "oneOf")]
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub one_of: Option<Vec<Schema>>,
103 #[serde(rename = "anyOf")]
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub any_of: Option<Vec<Schema>>,
107 #[serde(rename = "allOf")]
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub all_of: Option<Vec<Schema>>,
111}
112
113impl Default for Schema {
114 fn default() -> Self {
116 Self {
117 title: None,
118 description: None,
119 schema_type: SchemaType::Object,
120 properties: None,
121 required: None,
122 items: None,
123 enum_values: None,
124 default: None,
125 example: None,
126 nullable: false,
127 read_only: false,
128 write_only: false,
129 minimum: None,
130 maximum: None,
131 min_length: None,
132 max_length: None,
133 pattern: None,
134 format: None,
135 one_of: None,
136 any_of: None,
137 all_of: None,
138 }
139 }
140}
141
142impl Schema {
143 pub fn string() -> Self {
145 Self { schema_type: SchemaType::String, ..Default::default() }
146 }
147
148 pub fn integer() -> Self {
150 Self { schema_type: SchemaType::Integer, ..Default::default() }
151 }
152
153 pub fn number() -> Self {
155 Self { schema_type: SchemaType::Number, ..Default::default() }
156 }
157
158 pub fn boolean() -> Self {
160 Self { schema_type: SchemaType::Boolean, ..Default::default() }
161 }
162
163 pub fn array(items: Schema) -> Self {
165 Self { schema_type: SchemaType::Array, items: Some(Box::new(items)), ..Default::default() }
166 }
167
168 pub fn object() -> Self {
170 Self { schema_type: SchemaType::Object, properties: Some(std::collections::BTreeMap::new()), ..Default::default() }
171 }
172
173 pub fn title(mut self, title: impl Into<String>) -> Self {
175 self.title = Some(title.into());
176 self
177 }
178
179 pub fn description(mut self, desc: impl Into<String>) -> Self {
181 self.description = Some(desc.into());
182 self
183 }
184
185 pub fn property(mut self, name: impl Into<String>, schema: Schema) -> Self {
187 let properties = self.properties.get_or_insert_with(std::collections::BTreeMap::new);
188 properties.insert(name.into(), schema);
189 self
190 }
191
192 pub fn required(mut self, fields: Vec<&str>) -> Self {
194 self.required = Some(fields.into_iter().map(String::from).collect());
195 self
196 }
197
198 pub fn enum_values(mut self, values: Vec<serde_json::Value>) -> Self {
200 self.enum_values = Some(values);
201 self
202 }
203
204 pub fn with_default(mut self, value: serde_json::Value) -> Self {
206 self.default = Some(value);
207 self
208 }
209
210 pub fn example(mut self, value: serde_json::Value) -> Self {
212 self.example = Some(value);
213 self
214 }
215
216 pub fn format(mut self, format: impl Into<String>) -> Self {
218 self.format = Some(format.into());
219 self
220 }
221
222 pub fn pattern(mut self, pattern: impl Into<String>) -> Self {
224 self.pattern = Some(pattern.into());
225 self
226 }
227
228 pub fn min_length(mut self, len: usize) -> Self {
230 self.min_length = Some(len);
231 self
232 }
233
234 pub fn max_length(mut self, len: usize) -> Self {
236 self.max_length = Some(len);
237 self
238 }
239
240 pub fn minimum(mut self, min: f64) -> Self {
242 self.minimum = Some(min);
243 self
244 }
245
246 pub fn maximum(mut self, max: f64) -> Self {
248 self.maximum = Some(max);
249 self
250 }
251
252 pub fn nullable(mut self, nullable: bool) -> Self {
254 self.nullable = nullable;
255 self
256 }
257
258 pub fn read_only(mut self, read_only: bool) -> Self {
260 self.read_only = read_only;
261 self
262 }
263
264 pub fn write_only(mut self, write_only: bool) -> Self {
266 self.write_only = write_only;
267 self
268 }
269
270 pub fn one_of(mut self, schemas: Vec<Schema>) -> Self {
272 self.one_of = Some(schemas);
273 self
274 }
275
276 pub fn any_of(mut self, schemas: Vec<Schema>) -> Self {
278 self.any_of = Some(schemas);
279 self
280 }
281
282 pub fn all_of(mut self, schemas: Vec<Schema>) -> Self {
284 self.all_of = Some(schemas);
285 self
286 }
287
288 pub fn to_json_schema(&self) -> serde_json::Value {
290 serde_json::to_value(self).unwrap_or(serde_json::Value::Null)
291 }
292}
293
294impl ToSchema for String {
296 fn schema() -> Schema {
297 Schema::string()
298 }
299}
300
301impl ToSchema for i64 {
302 fn schema() -> Schema {
303 Schema::integer()
304 }
305}
306
307impl ToSchema for i32 {
308 fn schema() -> Schema {
309 Schema::integer()
310 }
311}
312
313impl ToSchema for i16 {
314 fn schema() -> Schema {
315 Schema::integer()
316 }
317}
318
319impl ToSchema for i8 {
320 fn schema() -> Schema {
321 Schema::integer()
322 }
323}
324
325impl ToSchema for u64 {
326 fn schema() -> Schema {
327 Schema::integer()
328 }
329}
330
331impl ToSchema for u32 {
332 fn schema() -> Schema {
333 Schema::integer()
334 }
335}
336
337impl ToSchema for u16 {
338 fn schema() -> Schema {
339 Schema::integer()
340 }
341}
342
343impl ToSchema for u8 {
344 fn schema() -> Schema {
345 Schema::integer()
346 }
347}
348
349impl ToSchema for f64 {
350 fn schema() -> Schema {
351 Schema::number()
352 }
353}
354
355impl ToSchema for f32 {
356 fn schema() -> Schema {
357 Schema::number()
358 }
359}
360
361impl ToSchema for bool {
362 fn schema() -> Schema {
363 Schema::boolean()
364 }
365}
366
367impl<T: ToSchema> ToSchema for Vec<T> {
368 fn schema() -> Schema {
369 Schema::array(T::schema())
370 }
371}
372
373impl<T: ToSchema> ToSchema for Option<T> {
374 fn schema() -> Schema {
375 T::schema().nullable(true)
376 }
377}
378
379impl ToSchema for serde_json::Value {
380 fn schema() -> Schema {
381 <Schema as Default>::default()
382 }
383}