jtd_derive/
trait.rs

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
14/// Types that have an associated [_Typedef_](https://jsontypedef.com/) schema.
15pub trait JsonTypedef {
16    /// Generate the [`Schema`] for the implementor type, according to how
17    /// the [`Generator`] is configured.
18    fn schema(generator: &mut Generator) -> Schema;
19
20    /// Returns `true` if this type can appear in the top-level definitions
21    /// and be referenced using the ["ref" form](https://jsontypedef.com/docs/jtd-in-5-minutes/#ref-schemas).
22    fn referenceable() -> bool {
23        true
24    }
25
26    /// Returns info about how to refer to this type within the
27    /// [_Typedef_](https://jsontypedef.com/) schema.
28    /// Mostly used to generate a name for the top-level definitions.
29    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    // actual primitives
65    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
86// Distinct types due to additional constraints
87macro_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>);