1use std::borrow::Cow;
2use std::cell::{Cell, RefCell};
3use std::cmp::Reverse;
4use std::collections::{BTreeMap, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
5use std::fmt::Arguments;
6use std::ops::{Range, RangeInclusive};
7use std::sync::{atomic, Mutex, RwLock};
8
9use crate::schema::{Schema, SchemaType, TypeSchema};
10use crate::{Generator, Names};
11
12pub use jtd_derive_macros::JsonTypedef;
13
14pub trait JsonTypedef {
16 fn schema(generator: &mut Generator) -> Schema;
19
20 fn referenceable() -> bool {
23 true
24 }
25
26 fn names() -> Names;
30}
31
32macro_rules! impl_primitives {
33 ($($in:ty => $out:ident),*) => {
34 $(
35 impl JsonTypedef for $in {
36 fn schema(_: &mut Generator) -> Schema {
37 Schema {
38 ty: SchemaType::Type {
39 r#type: TypeSchema::$out,
40 },
41 ..Schema::default()
42 }
43 }
44
45 fn referenceable() -> bool {
46 false
47 }
48
49 fn names() -> Names {
50 Names {
51 short: TypeSchema::$out.name(),
52 long: TypeSchema::$out.name(),
53 nullable: false,
54 type_params: vec![],
55 const_params: vec![],
56 }
57 }
58 }
59 )*
60 };
61}
62
63impl_primitives! {
64 bool => Boolean,
66 u8 => Uint8,
67 u16 => Uint16,
68 u32 => Uint32,
69 i8 => Int8,
70 i16 => Int16,
71 i32 => Int32,
72 f32 => Float32,
73 f64 => Float64,
74 atomic::AtomicBool => Boolean,
75 atomic::AtomicU8 => Uint8,
76 atomic::AtomicU16 => Uint16,
77 atomic::AtomicU32 => Uint32,
78 atomic::AtomicI8 => Int8,
79 atomic::AtomicI16 => Int16,
80 atomic::AtomicI32 => Int32,
81 char => String,
82 String => String,
83 str => String
84}
85
86macro_rules! impl_wrappers {
88 ($($($path_parts:ident)::+ => $in:ident => $out:ident),*) => {
89 $(
90 impl JsonTypedef for $($path_parts)::+::$in {
91 fn schema(_: &mut Generator) -> Schema {
92 Schema {
93 ty: SchemaType::Type {
94 r#type: TypeSchema::$out,
95 },
96 ..Schema::default()
97 }
98 }
99
100 fn referenceable() -> bool {
101 true
102 }
103
104 fn names() -> Names {
105 Names {
106 short: stringify!($in),
107 long: stringify!($($path_parts)::+::$in),
108 nullable: false,
109 type_params: vec![],
110 const_params: vec![],
111 }
112 }
113 }
114 )*
115 };
116}
117
118impl_wrappers! {
119 std::num => NonZeroU8 => Uint8,
120 std::num => NonZeroU16 => Uint16,
121 std::num => NonZeroU32 => Uint32,
122 std::num => NonZeroI8 => Int8,
123 std::num => NonZeroI16 => Int16,
124 std::num => NonZeroI32 => Int32,
125
126 std::net => IpAddr => String,
127 std::net => Ipv4Addr => String,
128 std::net => Ipv6Addr => String,
129 std::net => SocketAddr => String,
130 std::net => SocketAddrV4 => String,
131 std::net => SocketAddrV6 => String,
132
133 std::path => Path => String
134}
135
136#[cfg(feature = "url")]
137impl_wrappers! {
138 url => Url => String
139}
140
141impl JsonTypedef for std::path::PathBuf {
142 fn schema(gen: &mut Generator) -> Schema {
143 gen.sub_schema::<std::path::Path>()
144 }
145
146 fn referenceable() -> bool {
147 false
148 }
149
150 fn names() -> Names {
151 std::path::Path::names()
152 }
153}
154
155impl<T: JsonTypedef> JsonTypedef for Option<T> {
156 fn schema(gen: &mut Generator) -> Schema {
157 let mut schema = gen.sub_schema::<T>();
158 schema.nullable = true;
159 schema
160 }
161
162 fn referenceable() -> bool {
163 false
164 }
165
166 fn names() -> Names {
167 let mut names = T::names();
168 names.nullable = true;
169 names
170 }
171}
172
173macro_rules! impl_array_like {
174 ($($in:ty),*) => {
175 $(
176 impl<T: JsonTypedef> JsonTypedef for $in {
177 fn schema(gen: &mut Generator) -> Schema {
178 Schema {
179 ty: SchemaType::Elements {
180 elements: Box::new(gen.sub_schema::<T>()),
181 },
182 ..Schema::default()
183 }
184 }
185
186 fn referenceable() -> bool {
187 false
188 }
189
190 fn names() -> Names {
191 Names {
192 short: "array",
193 long: "array",
194 nullable: false,
195 type_params: vec![T::names()],
196 const_params: vec![],
197 }
198 }
199 }
200 )*
201 };
202}
203
204impl_array_like!(
205 Vec<T>,
206 VecDeque<T>,
207 std::collections::BTreeSet<T>,
208 BinaryHeap<T>,
209 HashSet<T>,
210 LinkedList<T>,
211 [T]
212);
213
214impl<T: JsonTypedef, const N: usize> JsonTypedef for [T; N] {
215 fn schema(gen: &mut Generator) -> Schema {
216 Schema {
217 ty: SchemaType::Elements {
218 elements: Box::new(gen.sub_schema::<T>()),
219 },
220 ..Schema::default()
221 }
222 }
223
224 fn referenceable() -> bool {
225 false
226 }
227
228 fn names() -> Names {
229 Names {
230 short: "array",
231 long: "array",
232 nullable: false,
233 type_params: vec![T::names()],
234 const_params: vec![],
235 }
236 }
237}
238
239macro_rules! impl_map_like {
240 ($($in:ty),*) => {
241 $(
242 impl<K: ToString, V: JsonTypedef> JsonTypedef for $in {
243 fn schema(gen: &mut Generator) -> Schema {
244 Schema {
245 ty: SchemaType::Values {
246 values: Box::new(gen.sub_schema::<V>()),
247 },
248 ..Schema::default()
249 }
250 }
251
252 fn referenceable() -> bool {
253 false
254 }
255
256 fn names() -> Names {
257 Names {
258 short: "map",
259 long: "map",
260 nullable: false,
261 type_params: vec![V::names()],
262 const_params: vec![],
263 }
264 }
265 }
266 )*
267 };
268}
269
270impl_map_like!(BTreeMap<K, V>, HashMap<K, V>);
271
272macro_rules! impl_transparent {
273 ($($in:ty),*) => {
274 $(
275 impl<T: JsonTypedef> JsonTypedef for $in {
276 fn schema(gen: &mut Generator) -> Schema {
277 gen.sub_schema::<T>()
278 }
279
280 fn referenceable() -> bool {
281 false
282 }
283
284 fn names() -> Names {
285 T::names()
286 }
287 }
288 )*
289 };
290}
291
292impl_transparent!(
293 std::num::Wrapping<T>,
294 Cell<T>,
295 RefCell<T>,
296 Box<T>,
297 Mutex<T>,
298 RwLock<T>,
299 Reverse<T>
300);
301
302macro_rules! impl_transparent_lifetime {
303 ($($in:ty),*) => {
304 $(
305 impl<'a, T: JsonTypedef + ?Sized> JsonTypedef for $in {
306 fn schema(gen: &mut Generator) -> Schema {
307 gen.sub_schema::<T>()
308 }
309
310 fn referenceable() -> bool {
311 false
312 }
313
314 fn names() -> Names {
315 T::names()
316 }
317 }
318 )*
319 };
320}
321
322impl_transparent_lifetime!(&'a T, &'a mut T);
323
324impl<'a, T: JsonTypedef + Clone> JsonTypedef for Cow<'a, T> {
325 fn schema(gen: &mut Generator) -> Schema {
326 gen.sub_schema::<T>()
327 }
328
329 fn referenceable() -> bool {
330 false
331 }
332
333 fn names() -> Names {
334 T::names()
335 }
336}
337
338impl<'a> JsonTypedef for Arguments<'a> {
339 fn schema(_: &mut Generator) -> Schema {
340 Schema {
341 ty: SchemaType::Type {
342 r#type: TypeSchema::String,
343 },
344 ..Schema::default()
345 }
346 }
347
348 fn referenceable() -> bool {
349 false
350 }
351
352 fn names() -> Names {
353 Names {
354 short: "string",
355 long: "string",
356 nullable: false,
357 type_params: vec![],
358 const_params: vec![],
359 }
360 }
361}
362
363macro_rules! impl_range {
364 ($($in:ty),*) => {
365 $(
366 impl<T: JsonTypedef> JsonTypedef for $in {
367 fn schema(gen: &mut Generator) -> Schema {
368 Schema {
369 ty: SchemaType::Properties {
370 properties: [("start", gen.sub_schema::<T>()), ("end", gen.sub_schema::<T>())].into(),
371 optional_properties: [].into(),
372 additional_properties: false,
373 },
374 ..Schema::default()
375 }
376 }
377
378 fn referenceable() -> bool {
379 true
380 }
381
382 fn names() -> Names {
383 Names {
384 short: stringify!($in),
385 long: concat!("std::ops::", stringify!($in)),
386 nullable: false,
387 type_params: vec![T::names()],
388 const_params: vec![],
389 }
390 }
391 }
392 )*
393 };
394}
395
396impl_range!(Range<T>, RangeInclusive<T>);