predawn_schema/
to_schema.rs

1use 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        // nested types
49        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}