dofigen_lib/
json_schema.rs

1use crate::deserialize::*;
2///! This module provides a custom implementation of `JsonSchema`.
3use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
4use std::{borrow::Cow, str::FromStr};
5use struct_patch::Patch;
6
7#[cfg(feature = "permissive")]
8impl<T> JsonSchema for ParsableStruct<T>
9where
10    T: Clone + JsonSchema + FromStr,
11{
12    fn schema_id() -> Cow<'static, str> {
13        format!("ParsableStruct<{}>", T::schema_name()).into()
14    }
15
16    fn schema_name() -> Cow<'static, str> {
17        format!("ParsableStruct_{}", T::schema_name()).into()
18    }
19
20    fn json_schema(generator: &mut SchemaGenerator) -> Schema {
21        json_schema!({
22            "title": Self::schema_id(),
23            "oneOf": [
24                generator.subschema_for::<T>(),
25                generator.subschema_for::<String>(),
26            ]
27        })
28    }
29}
30
31#[cfg(feature = "permissive")]
32impl<T> JsonSchema for OneOrMany<T>
33where
34    T: Clone + JsonSchema,
35{
36    fn schema_id() -> Cow<'static, str> {
37        format!("OneOrMany<{}>", T::schema_name()).into()
38    }
39    fn schema_name() -> Cow<'static, str> {
40        format!("OneOrMany_{}", T::schema_name()).into()
41    }
42
43    fn json_schema(generator: &mut SchemaGenerator) -> Schema {
44        json_schema!({
45            "title": Self::schema_id(),
46            "oneOf": [
47                generator.subschema_for::<T>(),
48                {
49                    "type": "array",
50                    "items": generator.subschema_for::<T>()
51                }
52            ]
53        })
54    }
55}
56
57impl<T> JsonSchema for VecPatch<T>
58where
59    T: Clone + JsonSchema,
60{
61    fn schema_id() -> Cow<'static, str> {
62        format!("VecPatch<{}>", T::schema_name()).into()
63    }
64    fn schema_name() -> Cow<'static, str> {
65        format!("VecPatch_{}", T::schema_name()).into()
66    }
67
68    fn json_schema(generator: &mut SchemaGenerator) -> Schema {
69        let type_schema = generator.subschema_for::<T>();
70        let array_schema = json_schema!({
71            "type": "array",
72            "items": type_schema
73        });
74        let patterns_schema = json_schema!({
75            "type": "object",
76            "patternProperties": {
77                // ReplaceAll
78                r"_": array_schema,
79                // Replace
80                r"^\d+$": type_schema,
81                // InsertBefore
82                r"^\+\d+$": array_schema,
83                // InsertAfter
84                r"^\d+\+$": array_schema,
85                // Append
86                r"^\+$": array_schema,
87            }
88        });
89
90        let one_of = vec![
91            #[cfg(feature = "permissive")]
92            type_schema,
93            array_schema,
94            patterns_schema,
95        ];
96
97        json_schema!({
98            "title": Self::schema_id(),
99            "oneOf": one_of
100        })
101    }
102}
103
104impl<T, P> JsonSchema for VecDeepPatch<T, P>
105where
106    T: Clone + Patch<P> + From<P>,
107    P: Clone + JsonSchema,
108{
109    fn schema_id() -> Cow<'static, str> {
110        format!("VecDeepPatch<{}>", P::schema_name()).into()
111    }
112    fn schema_name() -> Cow<'static, str> {
113        format!("VecDeepPatch_{}", P::schema_name()).into()
114    }
115
116    fn json_schema(generator: &mut SchemaGenerator) -> Schema {
117        let type_schema = generator.subschema_for::<P>();
118        let array_schema = json_schema!({
119            "type": "array",
120            "items": type_schema
121        });
122        let patterns_schema = json_schema!({
123            "type": "object",
124            "patternProperties": {
125                // ReplaceAll
126                r"_": array_schema,
127                // Replace
128                r"^\d+$": type_schema,
129                // Patch
130                r"^\d+<$": type_schema,
131                // InsertBefore
132                r"^\+\d+$": array_schema,
133                // InsertAfter
134                r"^\d+\+$": array_schema,
135                // Append
136                r"^\+$": array_schema,
137            }
138        });
139
140        let one_of = vec![
141            #[cfg(feature = "permissive")]
142            type_schema,
143            array_schema,
144            patterns_schema,
145        ];
146
147        json_schema!({
148            "title": Self::schema_id(),
149            "oneOf": one_of
150        })
151    }
152}
153
154impl<K, V> JsonSchema for HashMapPatch<K, V>
155where
156    K: Clone + Eq + std::hash::Hash + JsonSchema,
157    V: Clone + JsonSchema,
158{
159    fn schema_id() -> Cow<'static, str> {
160        format!("HashMapPatch<{}, {}>", K::schema_name(), V::schema_name()).into()
161    }
162    fn schema_name() -> Cow<'static, str> {
163        format!("HashMapPatch_{}_{}", K::schema_name(), V::schema_name()).into()
164    }
165
166    fn json_schema(generator: &mut SchemaGenerator) -> Schema {
167        json_schema!({
168            "title": Self::schema_id(),
169            "type": "object",
170            "patternProperties": {
171                "^.+$": generator.subschema_for::<Option<V>>()
172            }
173        })
174    }
175}
176
177impl<K, V> JsonSchema for HashMapDeepPatch<K, V>
178where
179    K: Clone + Eq + std::hash::Hash + JsonSchema,
180    V: Clone + JsonSchema,
181{
182    fn schema_id() -> Cow<'static, str> {
183        format!(
184            "HashMapDeepPatch<{}, {}>",
185            K::schema_name(),
186            V::schema_name()
187        )
188        .into()
189    }
190    fn schema_name() -> Cow<'static, str> {
191        format!("HashMapDeepPatch_{}_{}", K::schema_name(), V::schema_name()).into()
192    }
193
194    fn json_schema(generator: &mut SchemaGenerator) -> Schema {
195        json_schema!({
196            "title": Self::schema_id(),
197            "type": "object",
198            "patternProperties": {
199                "^.+$": generator.subschema_for::<Option<V>>()
200            }
201        })
202    }
203}
204
205pub fn optional_string_or_number_schema(_gen: &mut SchemaGenerator) -> Schema {
206    json_schema!({
207          "type": [
208            "string",
209            "number",
210            "null"
211          ],
212          "default": null,
213          "nullable": true
214    })
215}