1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use quote::quote;
4use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Expr, Fields, Ident, LitInt};
5
6mod parser;
7
8use parser::*;
9
10#[proc_macro]
11pub fn tuple_traits_impl(input: TokenStream) -> TokenStream {
12 let max = parse_macro_input!(input as LitInt);
13 let max: usize = match max.base10_parse() {
14 Ok(v) => v,
15 Err(e) => return e.into_compile_error().into(),
16 };
17
18 let mut impls = vec![];
19 impls.push(quote! {
20 impl ::tuplez::ToPrimitive for ::tuplez::Unit {
21 type Primitive = ();
22 fn primitive(self) -> Self::Primitive {}
23 }
24 impl From<()> for ::tuplez::Unit {
25 fn from(_: ()) -> Self {
26 ::tuplez::Unit
27 }
28 }
29 #[cfg(not(feature = "any_array"))]
30 impl<T> ::tuplez::ToArray<T> for ::tuplez::Unit {
31 type Array = [T; 0];
32 type Iter<'a> = std::array::IntoIter<&'a T, 0> where Self: 'a, T: 'a;
33 type IterMut<'a> = std::array::IntoIter<&'a mut T, 0> where Self: 'a, T: 'a;
34 fn to_array(self) -> Self::Array {
35 Default::default()
36 }
37 fn iter<'a>(&'a self) -> Self::Iter<'a>
38 where
39 Self: 'a,
40 T: 'a
41 {
42 self.as_ref().to_array().into_iter()
43 }
44 fn iter_mut<'a>(&'a mut self) -> Self::IterMut<'a>
45 where
46 Self: 'a,
47 T: 'a
48 {
49 self.as_mut().to_array().into_iter()
50 }
51 }
52 #[cfg(not(feature = "any_array"))]
53 impl<T> From<[T; 0]> for ::tuplez::Unit {
54 fn from(_: [T; 0]) -> Self {
55 ::tuplez::Unit
56 }
57 }
58 });
59
60 let mut tys = vec![];
61 let mut pats = vec![];
62 for i in 0..max {
63 tys.push(Ident::new(&format!("T{i}"), Span::call_site()));
64 pats.push(Ident::new(&format!("v{i}"), Span::call_site()));
65 let count = LitInt::new(&format!("{}", i + 1), Span::call_site());
66 impls.push(quote! {
67 impl<#(#tys),*> ::tuplez::ToPrimitive for ::tuplez::tuple_t!(#(#tys),*) {
68 type Primitive = (#(#tys),*,);
69 fn primitive(self) -> Self::Primitive {
70 let ::tuplez::tuple_pat!(#(#pats),*) = self;
71 (#(#pats),*,)
72 }
73 }
74 impl<#(#tys),*> From<(#(#tys),*,)> for ::tuplez::tuple_t!(#(#tys),*) {
75 fn from((#(#pats),*,): (#(#tys),*,)) -> Self {
76 ::tuplez::tuple!(#(#pats),*)
77 }
78 }
79 #[cfg(not(feature = "any_array"))]
80 impl<T> ToArray<T> for ::tuplez::tuple_t!(T; #count) {
81 type Array = [T; #count];
82 type Iter<'a> = std::array::IntoIter<&'a T, #count> where Self: 'a, T: 'a;
83 type IterMut<'a> = std::array::IntoIter<&'a mut T, #count> where Self: 'a, T: 'a;
84 fn to_array(self) -> Self::Array {
85 let ::tuplez::tuple_pat!(#(#pats),*) = self;
86 [#(#pats),*]
87 }
88 fn iter<'a>(&'a self) -> Self::Iter<'a>
89 where
90 Self: 'a,
91 T: 'a
92 {
93 self.as_ref().to_array().into_iter()
94 }
95 fn iter_mut<'a>(&'a mut self) -> Self::IterMut<'a>
96 where
97 Self: 'a,
98 T: 'a
99 {
100 self.as_mut().to_array().into_iter()
101 }
102 }
103 #[cfg(not(feature = "any_array"))]
104 impl<T> From<[T; #count]> for ::tuplez::tuple_t!(T; #count) {
105 fn from([#(#pats),*]: [T; #count]) -> Self {
106 ::tuplez::tuple!(#(#pats),*)
107 }
108 }
109 });
110 }
111
112 quote! {#(#impls)*}.into()
113}
114
115#[proc_macro]
116pub fn tuple(input: TokenStream) -> TokenStream {
117 let ReExportTuplez {
118 path,
119 other: TupleGen(exprs),
120 } = parse_macro_input!(input as ReExportTuplez<TupleGen>);
121 let mut unpack = quote!( #path::Unit );
122 for expr in exprs.into_iter().rev() {
123 unpack = quote!( #path::Tuple( #expr, #unpack) );
124 }
125 unpack.into()
126}
127
128#[proc_macro]
129pub fn tuple_t(input: TokenStream) -> TokenStream {
130 let ReExportTuplez {
131 path,
132 other: TupleType(types),
133 } = parse_macro_input!(input as ReExportTuplez<TupleType>);
134 let mut unpack = quote!( #path::Unit );
135 for ty in types.into_iter().rev() {
136 unpack = quote!( #path::Tuple< #ty, #unpack> );
137 }
138 unpack.into()
139}
140
141#[proc_macro]
142pub fn tuple_pat(input: TokenStream) -> TokenStream {
143 let ReExportTuplez {
144 path,
145 other: TuplePat { mut pats, leader },
146 } = parse_macro_input!(input as ReExportTuplez<TuplePat>);
147 let mut unpack;
148 if pats.is_empty() {
149 unpack = quote!(_);
150 } else if leader {
151 unpack = quote!(..);
152 for pat in pats.into_iter().rev() {
153 unpack = quote!( #path::Tuple( #pat, #unpack) );
154 }
155 } else {
156 let last = pats.pop().unwrap();
157 unpack = quote!(#last);
158 for pat in pats.into_iter().rev() {
159 unpack = quote!( #path::Tuple( #pat, #unpack) );
160 }
161 }
162 unpack.into()
163}
164
165#[proc_macro]
166pub fn get(input: TokenStream) -> TokenStream {
167 let TupleIndex { tup, index } = parse_macro_input!(input as TupleIndex);
168 let field = quote!(. 1);
169 let fields = vec![field.clone(); index];
170 quote!( (#tup) #(#fields)* . 0).into()
171}
172
173#[proc_macro]
174pub fn take(input: TokenStream) -> TokenStream {
175 let ReExportTuplez {
176 path,
177 other: result,
178 } = parse_macro_input!(input as ReExportTuplez<TupleTake>);
179 match result {
180 TupleTake {
181 tup,
182 ext: IndexOrType::Index(index),
183 } => {
184 let tup = quote!( let tup_ = #tup );
185 let field = quote!(. 1);
186 let mut fields = vec![field.clone(); index];
187 let element = quote!( tup_ #(#fields)* . 0 );
188 let mut unpack = quote!( tup_ #(#fields)* . 1 );
189 for _ in 0..index {
190 _ = fields.pop();
191 unpack = quote!( #path::Tuple( tup_ #(#fields)* . 0, #unpack ) )
192 }
193 quote!({
194 #tup ;
195 ( #element, #unpack )
196 })
197 }
198 TupleTake {
199 tup,
200 ext: IndexOrType::Type(ty),
201 } => quote!({
202 use #path::TupleLike;
203 let (element_, remainder_): (#ty, _) = (#tup).take();
204 (element_, remainder_)
205 }),
206 }
207 .into()
208}
209
210#[proc_macro]
211pub fn pick(input: TokenStream) -> TokenStream {
212 let TuplePick { tup, indices } = parse_macro_input!(input as TuplePick);
213 let tup = quote!( let tup_ = #tup );
214 let max = *indices.iter().max().unwrap();
215 let unpicked_indices = (0..max).filter(|i| !indices.contains(i));
216 let field = quote!(. 1);
217 let picked = indices
218 .iter()
219 .map(|x| {
220 let fields = vec![field.clone(); *x];
221 quote!( tup_ #(#fields)* .0 )
222 })
223 .rfold(
224 quote!(tuplez::Unit),
225 |packed, token| quote!( tuplez::Tuple( #token, #packed ) ),
226 );
227 let tail = {
228 let fields = vec![field.clone(); max];
229 quote!( tup_ #(#fields)* .1 )
230 };
231 let unpicked = unpicked_indices
232 .map(|x| {
233 let fields = vec![field.clone(); x];
234 quote!( tup_ #(#fields)* .0 )
235 })
236 .rfold(
237 tail,
238 |packed, token| quote!( tuplez::Tuple( #token, #packed ) ),
239 );
240 quote!({
241 #tup ;
242 ( #picked, #unpicked )
243 })
244 .into()
245}
246
247#[proc_macro]
248pub fn split_at(input: TokenStream) -> TokenStream {
249 let ReExportTuplez {
250 path,
251 other: TupleIndex { tup, index },
252 } = parse_macro_input!(input as ReExportTuplez<TupleIndex>);
253 let tup = quote!( let tup_ = #tup );
254 let field = quote!(. 1);
255 let mut fields = vec![field.clone(); index];
256 let mut unpack = quote!( #path::Unit );
257 let other = quote!( tup_ #(#fields)* );
258 for _ in 0..index {
259 _ = fields.pop();
260 unpack = quote!( #path::Tuple( tup_ #(#fields)* . 0, #unpack ) );
261 }
262 quote!({
263 #tup ;
264 ( #unpack, #other )
265 })
266 .into()
267}
268
269#[proc_macro]
270pub fn swap_at(input: TokenStream) -> TokenStream {
271 let TupleSwap { tup, left, right } = parse_macro_input!(input as TupleSwap);
272 let tup = quote!( let mut tup_ = #tup );
273 let field = quote!(. 1);
274 let max = std::cmp::max(*left.iter().max().unwrap(), *right.iter().max().unwrap());
275 let mut indices: Vec<usize> = (0..=max).collect();
276 for i in 0..left.len() {
277 indices.swap(left[i], right[i]);
278 }
279 let tail = {
280 let fields = vec![field.clone(); max];
281 quote!( tup_ #(#fields)* .1 )
282 };
283 let output = indices
284 .into_iter()
285 .map(|x| {
286 let fields = vec![field.clone(); x];
287 quote!( tup_ #(#fields)* .0 )
288 })
289 .rfold(
290 tail,
291 |packed, token| quote!( tuplez::Tuple( #token, #packed ) ),
292 );
293
294 quote!({
295 #tup ;
296 #output
297 })
298 .into()
299}
300
301#[proc_macro]
302pub fn apply(input: TokenStream) -> TokenStream {
303 let TupleApply {
304 tup,
305 mut func,
306 args,
307 } = parse_macro_input!(input as TupleApply);
308 let tup = quote!( #[allow(unused_mut)] let mut tup_ = #tup );
309 let field_at = |index| {
310 let field = quote!(. 1);
311 let fields = vec![field.clone(); index];
312 parse_quote!( tup_ #(#fields)* . 0)
313 };
314 args.0
315 .into_iter()
316 .map(move |arg| match arg {
317 TupleArg::Move(index) => field_at(index),
318 TupleArg::Ref(index) => {
319 let arg = field_at(index);
320 parse_quote!(& #arg)
321 }
322 TupleArg::Mut(index) => {
323 let arg = field_at(index);
324 parse_quote!(& mut #arg)
325 }
326 })
327 .for_each(|arg| match &mut func {
328 Expr::Call(call) => call.args.push(arg),
329 Expr::MethodCall(call) => call.args.push(arg),
330 _ => (),
331 });
332 quote!({
333 #tup ;
334 #func
335 })
336 .into()
337}
338
339#[proc_macro]
340pub fn mapper(input: TokenStream) -> TokenStream {
341 let ReExportTuplez {
342 path,
343 other: Mapper(rules),
344 } = parse_macro_input!(input as ReExportTuplez<Mapper>);
345 let rules = rules.into_iter().map(
346 |Rule {
347 generic,
348 mut inputs,
349 output_type,
350 body,
351 }| {
352 let (x, tyx, mutx) = inputs.pop_front().unwrap();
353 let tyx = tyx.unwrap();
354 let mutx = if mutx { quote!(mut) } else { quote!() };
355 let tyout = output_type.unwrap();
356
357 quote!(
358 impl #generic Mapper<#tyx> for __Mapper {
359 type Output = #tyout;
360 type NextMapper = Self;
361 fn map(self, value: #tyx) -> (Self::Output, Self::NextMapper) {
362 let f = | #mutx #x : #tyx | -> #tyout #body;
363 (f(value), self)
364 }
365 }
366 )
367 },
368 );
369 quote!(
370 {
371 use #path::foreach::Mapper;
372 #[derive(Copy, Clone, Debug)]
373 struct __Mapper;
374 #(#rules)*
375 __Mapper
376 }
377 )
378 .into()
379}
380
381#[proc_macro]
382pub fn folder(input: TokenStream) -> TokenStream {
383 let ReExportTuplez {
384 path,
385 other: Folder(rules),
386 } = parse_macro_input!(input as ReExportTuplez<Folder>);
387 let rules = rules.into_iter().map(
388 |Rule {
389 generic,
390 mut inputs,
391 output_type,
392 body,
393 }| {
394 let (acc, tyacc, mutacc) = inputs.pop_front().unwrap();
395 let (x, tyx, mutx) = inputs.pop_front().unwrap();
396 let tyacc = tyacc.unwrap();
397 let mutacc = if mutacc { quote!(mut) } else { quote!() };
398 let tyx = tyx.unwrap();
399 let mutx = if mutx { quote!(mut) } else { quote!() };
400 let tyout = output_type.unwrap();
401
402 quote!(
403 impl #generic Folder<#tyx, #tyout> for __Folder {
404 type Output = #tyout;
405 type NextFolder = Self;
406 fn fold(self, acc: #tyacc, value: #tyx) -> (Self::Output, Self::NextFolder) {
407 let f = | #mutacc #acc: #tyacc, #mutx #x: #tyx | -> #tyout #body;
408 (f(acc, value), self)
409 }
410 }
411 )
412 },
413 );
414 quote!(
415 {
416 use #path::fold::Folder;
417 #[derive(Copy, Clone, Debug)]
418 struct __Folder;
419 #(#rules)*
420 __Folder
421 }
422 )
423 .into()
424}
425
426#[proc_macro]
427pub fn unary_pred(input: TokenStream) -> TokenStream {
428 let ReExportTuplez {
429 path,
430 other: UnaryPredicate(rules),
431 } = parse_macro_input!(input as ReExportTuplez<UnaryPredicate>);
432 let rules = rules.into_iter().map(
433 |Rule {
434 generic,
435 mut inputs,
436 output_type,
437 body,
438 }| {
439 let (x, tyx, mutx) = inputs.pop_front().unwrap();
440 let tyx = tyx.unwrap();
441 let mutx = if mutx { quote!(mut) } else { quote!() };
442 let tyout = output_type.unwrap();
443
444 quote!(
445 impl #generic Mapper<& #tyx> for __UnaryPred {
446 type Output = #tyout;
447 type NextMapper = Self;
448 fn map(self, value: & #tyx) -> (Self::Output, Self::NextMapper) {
449 let f = | #mutx #x : & #tyx | -> #tyout #body;
450 (f(value), self)
451 }
452 }
453 )
454 },
455 );
456 quote!(
457 {
458 use #path::foreach::Mapper;
459 #[derive(Copy, Clone, Debug)]
460 struct __UnaryPred;
461 #(#rules)*
462 __UnaryPred
463 }
464 )
465 .into()
466}
467
468#[proc_macro_derive(Tupleize)]
469pub fn tupleize_derive(input: TokenStream) -> TokenStream {
470 let DeriveInput {
471 attrs: _,
472 vis: _,
473 ident,
474 generics,
475 data,
476 } = parse_macro_input!(input as DeriveInput);
477
478 let Data::Struct(data) = data else {
479 return syn::Error::new(ident.span(), "expected struct")
480 .to_compile_error()
481 .into();
482 };
483 let (tuple_ty, from_tuple, to_tuple) = data.fields.iter().enumerate().rev().fold(
484 (quote!(tuplez::Unit), quote!(), quote!(tuplez::Unit)),
485 |(ty, from, to), (index, field)| {
486 let field_ty = &field.ty;
487 let ty = quote!( ::tuplez::Tuple< #field_ty, #ty > );
488 match &field.ident {
489 Some(ident) => {
490 let field = quote!(. 1);
491 let fields = vec![field.clone(); index];
492 let element = quote!( value #(#fields)* . 0);
493 let from = quote!( #ident: #element, #from );
494 let to = quote!( ::tuplez::Tuple( value . #ident, #to) );
495 (ty, from, to)
496 }
497 None => {
498 let field = quote!(. 1);
499 let fields = vec![field.clone(); index];
500 let from = quote!( value #(#fields)* . 0, #from );
501 let index = syn::Index::from(index);
502 let to = quote!( ::tuplez::Tuple( value . #index, #to) );
503 (ty, from, to)
504 }
505 }
506 },
507 );
508 let from_tuple = match &data.fields {
509 Fields::Named(_) => quote!( Self { #from_tuple } ),
510 Fields::Unnamed(_) => quote!( Self(#from_tuple) ),
511 Fields::Unit => quote!(Self),
512 };
513 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
514 quote!(
515 impl #impl_generics ::std::convert::From<#ident #ty_generics> for #tuple_ty #where_clause {
516 fn from(value: #ident #ty_generics) -> Self {
517 #to_tuple
518 }
519 }
520
521 impl #impl_generics ::std::convert::From<#tuple_ty> for #ident #ty_generics #where_clause {
522 fn from(value: #tuple_ty) -> Self {
523 #from_tuple
524 }
525 }
526
527 impl #impl_generics ::tuplez::Tupleize for #ident #ty_generics #where_clause {
528 type Equivalent = #tuple_ty;
529 }
530 )
531 .into()
532}