1use std::collections::HashMap;
2
3use openapiv3::{ReferenceOr, Schema};
4
5#[cfg(feature = "actix")]
6mod actix;
7
8#[cfg(feature = "axum")]
9mod axum;
10
11#[cfg(feature = "chrono")]
12mod chrono;
13#[cfg(feature = "cookies")]
14mod cookies;
15#[cfg(feature = "phonenumber")]
16mod phonenumber;
17#[cfg(feature = "sqlx")]
18mod sqlx;
19#[cfg(feature = "time")]
20mod time;
21
22#[cfg(feature = "bigdecimal")]
23mod bigdecimal;
24mod http;
25#[cfg(feature = "sid")]
26mod sid;
27mod tuple;
28
29pub trait OaSchema {
30 fn schema() -> Schema;
31
32 fn schema_ref() -> ReferenceOr<Schema> {
33 ReferenceOr::Item(Self::schema())
34 }
35 #[doc(hidden)]
37 fn body_schema() -> Option<ReferenceOr<Schema>> {
38 Some(Self::schema_ref())
39 }
40}
41
42pub struct SchemaRegister {
43 pub name: &'static str,
44 pub constructor: &'static (dyn Sync + Send + Fn() -> Schema),
45}
46
47inventory::collect!(SchemaRegister);
48
49#[macro_export]
50macro_rules! impl_oa_schema {
51 ($t:ty,$schema:expr) => {
52 impl $crate::OaSchema for $t {
53 fn schema() -> $crate::Schema {
54 $schema
55 }
56 }
57 };
58}
59
60#[macro_export]
61macro_rules! impl_oa_schema_passthrough {
62 ($t:ty) => {
63 impl<T> $crate::OaSchema for $t
64 where
65 T: $crate::OaSchema,
66 {
67 fn schema_ref() -> $crate::ReferenceOr<$crate::Schema> {
68 T::schema_ref()
69 }
70
71 fn schema() -> $crate::Schema {
72 T::schema()
73 }
74 }
75 };
76}
77
78impl_oa_schema!(bool, Schema::new_bool());
79
80impl_oa_schema!(usize, Schema::new_integer());
81impl_oa_schema!(isize, Schema::new_integer());
82
83impl_oa_schema!(u8, Schema::new_integer());
84impl_oa_schema!(i8, Schema::new_integer());
85
86impl_oa_schema!(u16, Schema::new_integer());
87impl_oa_schema!(i16, Schema::new_integer());
88
89impl_oa_schema!(u32, Schema::new_integer());
90impl_oa_schema!(i32, Schema::new_integer());
91
92impl_oa_schema!(u64, Schema::new_integer());
93impl_oa_schema!(i64, Schema::new_integer());
94
95impl_oa_schema!(f32, Schema::new_number());
96impl_oa_schema!(f64, Schema::new_number());
97
98impl_oa_schema!(String, Schema::new_string());
99
100impl<T> OaSchema for Vec<T>
101where
102 T: OaSchema,
103{
104 fn schema() -> Schema {
105 let inner = T::schema();
106 Schema::new_array(inner)
107 }
108
109 fn schema_ref() -> ReferenceOr<Schema> {
110 let inner = T::schema_ref();
111 ReferenceOr::Item(Schema::new_array(inner))
112 }
113}
114
115impl<T> OaSchema for Option<T>
116where
117 T: OaSchema,
118{
119 fn schema() -> Schema {
120 let mut schema = T::schema();
121 schema.nullable = true;
122 schema
123 }
124
125 fn schema_ref() -> ReferenceOr<Schema> {
126 let mut schema = T::schema_ref();
127 let Some(s) = schema.as_mut() else {
128 return schema;
129 };
130 s.nullable = true;
131 schema
132 }
133}
134
135impl OaSchema for () {
136 fn schema() -> Schema {
137 panic!("Unit type has no schema")
138 }
139 fn body_schema() -> Option<ReferenceOr<Schema>> {
140 None
141 }
142}
143
144impl<K, V> OaSchema for HashMap<K, V>
145where
146 V: OaSchema,
147{
148 fn schema() -> Schema {
149 Schema::new_map(V::schema())
150 }
151
152 fn schema_ref() -> ReferenceOr<Schema> {
153 ReferenceOr::Item(Schema::new_map(V::schema_ref()))
154 }
155}
156
157#[cfg(feature = "uuid")]
158impl_oa_schema!(uuid::Uuid, Schema::new_string().with_format("uuid"));
159
160impl_oa_schema!(serde_json::Value, Schema::new_object());