1use std::collections::BTreeMap;
6
7pub use junction_typeinfo_derive::TypeInfo;
8
9#[derive(Clone, Debug, PartialEq, Eq)]
25pub enum Kind {
26 Bool,
27 String,
28 Int,
29 Float,
30 Duration,
31 Union(&'static str, Vec<Variant>),
32 Tuple(Vec<Kind>),
33 Array(Box<Kind>),
34 Map(Box<Kind>, Box<Kind>),
35 Object(&'static str),
36}
37
38pub trait TypeInfo {
43 fn kind() -> Kind;
45
46 fn doc() -> Option<&'static str> {
48 None
49 }
50
51 fn fields() -> Vec<Field> {
54 Vec::new()
55 }
56
57 fn nullable() -> bool {
62 false
63 }
64
65 fn item() -> Item {
67 Item {
68 kind: Self::kind(),
69 fields: Self::fields(),
70 nullable: Self::nullable(),
71 doc: Self::doc(),
72 }
73 }
74
75 fn variant_fields() -> Vec<Field> {
78 let mut fields: BTreeMap<&str, Vec<_>> = BTreeMap::new();
79
80 if let Kind::Union(_, variants) = Self::kind() {
81 for variant in variants {
82 if let Variant::Struct(v) = variant {
83 for field in v.fields {
84 let fields: &mut Vec<Field> = fields.entry(field.name).or_default();
85
86 match fields.first_mut() {
87 Some(f) => {
88 merge_fields(f, field);
89 }
90 _ => fields.push(field),
91 }
92 }
93 }
94 }
95 }
96
97 let mut fields: Vec<_> = fields.into_values().flatten().collect();
98 fields.sort_by_key(|f| f.name);
99 fields.dedup_by_key(|f| f.name);
100 fields
101 }
102
103 fn flatten_fields() -> Vec<Field> {
106 match Self::kind() {
107 Kind::Union(_, _) => Self::variant_fields(),
108 Kind::Object(_) => Self::fields(),
109 _ => Vec::new(),
110 }
111 }
112}
113
114fn merge_fields(a: &mut Field, b: Field) {
115 if a.kind == b.kind {
117 return;
118 }
119
120 match &mut a.kind {
122 Kind::Union(_, _) => (),
123 other => {
124 a.doc = None;
125 a.kind = Kind::Union(a.name, vec![Variant::Newtype(other.clone())]);
126 }
127 }
128 let a_vars = match &mut a.kind {
130 Kind::Union(_, vars) => vars,
131 _ => unreachable!(),
132 };
133 let b_vars = match b.kind {
135 Kind::Union(_, vars) => vars,
136 other => vec![Variant::Newtype(other)],
137 };
138 a_vars.extend(b_vars);
139 a_vars.dedup();
140}
141
142#[derive(Clone, Debug, PartialEq, Eq)]
144pub struct Item {
145 pub kind: Kind,
146 pub fields: Vec<Field>,
147 pub nullable: bool,
148 pub doc: Option<&'static str>,
149}
150
151#[derive(Clone, Debug, PartialEq, Eq)]
153pub struct Field {
154 pub name: &'static str,
155 pub kind: Kind,
156 pub nullable: bool,
157 pub doc: Option<&'static str>,
158}
159
160#[derive(Clone, Debug, PartialEq, Eq)]
162pub enum Variant {
163 Literal(&'static str),
164 Newtype(Kind),
165 Tuple(Vec<Kind>),
166 Struct(StructVariant),
167}
168
169#[derive(Clone, Debug, PartialEq, Eq)]
171pub struct StructVariant {
172 pub parent: &'static str,
173 pub name: &'static str,
174 pub doc: Option<&'static str>,
175 pub fields: Vec<Field>,
176}
177
178macro_rules! impl_type {
179 ($ty:ty, $kind:expr) => {
180 impl crate::TypeInfo for $ty {
181 fn kind() -> crate::Kind {
182 $kind
183 }
184 }
185 };
186}
187
188impl_type!(bool, Kind::Bool);
190
191impl_type!(String, Kind::String);
193impl_type!(&'static str, Kind::String);
194
195impl_type!(u8, Kind::Int);
201impl_type!(u16, Kind::Int);
202impl_type!(u32, Kind::Int);
203impl_type!(i8, Kind::Int);
204impl_type!(i16, Kind::Int);
205impl_type!(i32, Kind::Int);
206
207impl_type!(f32, Kind::Float);
209impl_type!(f64, Kind::Float);
210
211impl<T: TypeInfo> TypeInfo for Option<T> {
213 fn kind() -> Kind {
214 T::kind()
215 }
216
217 fn nullable() -> bool {
218 true
219 }
220
221 fn fields() -> Vec<Field> {
222 T::fields()
223 }
224}
225
226impl<T: TypeInfo> TypeInfo for Vec<T> {
228 fn kind() -> Kind {
229 crate::Kind::Array(Box::new(T::kind()))
230 }
231
232 fn fields() -> Vec<Field> {
233 Vec::new()
234 }
235}
236
237impl<K: TypeInfo, V: TypeInfo> TypeInfo for BTreeMap<K, V> {
238 fn kind() -> Kind {
239 crate::Kind::Map(Box::new(K::kind()), Box::new(V::kind()))
240 }
241}
242
243macro_rules! tuple_impl {
244 ( $($type_param:tt),+ ) => {
245 impl<$($type_param: crate::TypeInfo),+> crate::TypeInfo for ($($type_param),+,) {
247 fn kind() -> Kind {
248 crate::Kind::Tuple(vec![
249 $(
250 <$type_param as crate::TypeInfo>::kind(),
251 )+
252 ])
253 }
254 }
255 };
256}
257
258tuple_impl!(T1);
259tuple_impl!(T1, T2);
260tuple_impl!(T1, T2, T3);
261tuple_impl!(T1, T2, T3, T4);
262tuple_impl!(T1, T2, T3, T4, T5);
263
264#[doc(hidden)]
278#[allow(unused)]
279#[cfg(doctest)]
280fn test_unsupported_unit_struct() {
281 panic!("this function is just a doctest")
282}
283
284#[doc(hidden)]
291#[allow(unused)]
292#[cfg(doctest)]
293fn test_unsupported_fieldless_tuple_struct() {
294 panic!("this function is just a doctest")
295}
296
297#[doc(hidden)]
304#[allow(unused)]
305#[cfg(doctest)]
306fn test_unsupported_newtype_struct() {
307 panic!("this function is just a doctest")
308}
309
310#[doc(hidden)]
320#[allow(unused)]
321#[cfg(doctest)]
322fn test_unsupported_union() {
323 panic!("this function is just a doctest")
324}
325
326#[cfg(doctest)]
338fn test_unsupported_serde_flatten() {
339 panic!("this function is just a doctest")
340}