forked from specta-rs/rspc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathselection.rs
122 lines (112 loc) · 4.67 KB
/
selection.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#[macro_export]
macro_rules! selection {
( $s:expr, { $($n:ident),+ } ) => {{
#[allow(non_camel_case_types)]
mod selection {
#[derive(serde::Serialize)]
pub struct Selection<$($n,)*> {
$(pub $n: $n,)*
}
impl<$($n: $crate::internal::specta::Type + 'static,)*> $crate::internal::specta::Type for Selection<$($n,)*> {
const NAME: &'static str = "Selection";
fn inline(opts: $crate::internal::specta::DefOpts, _generics: &[$crate::internal::specta::DataType]) -> $crate::internal::specta::DataType {
$crate::internal::specta::DataType::Object($crate::internal::specta::ObjectType {
name: "Selection".to_string(),
tag: None,
generics: vec![],
fields: vec![$(
$crate::internal::specta::ObjectField {
name: stringify!($n).to_string(),
ty: <$n as $crate::internal::specta::Type>::reference(
$crate::internal::specta::DefOpts {
parent_inline: false,
type_map: opts.type_map,
},
&[]
),
optional: false,
flatten: false
}
),*],
type_id: Some(std::any::TypeId::of::<Self>()),
})
}
}
}
use selection::Selection;
#[allow(non_camel_case_types)]
Selection { $($n: $s.$n,)* }
}};
( $s:expr, [{ $($n:ident),+ }] ) => {{
#[allow(non_camel_case_types)]
mod selection {
#[derive(serde::Serialize)]
pub struct Selection<$($n,)*> {
$(pub $n: $n,)*
}
impl<$($n: $crate::internal::specta::Type + 'static,)*> $crate::internal::specta::Type for Selection<$($n,)*> {
const NAME: &'static str = "Selection";
fn inline(opts: $crate::internal::specta::DefOpts, _generics: &[$crate::internal::specta::DataType]) -> $crate::internal::specta::DataType {
$crate::internal::specta::DataType::Object($crate::internal::specta::ObjectType {
name: "Selection".to_string(),
tag: None,
generics: vec![],
fields: vec![$(
$crate::internal::specta::ObjectField {
name: stringify!($n).to_string(),
ty: <$n as $crate::internal::specta::Type>::reference(
$crate::internal::specta::DefOpts {
parent_inline: false,
type_map: opts.type_map,
},
&[]
),
optional: false,
flatten: false
}
),*],
type_id: Some(std::any::TypeId::of::<Self>())
})
}
}
}
use selection::Selection;
#[allow(non_camel_case_types)]
$s.into_iter().map(|v| Selection { $($n: v.$n,)* }).collect::<Vec<_>>()
}};
}
#[cfg(test)]
mod tests {
use specta::{ts::inline, Type};
fn ts_export_ref<T: Type>(_t: &T) -> String {
inline::<T>(&Default::default()).unwrap()
}
#[derive(Clone)]
#[allow(dead_code)]
struct User {
pub id: i32,
pub name: String,
pub email: String,
pub age: i32,
pub password: String,
}
#[test]
fn test_selection_macros() {
let user = User {
id: 1,
name: "Monty Beaumont".into(),
email: "[email protected]".into(),
age: 7,
password: "password123".into(),
};
let s1 = selection!(user.clone(), { name, age });
assert_eq!(s1.name, "Monty Beaumont".to_string());
assert_eq!(s1.age, 7);
assert_eq!(ts_export_ref(&s1), "{ name: string, age: number }");
let users = vec![user; 3];
let s2 = selection!(users, [{ name, age }]);
assert_eq!(s2[0].name, "Monty Beaumont".to_string());
assert_eq!(s2[0].age, 7);
assert_eq!(ts_export_ref(&s2), "{ name: string, age: number }[]");
}
}