predawn_schema/
to_schema.rs1use std::{borrow::Cow, collections::BTreeMap};
2
3use openapiv3::{ReferenceOr, Schema};
4
5pub trait ToSchema {
6 const REQUIRED: bool = true;
7
8 fn key() -> String {
9 std::any::type_name::<Self>().replace("::", ".")
10 }
11
12 fn title() -> Cow<'static, str>;
13
14 fn schema_ref(
15 schemas: &mut BTreeMap<String, Schema>,
16 schemas_in_progress: &mut Vec<String>,
17 ) -> ReferenceOr<Schema> {
18 reference::<Self, _>(schemas, schemas_in_progress)
19 }
20
21 fn schema_ref_box(
22 schemas: &mut BTreeMap<String, Schema>,
23 schemas_in_progress: &mut Vec<String>,
24 ) -> ReferenceOr<Box<Schema>> {
25 reference::<Self, _>(schemas, schemas_in_progress)
26 }
27
28 fn schema(
29 schemas: &mut BTreeMap<String, Schema>,
30 schemas_in_progress: &mut Vec<String>,
31 ) -> Schema;
32}
33
34fn reference<S, T>(
35 schemas: &mut BTreeMap<String, Schema>,
36 schemas_in_progress: &mut Vec<String>,
37) -> ReferenceOr<T>
38where
39 S: ToSchema + ?Sized,
40{
41 let key = S::key();
42
43 let reference = ReferenceOr::Reference {
44 reference: format!("#/components/schemas/{}", key),
45 };
46
47 if !schemas.contains_key(&key) {
48 if schemas_in_progress.contains(&key) {
50 return reference;
51 }
52
53 schemas_in_progress.push(key);
54 let schema = S::schema(schemas, schemas_in_progress);
55 let key = schemas_in_progress.pop().expect("must have a name");
56
57 debug_assert_eq!(key, S::key());
58
59 schemas.insert(key, schema);
60 }
61
62 reference
63}