Skip to main content

specta_util/
selection.rs

1// TODO: Should `specta-util` rexport `specta` for these macros???
2
3/// Specta compatible selection of struct fields.
4///
5/// ```ignore
6/// use specta_typescript::legacy::inline_ref;
7/// use specta_util::selection;
8///
9/// #[derive(Clone)]
10/// struct MyStruct {
11///     name: String,
12///     age: i32,
13///     is_verified: bool,
14///     password: String,
15/// }
16///
17/// let person = MyStruct {
18///     name: "Monty".into(),
19///     age: 7,
20///     is_verified: true,
21///     password: "password".into(),
22/// };
23/// let people = vec![person.clone(), person.clone()];
24///
25/// // Selection creates an anonymous struct with the subset of fields you want.
26/// assert_eq!(inline_ref(&selection!(person, {
27///     name,
28///     age
29/// }), &Default::default()).unwrap(), "{ name: string; age: number }");
30///
31/// // You can apply the selection to an array.
32/// assert_eq!(inline_ref(&selection!(people, [{
33///     name,
34///     age
35/// }]), &Default::default()).unwrap(), "{ name: string; age: number }[]");
36/// ```
37// TODO: better docs w/ example
38#[macro_export]
39macro_rules! selection {
40    ( $s:expr, { $($n:ident),+ $(,)? } as $name:ident ) => {{
41        #[allow(non_camel_case_types)]
42        mod selection {
43            #[derive(serde::Serialize, specta::Type)]
44            #[specta(inline)]
45            pub struct $name<$($n,)*> {
46                $(pub $n: $n),*
47            }
48        }
49        use selection::$name;
50        #[allow(non_camel_case_types)]
51        $name { $($n: $s.$n,)* }
52    }};
53    ( $s:expr, { $($n:ident),+ $(,)? } ) => {{
54        $crate::selection!($s, { $($n),+ } as Selection)
55    }};
56
57    ( $s:expr, [{ $($n:ident),+ $(,)? }] as $name:ident ) => {{
58        #[allow(non_camel_case_types)]
59        mod selection {
60            #[derive(serde::Serialize, specta::Type)]
61            #[specta(inline)]
62            pub struct $name<$($n,)*> {
63                $(pub $n: $n),*
64            }
65        }
66        use selection::$name;
67        #[allow(non_camel_case_types)]
68        $s.into_iter().map(|v| $name { $($n: v.$n,)* }).collect::<Vec<_>>()
69    }};
70    ( $s:expr, [{ $($n:ident),+ $(,)? }] ) => {{
71        $crate::selection!($s, [{ $($n),+ }] as Selection)
72    }};
73}