utility_macros_internals/derive/
record.rs1use convert_case::{Case, Casing as _};
2use proc_macro2::{Span, TokenStream, TokenTree};
3use quote::quote;
4use syn::{Data, DeriveInput, Ident, Meta};
5
6pub fn record_impl(
7 DeriveInput {
8 attrs: type_attrs,
9 ident: type_ident,
10 data,
11 ..
12 }: DeriveInput,
13) -> TokenStream {
14 let Data::Enum(data) = data else {
15 panic!("Expected Enum")
16 };
17
18 let mut impls = Vec::new();
19
20 for attr in &type_attrs {
21 let Meta::List(meta) = &attr.meta else {
22 continue;
23 };
24
25 if meta
26 .path
27 .segments
28 .first()
29 .map_or(true, |s| s.ident != "record")
30 {
31 continue;
32 }
33
34 let mut tokens = meta.tokens.clone().into_iter();
35
36 let Some(TokenTree::Ident(ident)) = tokens.next() else {
37 panic!("Expected ident");
38 };
39
40 match tokens.next() {
41 Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {}
42 _ => {
43 panic!("Expected \"=>\"");
44 }
45 }
46
47 match tokens.next() {
48 Some(TokenTree::Punct(punct)) if punct.as_char() == '>' => {}
49 _ => {
50 panic!("Expected \"=>\"");
51 }
52 }
53
54 let ty = tokens.next().expect("Expected type");
55 match &ty {
56 TokenTree::Literal(_) | TokenTree::Punct(_) => panic!("Expected ident or group"),
57 _ => {}
58 }
59
60 let variants = data.variants.clone().into_iter().collect::<Vec<_>>();
61
62 let idents = variants
63 .clone()
64 .into_iter()
65 .map(|v| {
66 Ident::new(
67 v.ident.to_string().to_case(Case::Snake).as_str(),
68 Span::call_site(),
69 )
70 })
71 .collect::<Vec<_>>();
72
73 impls.push(quote! {
74 utility_macros::_um::_sa::assert_impl_all! (#ty: Sized);
75
76 pub struct #ident {
77 #(pub #idents: #ty),*
78 }
79
80 impl utility_macros::_um::record::HasRecord for #type_ident {
81 type Record = #ident;
82 }
83
84 impl utility_macros::_um::record::Record for #ident {
85 type Keys = #type_ident;
86 type Type = #ty;
87
88 fn keys(&self) -> Vec<Self::Keys> {
89 vec![
90 #(#type_ident::#variants),*
91 ]
92 }
93
94 fn values(&self) -> Vec<&Self::Type> {
95 vec![
96 #(&self.#idents),*
97 ]
98 }
99 fn values_mut(&mut self) -> Vec<&mut Self::Type> {
100 vec![
101 #(&mut self.#idents),*
102 ]
103 }
104
105 fn entries(&self) -> Vec<(Self::Keys, &Self::Type)> {
106 vec![
107 #((#type_ident::#variants, &self.#idents)),*
108 ]
109 }
110 fn entires_mut(&mut self) -> Vec<(Self::Keys, &mut Self::Type)> {
111 vec![
112 #((#type_ident::#variants, &mut self.#idents)),*
113 ]
114 }
115
116 fn try_from_entries(entries: Vec<(Self::Keys, Self::Type)>) -> utility_macros::_um::error::Result<Self> {
117 #(let mut #idents = Option::<Self::Type>::None;)*
118
119 for (k, v) in entries {
120 match k {
121 #(
122 #type_ident::#variants => {
123 if let Some(_) = #idents {
124 return Err(utility_macros::_um::error::Error::DuplicateKey(
125 concat!(stringify!(#type_ident), "::", stringify!(#variants))
126 ));
127 }
128 #idents = Some(v);
129 }
130 ),*
131 }
132 }
133
134 Ok(Self {
135 #(
136 #idents: #idents.ok_or(utility_macros::_um::error::Error::MissingKey(
137 concat!(stringify!(#type_ident), "::", stringify!(#variants))
138 ))?
139 ),*
140 })
141 }
142 }
143
144 impl std::ops::Index<#type_ident> for #ident {
145 type Output = #ty;
146
147 fn index(&self, index: #type_ident) -> &Self::Output {
148 match index {
149 #(#type_ident::#variants => &self.#idents),*
150 }
151 }
152 }
153
154 impl std::ops::IndexMut<#type_ident> for #ident {
155 fn index_mut(&mut self, index: #type_ident) -> &mut Self::Output {
156 match index {
157 #(#type_ident::#variants => &mut self.#idents),*
158 }
159 }
160
161 }
162 });
163 }
164
165 quote! {
166 #(#impls)*
167 }
168}