oasgen_core/
schema.rs

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    /// You should rarely if ever implement this method.
36    #[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());