truck_derivers/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(debug_assertions), deny(warnings))]
3#![deny(clippy::all, rust_2018_idioms)]
4#![warn(
5    missing_docs,
6    missing_debug_implementations,
7    trivial_casts,
8    trivial_numeric_casts,
9    unsafe_code,
10    unstable_features,
11    unused_import_braces,
12    unused_qualifications
13)]
14
15use proc_macro::TokenStream;
16use proc_macro2::TokenStream as TokenStream2;
17use proc_macro_error::proc_macro_error;
18use quote::*;
19use syn::*;
20
21fn enumerate_impl_return_something<'a>(
22    variants: impl IntoIterator<Item = &'a Variant> + 'a,
23    method: TokenStream2,
24    method_variants: TokenStream2,
25) -> TokenStream2 {
26    let impls: Vec<_> = variants
27        .into_iter()
28        .map(|variant| {
29            let variant_name = &variant.ident;
30            let vec: Vec<_> = variant.fields.iter().collect();
31            match vec.len() {
32                0 => panic!("empty field!"),
33                1 => match &vec[0].ident {
34                    Some(ident) => quote! {
35                        Self::#variant_name { #ident } => #method(#ident, #method_variants)
36                    },
37                    None => quote! {
38                        Self::#variant_name(got) => #method(got, #method_variants)
39                    },
40                },
41                _ => unimplemented!(),
42            }
43        })
44        .collect();
45    quote! { match self { #(#impls),* } }
46}
47
48fn enumerate_impl_return_self<'a>(
49    variants: impl IntoIterator<Item = &'a Variant> + 'a,
50    method: TokenStream2,
51    method_variants: TokenStream2,
52) -> TokenStream2 {
53    let impls: Vec<_> = variants
54        .into_iter()
55        .map(|variant| {
56            let variant_name = &variant.ident;
57            let vec: Vec<_> = variant.fields.iter().collect();
58            match vec.len() {
59                0 => panic!("empty field!"),
60                1 => match &vec[0].ident {
61                    Some(ident) => {
62                        quote! {
63                            Self::#variant_name { #ident } => Self::#variant_name { #ident: #method(#ident, #method_variants) }
64                        }
65                    }
66                    None => {
67                        quote! {
68                            Self::#variant_name(got) => Self::#variant_name(#method(got, #method_variants))
69                        }
70                    }
71                },
72                _ => unimplemented!(),
73            }
74        })
75        .collect();
76    quote! {
77        match self {
78            #(#impls),*
79        }
80    }
81}
82
83#[derive(Clone, Debug)]
84struct Field {
85    var: TokenStream2,
86    ty: TokenStream2,
87}
88
89macro_rules! fields {
90    ($($var: tt : $ty: tt),*) => {
91        vec![$(Field {
92            var: quote! { $var },
93            ty: quote! { $ty },
94        }),*]
95    };
96}
97
98#[derive(Clone, Debug)]
99struct Method<I> {
100    name: TokenStream2,
101    generics: Option<TokenStream2>,
102    self_field: TokenStream2,
103    fields: Vec<Field>,
104    return_type: TokenStream2,
105    variants: I,
106    trait_name: TokenStream2,
107}
108
109macro_rules! methods {
110    (
111        $variants: ident, $trait_name: ident,
112        $(fn $name: ident (
113            $self_field: expr,
114            $($var: ident: $ty: ty),*$(,)?
115        ) -> $return_type: ty),*$(,)?
116    ) => {
117        vec![$(Method {
118            name: quote! { $name },
119            generics: None,
120            self_field: quote! { $self_field, },
121            fields: fields!($($var: $ty),*),
122            return_type: quote! { $return_type },
123            variants: $variants,
124            trait_name: $trait_name.clone(),
125        }
126        .to_token_stream()),*]
127    };
128    (
129        $variants: ident, $trait_name: ident,
130        $(fn $name: ident <$($gen: ident: $path: path),*> (
131            $self_field: expr,
132            $($var: ident: $ty: ty),*$(,)?
133        ) -> $return_type: ty),*$(,)?
134    ) => {
135        vec![$(Method {
136            name: quote! { $name },
137            generics: Some(quote! { <$($gen: $path),*> }),
138            self_field: quote! { $self_field, },
139            fields: fields!($($var: $ty),*),
140            return_type: quote! { $return_type },
141            variants: $variants,
142            trait_name: $trait_name.clone(),
143        }
144        .to_token_stream()),*]
145    };
146}
147
148impl<'a, I> Method<I>
149where I: IntoIterator<Item = &'a Variant> + 'a + Copy
150{
151    fn to_token_stream(&'a self) -> TokenStream2 {
152        let method_name = &self.name;
153        let generics = &self.generics;
154        let trait_name = &self.trait_name;
155        let self_field = &self.self_field;
156        let fields = self
157            .fields
158            .iter()
159            .map(|f| {
160                let var = &f.var;
161                let ty = &f.ty;
162                quote! { #var: #ty }
163            })
164            .collect::<Vec<_>>();
165        let vals = self.fields.iter().map(|f| &f.var).collect::<Vec<_>>();
166        let return_type = &self.return_type;
167        let implement = if return_type.to_string() == "Self" {
168            enumerate_impl_return_self::<'_>(
169                self.variants,
170                quote! { #trait_name::#method_name },
171                quote! { #(#vals),* },
172            )
173        } else {
174            enumerate_impl_return_something::<'a>(
175                self.variants,
176                quote! { #trait_name::#method_name },
177                quote! { #(#vals),* },
178            )
179        };
180        quote! {
181            fn #method_name #generics (#self_field #(#fields),*) -> #return_type { #implement }
182        }
183    }
184}
185
186/// Derive macro generating an impl of the trait `BoundedCurve` for Enums or single field tuple structs.
187#[proc_macro_error]
188#[proc_macro_derive(BoundedCurve)]
189pub fn derive_bounded_curve(input: TokenStream) -> TokenStream {
190    let input = parse_macro_input!(input as DeriveInput);
191    let trait_name = quote! { truck_geotrait::BoundedCurve };
192    let ty = input.ident;
193    let gen = input.generics;
194    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
195    match input.data {
196        Data::Enum(DataEnum { ref variants, .. }) => {
197            let variant = variants.into_iter().next().expect("empty enum!");
198            let tys: Vec<_> = variant
199                .fields
200                .iter()
201                .map(|field| &field.ty)
202                .collect();
203            let top_ty = &tys[0];
204            let tys = &tys[1..];
205            let methods = methods! {
206                variants, trait_name,
207                fn range_tuple(&self,) -> (f64, f64),
208                fn front(&self,) -> Self::Point,
209                fn back(&self,) -> Self::Point,
210            };
211            quote! {
212                #[automatically_derived]
213                impl #gen #trait_name for #ty #gen
214                where
215                    #(#where_predicates,)*
216                    #top_ty: #trait_name,
217                    #(#tys: #trait_name<Point = <#top_ty as ParametricCurve>::Point>,)*
218                    Self: truck_geotrait::ParametricCurve<Point = <#top_ty as ParametricCurve>::Point>, {
219                    #(#methods)*
220                }
221            }
222        }
223        Data::Struct(DataStruct { ref fields, .. }) => {
224            let field: Vec<_> = fields.iter().collect();
225            if field.len() != 1 || field[0].ident.is_some() {
226                unimplemented!();
227            }
228            let field_type = &field[0].ty;
229            quote! {
230                #[automatically_derived]
231                impl #gen #trait_name for #ty #gen
232                where
233                    #(#where_predicates,)*
234                    #field_type: #trait_name,
235                    Self: truck_geotrait::ParametricCurve<Point
236                        = <#field_type as truck_geotrait::ParametricCurve>::Point>, {
237                    fn range_tuple(&self) -> (f64, f64) { self.0.range_tuple() }
238                    fn front(&self) -> Self::Point { self.0.front() }
239                    fn back(&self) -> Self::Point { self.0.back() }
240                }
241            }
242        }
243        _ => unimplemented!(),
244    }
245    .into()
246}
247
248/// Derive macro generating an impl of the trait `BoundedSurface` for Enums or single field tuple structs.
249#[proc_macro_error]
250#[proc_macro_derive(BoundedSurface)]
251pub fn derive_bounded_surface(input: TokenStream) -> TokenStream {
252    let input = parse_macro_input!(input as DeriveInput);
253    let trait_name = quote! { truck_geotrait::BoundedSurface };
254    let ty = input.ident;
255    let gen = input.generics;
256    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
257    match input.data {
258        Data::Enum(DataEnum { ref variants, .. }) => {
259            let variant = variants.into_iter().next().expect("empty enum!");
260            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
261            let methods = methods! {
262                variants, trait_name,
263                fn range_tuple(&self,) -> ((f64, f64), (f64, f64)),
264            };
265            quote! {
266                #[automatically_derived]
267                impl #gen #trait_name for #ty #gen
268                where
269                    #(#where_predicates,)*
270                    #(#tys: #trait_name,)* {
271                    #(#methods)*
272                }
273            }
274        }
275        Data::Struct(DataStruct { ref fields, .. }) => {
276            let field: Vec<_> = fields.iter().collect();
277            if field.len() != 1 || field[0].ident.is_some() {
278                unimplemented!();
279            }
280            let field_type = &field[0].ty;
281            quote! {
282                #[automatically_derived]
283                impl #gen #trait_name for #ty #gen
284                where
285                    #(#where_predicates,)*
286                    #field_type: #trait_name {
287                    fn range_tuple(&self) -> ((f64, f64), (f64, f64)) {
288                        self.0.range_tuple()
289                    }
290                }
291            }
292        }
293        _ => unimplemented!(),
294    }
295    .into()
296}
297
298/// Derive macro generating an impl of the trait `Cut` for Enums or single field tuple structs.
299#[proc_macro_error]
300#[proc_macro_derive(Cut)]
301pub fn derive_cut(input: TokenStream) -> TokenStream {
302    let input = parse_macro_input!(input as DeriveInput);
303    let trait_name = quote! { truck_geotrait::Cut };
304    let ty = input.ident;
305    let gen = input.generics;
306    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
307    match input.data {
308        Data::Enum(DataEnum { ref variants, .. }) => {
309            let variant = variants.into_iter().next().expect("empty enum!");
310            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
311            let methods = methods! {
312                variants, trait_name,
313                fn cut(&mut self, t: f64) -> Self,
314            };
315            quote! {
316                #[automatically_derived]
317                impl #gen #trait_name for #ty #gen
318                where
319                    #(#where_predicates,)*
320                    #(#tys: #trait_name,)* {
321                    #(#methods)*
322                }
323            }
324        }
325        Data::Struct(DataStruct { ref fields, .. }) => {
326            let field: Vec<_> = fields.iter().collect();
327            if field.len() != 1 || field[0].ident.is_some() {
328                unimplemented!();
329            }
330            let field_type = &field[0].ty;
331            quote! {
332                #[automatically_derived]
333                impl #gen #trait_name for #ty #gen
334                where
335                    #(#where_predicates,)*
336                    #field_type: #trait_name {
337                    fn cut(&mut self, t: f64) -> Self { Self(self.0.cut(t)) }
338                }
339            }
340        }
341        _ => unimplemented!(),
342    }
343    .into()
344}
345
346/// Derive macro generating an impl of the trait `Invertible` for Enums or single field tuple structs.
347#[proc_macro_error]
348#[proc_macro_derive(Invertible)]
349pub fn derive_invertible(input: TokenStream) -> TokenStream {
350    let input = parse_macro_input!(input as DeriveInput);
351    let trait_name = quote! { truck_geotrait::Invertible };
352    let ty = input.ident;
353    let gen = input.generics;
354    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
355    match input.data {
356        Data::Enum(DataEnum { ref variants, .. }) => {
357            let variant = variants.into_iter().next().expect("empty enum!");
358            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
359            let methods = methods! {
360                variants, trait_name,
361                fn invert(&mut self,) -> (),
362                fn inverse(&self,) -> Self,
363            };
364            quote! {
365                #[automatically_derived]
366                impl #gen #trait_name for #ty #gen
367                where
368                    #(#where_predicates,)*
369                    #(#tys: #trait_name,)*
370                    Self: Clone {
371                    #(#methods)*
372                }
373            }
374        }
375        Data::Struct(DataStruct { ref fields, .. }) => {
376            let field: Vec<_> = fields.iter().collect();
377            if field.len() != 1 || field[0].ident.is_some() {
378                unimplemented!();
379            }
380            let field_type = &field[0].ty;
381            quote! {
382                #[automatically_derived]
383                impl #gen #trait_name for #ty #gen
384                where
385                    #(#where_predicates,)*
386                    #field_type: #trait_name,
387                    Self: Clone {
388                    fn invert(&mut self) { self.0.invert() }
389                    fn inverse(&self) -> Self { Self(self.0.inverse()) }
390                }
391            }
392        }
393        _ => unimplemented!(),
394    }
395    .into()
396}
397
398/// Derive macro generating an impl of the trait `ParameterDivision1D` for Enums or single field tuple structs.
399#[proc_macro_error]
400#[proc_macro_derive(ParameterDivision1D)]
401pub fn derive_parameter_division_1d(input: TokenStream) -> TokenStream {
402    let input = parse_macro_input!(input as DeriveInput);
403    let trait_name = quote! { truck_geotrait::ParameterDivision1D };
404    let ty = input.ident;
405    let gen = input.generics;
406    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
407    match input.data {
408        Data::Enum(DataEnum { ref variants, .. }) => {
409            let variant = variants.into_iter().next().expect("empty enum!");
410            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
411            let top_ty = match tys.len() {
412                0 => panic!("empty field!"),
413                1 => tys[0].clone(),
414                _ => unimplemented!(),
415            };
416            let tys = &tys[1..];
417            let methods = methods! {
418                variants, trait_name,
419                fn parameter_division(&self, range: (f64, f64), tol: f64) -> (Vec<f64>, Vec<Self::Point>),
420            };
421            quote! {
422                #[automatically_derived]
423                impl #gen #trait_name for #ty #gen
424                where
425                    #(#where_predicates,)*
426                    #top_ty: #trait_name,
427                    #(#tys: #trait_name<Point = <#top_ty as #trait_name>::Point>,)* {
428                    type Point = <#top_ty as #trait_name>::Point;
429                    #(#methods)*
430                }
431            }
432        }
433        Data::Struct(DataStruct { ref fields, .. }) => {
434            let field: Vec<_> = fields.iter().collect();
435            if field.len() != 1 || field[0].ident.is_some() {
436                unimplemented!();
437            }
438            let field_type = &field[0].ty;
439            quote! {
440                #[automatically_derived]
441                impl #gen #trait_name for #ty #gen
442                where
443                    #(#where_predicates,)*
444                    #field_type: #trait_name {
445                    type Point = <#field_type as #trait_name>::Point;
446                    fn parameter_division(&self, range: (f64, f64), tol: f64) -> (Vec<f64>, Vec<Self::Point>) {
447                        self.0.parameter_division(range, tol)
448                    }
449                }
450            }
451        }
452        _ => unimplemented!(),
453    }
454    .into()
455}
456
457/// Derive macro generating an impl of the trait `ParameterDivision2D` for Enums or single field tuple structs.
458#[proc_macro_error]
459#[proc_macro_derive(ParameterDivision2D)]
460pub fn derive_parameter_division_2d(input: TokenStream) -> TokenStream {
461    let input = parse_macro_input!(input as DeriveInput);
462    let trait_name = quote! { truck_geotrait::ParameterDivision2D };
463    let ty = input.ident;
464    let gen = input.generics;
465    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
466    match input.data {
467        Data::Enum(DataEnum { ref variants, .. }) => {
468            let variant = variants.into_iter().next().expect("empty enum!");
469            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
470            let methods = methods! {
471                variants, trait_name,
472                fn parameter_division(&self, range: ((f64, f64), (f64, f64)), tol: f64) -> (Vec<f64>, Vec<f64>),
473            };
474            quote! {
475                #[automatically_derived]
476                impl #gen #trait_name for #ty #gen
477                where
478                    #(#where_predicates,)*
479                    #(#tys: #trait_name,)* {
480                    #(#methods)*
481                }
482            }
483        }
484        Data::Struct(DataStruct { ref fields, .. }) => {
485            let field: Vec<_> = fields.iter().collect();
486            if field.len() != 1 || field[0].ident.is_some() {
487                unimplemented!();
488            }
489            let field_type = &field[0].ty;
490            quote! {
491                #[automatically_derived]
492                impl #gen #trait_name for #ty #gen
493                where
494                    #(#where_predicates,)*
495                    #field_type: #trait_name {
496                    fn parameter_division(&self, range: ((f64, f64), (f64, f64)), tol: f64) -> (Vec<f64>, Vec<f64>) {
497                        self.0.parameter_division(range, tol)
498                    }
499                }
500            }
501        }
502        _ => unimplemented!(),
503    }
504    .into()
505}
506
507/// Derive macro generating an impl of the trait `ParametricCurve` for Enums or single field tuple structs.
508#[proc_macro_error]
509#[proc_macro_derive(ParametricCurve)]
510pub fn derive_parametric_curve(input: TokenStream) -> TokenStream {
511    let input = parse_macro_input!(input as DeriveInput);
512    let trait_name = quote! { truck_geotrait::ParametricCurve };
513    let ty = input.ident;
514    let gen = input.generics;
515    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
516    match input.data {
517        Data::Enum(DataEnum { ref variants, .. }) => {
518            let variant = variants.into_iter().next().expect("empty enum!");
519            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
520            let top_ty = &tys[0];
521            let methods = methods!(
522                variants,
523                trait_name,
524                fn subs(&self, t: f64) -> Self::Point,
525                fn der(&self, t: f64) -> Self::Vector,
526                fn der2(&self, t: f64) -> Self::Vector,
527                fn parameter_range(&self,) -> ParameterRange,
528                fn period(&self,) -> Option<f64>,
529            );
530            quote! {
531                #[automatically_derived]
532                impl #gen #trait_name for #ty #gen
533                where #(#where_predicates,)*
534                      #(#tys: #trait_name,)*
535                      Self: Clone {
536                    type Point = <#top_ty as #trait_name>::Point;
537                    type Vector = <#top_ty as #trait_name>::Vector;
538                    #(#methods)*
539                }
540            }
541        }
542        Data::Struct(DataStruct { ref fields, .. }) => {
543            let field: Vec<_> = fields.iter().collect();
544            if field.len() != 1 || field[0].ident.is_some() {
545                unimplemented!();
546            }
547            let field_type = &field[0].ty;
548            quote! {
549                #[automatically_derived]
550                impl #gen #trait_name for #ty #gen
551                where #(#where_predicates,)*
552                      #field_type: #trait_name,
553                      Self: Clone, {
554                    type Point = <#field_type as #trait_name>::Point;
555                    type Vector = <#field_type as #trait_name>::Vector;
556                    fn subs(&self, t: f64) -> Self::Point { self.0.subs(t) }
557                    fn der(&self, t: f64) -> Self::Vector { self.0.der(t) }
558                    fn der2(&self, t: f64) -> Self::Vector { self.0.der2(t) }
559                    fn parameter_range(&self) -> ParameterRange { self.0.parameter_range() }
560                    fn period(&self) -> Option<f64> { self.0.period() }
561                }
562            }
563        }
564        _ => unimplemented!(),
565    }
566    .into()
567}
568
569/// Derive macro generating an impl of the trait `ParametricSurface` for Enums or single field tuple structs.
570#[proc_macro_error]
571#[proc_macro_derive(ParametricSurface)]
572pub fn derive_parametric_surface(input: TokenStream) -> TokenStream {
573    let input = parse_macro_input!(input as DeriveInput);
574    let trait_name = quote! { truck_geotrait::ParametricSurface };
575    let ty = input.ident;
576    let gen = input.generics;
577    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
578    match input.data {
579        Data::Enum(DataEnum { ref variants, .. }) => {
580            let variant = variants.into_iter().next().expect("empty enum!");
581            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
582            let top_ty = &tys[0];
583            let methods = methods!(
584                variants,
585                trait_name,
586                fn subs(&self, s: f64, t: f64) -> Self::Point,
587                fn uder(&self, s: f64, t: f64) -> Self::Vector,
588                fn vder(&self, s: f64, t: f64) -> Self::Vector,
589                fn uuder(&self, s: f64, t: f64) -> Self::Vector,
590                fn uvder(&self, s: f64, t: f64) -> Self::Vector,
591                fn vvder(&self, s: f64, t: f64) -> Self::Vector,
592                fn parameter_range(&self,) -> (truck_geotrait::ParameterRange, truck_geotrait::ParameterRange),
593                fn u_period(&self,) -> Option<f64>,
594                fn v_period(&self,) -> Option<f64>,
595            );
596            quote! {
597                #[automatically_derived]
598                impl #gen #trait_name for #ty #gen
599                where
600                    #(#where_predicates,)*
601                    #(#tys: #trait_name,)* {
602                    type Point = <#top_ty as #trait_name>::Point;
603                    type Vector = <#top_ty as #trait_name>::Vector;
604                    #(#methods)*
605                }
606            }
607        }
608        Data::Struct(DataStruct { ref fields, .. }) => {
609            let field: Vec<_> = fields.iter().collect();
610            if field.len() != 1 || field[0].ident.is_some() {
611                unimplemented!();
612            }
613            let field_type = &field[0].ty;
614            quote! {
615                #[automatically_derived]
616                impl #gen #trait_name for #ty #gen
617                where
618                    #(#where_predicates,)*
619                    #field_type: #trait_name, {
620                    type Point = <#field_type as #trait_name>::Point;
621                    type Vector = <#field_type as #trait_name>::Vector;
622                    fn subs(&self, s: f64, t: f64) -> Self::Point { self.0.subs(s, t) }
623                    fn uder(&self, s: f64, t: f64) -> Self::Vector { self.0.uder(s, t) }
624                    fn vder(&self, s: f64, t: f64) -> Self::Vector { self.0.vder(s, t) }
625                    fn uuder(&self, s: f64, t: f64) -> Self::Vector { self.0.uuder(s, t) }
626                    fn uvder(&self, s: f64, t: f64) -> Self::Vector { self.0.uvder(s, t) }
627                    fn vvder(&self, s: f64, t: f64) -> Self::Vector { self.0.vvder(s, t) }
628                    fn parameter_range(&self,) -> ((std::ops::Bound<f64>, std::ops::Bound<f64>), (std::ops::Bound<f64>, std::ops::Bound<f64>)) {
629                        self.0.parameter_range()
630                    }
631                    fn u_period(&self) -> Option<f64> { self.0.u_period() }
632                    fn v_period(&self) -> Option<f64> { self.0.v_period() }
633                }
634            }
635        }
636        _ => unimplemented!(),
637    }
638    .into()
639}
640
641/// Derive macro generating an impl of the trait `ParametricSurface3D` for Enums or single field tuple structs.
642#[proc_macro_error]
643#[proc_macro_derive(ParametricSurface3D)]
644pub fn derive_parametric_surface3d(input: TokenStream) -> TokenStream {
645    let input = parse_macro_input!(input as DeriveInput);
646    let trait_name0 = quote! { truck_geotrait::ParametricSurface };
647    let trait_name1 = quote! { truck_geotrait::ParametricSurface3D };
648    let ty = input.ident;
649    let gen = input.generics;
650    let where_predicates = gen
651        .where_clause
652        .iter()
653        .flat_map(|x| &x.predicates)
654        .collect::<Vec<_>>();
655    match input.data {
656        Data::Enum(DataEnum { ref variants, .. }) => {
657            let variant = variants.into_iter().next().expect("empty enum!");
658            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
659            let methods0 = methods!(
660                variants,
661                trait_name0,
662                fn subs(&self, s: f64, t: f64) -> Self::Point,
663                fn uder(&self, s: f64, t: f64) -> Self::Vector,
664                fn vder(&self, s: f64, t: f64) -> Self::Vector,
665                fn uuder(&self, s: f64, t: f64) -> Self::Vector,
666                fn uvder(&self, s: f64, t: f64) -> Self::Vector,
667                fn vvder(&self, s: f64, t: f64) -> Self::Vector,
668                fn parameter_range(&self,) -> (truck_geotrait::ParameterRange, truck_geotrait::ParameterRange),
669                fn u_period(&self,) -> Option<f64>,
670                fn v_period(&self,) -> Option<f64>,
671            );
672            let methods1 = methods!(
673                variants,
674                trait_name1,
675                fn normal(&self, u: f64, v: f64) -> Vector3,
676            );
677            quote! {
678                #[automatically_derived]
679                impl #gen #trait_name0 for #ty #gen
680                where
681                    #(#where_predicates,)*
682                    #(#tys: #trait_name0,)* {
683                    type Point = Point3;
684                    type Vector = Vector3;
685                    #(#methods0)*
686                }
687
688                #[automatically_derived]
689                impl #gen #trait_name1 for #ty #gen
690                where
691                    #(#where_predicates,)*
692                    #(#tys: #trait_name0,)* {
693                    #(#methods1)*
694                }
695            }
696        }
697        Data::Struct(DataStruct { ref fields, .. }) => {
698            let field: Vec<_> = fields.iter().collect();
699            if field.len() != 1 || field[0].ident.is_some() {
700                unimplemented!();
701            }
702            let field_type = &field[0].ty;
703            quote! {
704                #[automatically_derived]
705                impl #gen #trait_name0 for #ty #gen
706                where
707                    #(#where_predicates,)*
708                    #field_type: #trait_name0, {
709                    type Point = Point3;
710                    type Vector = Vector3;
711                    fn subs(&self, s: f64, t: f64) -> Self::Point { self.0.subs(s, t) }
712                    fn uder(&self, s: f64, t: f64) -> Self::Vector { self.0.uder(s, t) }
713                    fn vder(&self, s: f64, t: f64) -> Self::Vector { self.0.vder(s, t) }
714                    fn uuder(&self, s: f64, t: f64) -> Self::Vector { self.0.uuder(s, t) }
715                    fn uvder(&self, s: f64, t: f64) -> Self::Vector { self.0.uvder(s, t) }
716                    fn vvder(&self, s: f64, t: f64) -> Self::Vector { self.0.vvder(s, t) }
717                    fn parameter_range(&self,) -> (truck_geotrait::ParmaterRange, truck_geotrait::ParameterRange) {
718                        self.0.parameter_range()
719                    }
720                    fn u_period(&self) -> Option<f64> { self.0.u_period() }
721                    fn v_period(&self) -> Option<f64> { self.0.v_period() }
722                }
723                #[automatically_derived]
724                impl #gen #trait_name1 for #ty #gen
725                where
726                    #(#where_predicates,)*
727                    #field_type: #trait_name0, {
728                    fn normal(&self, u: f64, v: f64) -> Vector3 { self.0.normal(u, v) }
729                }
730            }
731        }
732        _ => unimplemented!(),
733    }
734    .into()
735}
736
737/// Derive macro generating an impl of the trait `SearchNearestParameter<D1>` for Enums or single field tuple structs.
738#[proc_macro_error]
739#[proc_macro_derive(SearchNearestParameterD1)]
740pub fn derive_snp_d1(input: TokenStream) -> TokenStream {
741    let input = parse_macro_input!(input as DeriveInput);
742    let trait_name = quote! { truck_geotrait::SearchNearestParameter::<D1> };
743    let ty = input.ident;
744    let gen = input.generics;
745    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
746    match input.data {
747        Data::Enum(DataEnum { ref variants, .. }) => {
748            let variant = variants.into_iter().next().expect("empty enum!");
749            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
750            let top_ty = &tys[0];
751            let methods = methods!(
752                variants,
753                trait_name,
754                fn search_nearest_parameter<H: Into<SPHint1D>>(
755                    &self,
756                    pt: Self::Point,
757                    hint: H,
758                    trials: usize,
759                ) -> Option<f64>,
760            );
761            quote! {
762                #[automatically_derived]
763                impl #gen #trait_name for #ty #gen
764                where
765                    #(#where_predicates,)*
766                    #(#tys: #trait_name,)* {
767                    type Point = <#top_ty as #trait_name>::Point;
768                    #(#methods)*
769                }
770            }
771        }
772        Data::Struct(DataStruct { ref fields, .. }) => {
773            let field: Vec<_> = fields.iter().collect();
774            if field.len() != 1 || field[0].ident.is_some() {
775                unimplemented!();
776            }
777            let field_type = &field[0].ty;
778            quote! {
779                #[automatically_derived]
780                impl #gen #trait_name for #ty #gen
781                where
782                    #(#where_predicates,)*
783                    #field_type: #trait_name, {
784                    type Point = <#field_type as #trait_name>::Point;
785                    fn search_nearest_parameter<H: Into<SPHint1D>>(
786                        &self,
787                        pt: Self::Point,
788                        hint: H,
789                        trials: usize,
790                    ) -> Option<f64> {
791                        self.0.search_nearest_parameter(pt, hint, trials)
792                    }
793                }
794            }
795        }
796        _ => unimplemented!(),
797    }
798    .into()
799}
800
801/// Derive macro generating an impl of the trait `SearchNearestParameter<D2>` for Enums or single field tuple structs.
802#[proc_macro_error]
803#[proc_macro_derive(SearchNearestParameterD2)]
804pub fn derive_snp_d2(input: TokenStream) -> TokenStream {
805    let input = parse_macro_input!(input as DeriveInput);
806    let trait_name = quote! { truck_geotrait::SearchNearestParameter::<D2> };
807    let ty = input.ident;
808    let gen = input.generics;
809    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
810    match input.data {
811        Data::Enum(DataEnum { ref variants, .. }) => {
812            let variant = variants.into_iter().next().expect("empty enum!");
813            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
814            let top_ty = &tys[0];
815            let methods = methods!(
816                variants,
817                trait_name,
818                fn search_nearest_parameter<H: Into<SPHint2D>>(
819                    &self,
820                    pt: Self::Point,
821                    hint: H,
822                    trials: usize,
823                ) -> Option<(f64, f64)>,
824            );
825            quote! {
826                #[automatically_derived]
827                impl #gen #trait_name for #ty #gen
828                where
829                    #(#where_predicates,)*
830                    #(#tys: #trait_name,)* {
831                    type Point = <#top_ty as #trait_name>::Point;
832                    #(#methods)*
833                }
834            }
835        }
836        Data::Struct(DataStruct { ref fields, .. }) => {
837            let field: Vec<_> = fields.iter().collect();
838            if field.len() != 1 || field[0].ident.is_some() {
839                unimplemented!();
840            }
841            let field_type = &field[0].ty;
842            quote! {
843                #[automatically_derived]
844                impl #gen #trait_name for #ty #gen
845                where
846                    #(#where_predicates,)*
847                    #field_type: #trait_name, {
848                    type Point = <#field_type as #trait_name>::Point;
849                    fn search_nearest_parameter<H: Into<SPHint2D>>(
850                        &self,
851                        pt: Self::Point,
852                        hint: H,
853                        trials: usize,
854                    ) -> Option<(f64, f64)> {
855                        self.0.search_nearest_parameter(pt, hint, trials)
856                    }
857                }
858            }
859        }
860        _ => unimplemented!(),
861    }
862    .into()
863}
864
865/// Derive macro generating an impl of the trait `SearchParameter<D1>` for Enums or single field tuple structs.
866#[proc_macro_error]
867#[proc_macro_derive(SearchParameterD1)]
868pub fn derive_sp_d1(input: TokenStream) -> TokenStream {
869    let input = parse_macro_input!(input as DeriveInput);
870    let trait_name = quote! { truck_geotrait::SearchParameter::<D1> };
871    let ty = input.ident;
872    let gen = input.generics;
873    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
874    match input.data {
875        Data::Enum(DataEnum { ref variants, .. }) => {
876            let variant = variants.into_iter().next().expect("empty enum!");
877            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
878            let top_ty = &tys[0];
879            let tys = &tys[1..];
880            let methods = methods!(
881                variants,
882                trait_name,
883                fn search_parameter<H: Into<SPHint1D>>(
884                    &self,
885                    pt: Self::Point,
886                    hint: H,
887                    trials: usize,
888                ) -> Option<f64>,
889            );
890            quote! {
891                #[automatically_derived]
892                impl #gen #trait_name for #ty #gen
893                where
894                    #(#where_predicates,)*
895                    #top_ty: #trait_name,
896                    #(#tys: #trait_name<Point = <#top_ty as #trait_name>::Point>,)* {
897                    type Point = <#top_ty as #trait_name>::Point;
898                    #(#methods)*
899                }
900            }
901        }
902        Data::Struct(DataStruct { ref fields, .. }) => {
903            let field: Vec<_> = fields.iter().collect();
904            if field.len() != 1 || field[0].ident.is_some() {
905                unimplemented!();
906            }
907            let field_type = &field[0].ty;
908            quote! {
909                #[automatically_derived]
910                impl #gen #trait_name for #ty #gen
911                where
912                    #(#where_predicates,)*
913                    #field_type: #trait_name, {
914                    type Point = <#field_type as #trait_name>::Point;
915                    fn search_parameter<H: Into<SPHint1D>>(
916                        &self,
917                        pt: Self::Point,
918                        hint: H,
919                        trials: usize,
920                    ) -> Option<f64> {
921                        self.0.search_parameter(pt, hint, trials)
922                    }
923                }
924            }
925        }
926        _ => unimplemented!(),
927    }
928    .into()
929}
930
931/// Derive macro generating an impl of the trait `SearchParameter<D2>` for Enums or single field tuple structs.
932#[proc_macro_error]
933#[proc_macro_derive(SearchParameterD2)]
934pub fn derive_sp_d2(input: TokenStream) -> TokenStream {
935    let input = parse_macro_input!(input as DeriveInput);
936    let trait_name = quote! { truck_geotrait::SearchParameter::<D2> };
937    let ty = input.ident;
938    let gen = input.generics;
939    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
940    match input.data {
941        Data::Enum(DataEnum { ref variants, .. }) => {
942            let variant = variants.into_iter().next().expect("empty enum!");
943            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
944            let top_ty = &tys[0];
945            let methods = methods!(
946                variants,
947                trait_name,
948                fn search_parameter<H: Into<SPHint2D>>(
949                    &self,
950                    pt: Self::Point,
951                    hint: H,
952                    trials: usize,
953                ) -> Option<(f64, f64)>,
954            );
955            quote! {
956                #[automatically_derived]
957                impl #gen #trait_name for #ty #gen
958                where
959                    #(#where_predicates,)*
960                    #(#tys: #trait_name,)* {
961                    type Point = <#top_ty as #trait_name>::Point;
962                    #(#methods)*
963                }
964            }
965        }
966        Data::Struct(DataStruct { ref fields, .. }) => {
967            let field: Vec<_> = fields.iter().collect();
968            if field.len() != 1 || field[0].ident.is_some() {
969                unimplemented!();
970            }
971            let field_type = &field[0].ty;
972            quote! {
973                #[automatically_derived]
974                impl #gen #trait_name for #ty #gen
975                where
976                    #(#where_predicates,)*
977                    #field_type: #trait_name, {
978                    type Point = <#field_type as #trait_name>::Point;
979                    fn search_parameter<H: Into<SPHint2D>>(
980                        &self,
981                        pt: Self::Point,
982                        hint: H,
983                        trials: usize,
984                    ) -> Option<(f64, f64)> {
985                        self.0.search_parameter(pt, hint, trials)
986                    }
987                }
988            }
989        }
990        _ => unimplemented!(),
991    }
992    .into()
993}
994
995/// Derive macro generating an impl of the trait `Transformed<Matrix3>` for enums or single field tuple structs.
996#[proc_macro_error]
997#[proc_macro_derive(TransformedM3)]
998pub fn derive_transform_m3(input: TokenStream) -> TokenStream {
999    let input = parse_macro_input!(input as DeriveInput);
1000    let trait_name = quote! { truck_geotrait::Transformed::<Matrix3> };
1001    let ty = input.ident;
1002    let gen = input.generics;
1003    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
1004    match input.data {
1005        Data::Enum(DataEnum { ref variants, .. }) => {
1006            let variant = variants.into_iter().next().expect("empty enum!");
1007            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
1008            let methods = methods!(
1009                variants,
1010                trait_name,
1011                fn transform_by(&mut self, mat: truck_geometry::prelude::Matrix3) -> (),
1012                fn transformed(&self, mat: truck_geometry::prelude::Matrix3) -> Self,
1013            );
1014            quote! {
1015                #[automatically_derived]
1016                impl #gen #trait_name for #ty #gen
1017                where
1018                    #(#where_predicates,)*
1019                    #(#tys: #trait_name,)* {
1020                    #(#methods)*
1021                }
1022            }
1023        }
1024        Data::Struct(DataStruct { ref fields, .. }) => {
1025            let field: Vec<_> = fields.iter().collect();
1026            if field.len() != 1 || field[0].ident.is_some() {
1027                unimplemented!();
1028            }
1029            let field_type = &field[0].ty;
1030            quote! {
1031                #[automatically_derived]
1032                impl #gen #trait_name for #ty #gen
1033                where
1034                    #(#where_predicates,)*
1035                    #field_type: #trait_name, {
1036                    fn transform_by(&mut self, mat: truck_geometry::prelude::Matrix3) {
1037                        self.0.transformed(mat)
1038                    }
1039                    fn transformed(&self, mat: truck_geometry::prelude::Matrix3) -> Self {
1040                        Self(self.0.transformed(mat))
1041                    }
1042                }
1043            }
1044        }
1045        _ => unimplemented!(),
1046    }
1047    .into()
1048}
1049
1050/// Derive macro generating an impl of the trait `Transformed<Matrix4>` for enums or single field tuple structs.
1051#[proc_macro_error]
1052#[proc_macro_derive(TransformedM4)]
1053pub fn derive_transform_m4(input: TokenStream) -> TokenStream {
1054    let input = parse_macro_input!(input as DeriveInput);
1055    let trait_name = quote! { truck_geotrait::Transformed::<Matrix4> };
1056    let ty = input.ident;
1057    let gen = input.generics;
1058    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
1059    match input.data {
1060        Data::Enum(DataEnum { ref variants, .. }) => {
1061            let variant = variants.into_iter().next().expect("empty enum!");
1062            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
1063            let methods = methods!(
1064                variants,
1065                trait_name,
1066                fn transform_by(&mut self, mat: truck_geometry::prelude::Matrix4) -> (),
1067                fn transformed(&self, mat: truck_geometry::prelude::Matrix4) -> Self,
1068            );
1069            quote! {
1070                #[automatically_derived]
1071                impl #gen #trait_name for #ty #gen
1072                where
1073                    #(#where_predicates,)*
1074                    #(#tys: #trait_name,)* {
1075                    #(#methods)*
1076                }
1077            }
1078        }
1079        Data::Struct(DataStruct { ref fields, .. }) => {
1080            let field: Vec<_> = fields.iter().collect();
1081            if field.len() != 1 || field[0].ident.is_some() {
1082                unimplemented!();
1083            }
1084            let field_type = &field[0].ty;
1085            quote! {
1086                #[automatically_derived]
1087                impl #gen #trait_name for #ty #gen
1088                where
1089                    #(#where_predicates,)*
1090                    #field_type: #trait_name, {
1091                    fn transform_by(&mut self, mat: truck_geometry::prelude::Matrix4) {
1092                        self.0.transformed(mat)
1093                    }
1094                    fn transformed(&self, mat: truck_geometry::prelude::Matrix4) -> Self {
1095                        Self(self.0.transformed(mat))
1096                    }
1097                }
1098            }
1099        }
1100        _ => unimplemented!(),
1101    }
1102    .into()
1103}
1104/// Derive macro generating an impl of the trait `StepLength` for enums or single field tuple structs.
1105#[proc_macro_error]
1106#[proc_macro_derive(StepLength)]
1107pub fn derive_step_length(input: TokenStream) -> TokenStream {
1108    let input = parse_macro_input!(input as DeriveInput);
1109    let trait_name = quote! { truck_stepio::out::StepLength };
1110    let ty = input.ident;
1111    let gen = input.generics;
1112    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
1113    match input.data {
1114        Data::Enum(DataEnum { ref variants, .. }) => {
1115            let variant = variants.into_iter().next().expect("empty enum!");
1116            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
1117            let methods = methods!(
1118                variants,
1119                trait_name,
1120                fn step_length(&self,) -> usize,
1121            );
1122            quote! {
1123                #[automatically_derived]
1124                impl #gen #trait_name for #ty #gen
1125                where
1126                    #(#where_predicates,)*
1127                    #(#tys: #trait_name,)* {
1128                    #(#methods)*
1129                }
1130            }
1131        }
1132        Data::Struct(DataStruct { ref fields, .. }) => {
1133            let field: Vec<_> = fields.iter().collect();
1134            if field.len() != 1 || field[0].ident.is_some() {
1135                unimplemented!();
1136            }
1137            let field_type = &field[0].ty;
1138            quote! {
1139                #[automatically_derived]
1140                impl #gen #trait_name for #ty #gen
1141                where
1142                    #(#where_predicates,)*
1143                    #field_type: #trait_name, {
1144                    fn step_length(&self) -> usize { self.0.step_length() }
1145                }
1146            }
1147        }
1148        _ => unimplemented!(),
1149    }
1150    .into()
1151}
1152
1153/// Derive macro generating an impl of the trait `DisplayByStep` for enums or single field tuple structs.
1154#[proc_macro_error]
1155#[proc_macro_derive(DisplayByStep)]
1156pub fn derive_display_by_step(input: TokenStream) -> TokenStream {
1157    let input = parse_macro_input!(input as DeriveInput);
1158    let trait_name = quote! { truck_stepio::out::DisplayByStep };
1159    let ty = input.ident;
1160    let gen = input.generics;
1161    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
1162    match input.data {
1163        Data::Enum(DataEnum { ref variants, .. }) => {
1164            let variant = variants.into_iter().next().expect("empty enum!");
1165            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
1166            let methods = methods!(
1167                variants,
1168                trait_name,
1169                fn fmt(&self, idx: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result,
1170            );
1171            quote! {
1172                #[automatically_derived]
1173                impl #gen #trait_name for #ty #gen
1174                where
1175                    #(#where_predicates,)*
1176                    #(#tys: #trait_name,)* {
1177                    #(#methods)*
1178                }
1179            }
1180        }
1181        Data::Struct(DataStruct { ref fields, .. }) => {
1182            let field: Vec<_> = fields.iter().collect();
1183            if field.len() != 1 || field[0].ident.is_some() {
1184                unimplemented!();
1185            }
1186            let field_type = &field[0].ty;
1187            quote! {
1188                #[automatically_derived]
1189                impl #gen #trait_name for #ty #gen
1190                where
1191                    #(#where_predicates,)*
1192                    #field_type: #trait_name, {
1193                    fn fmt(&self, idx: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1194                        #trait_name::fmt(&self.0, idx, f)
1195                    }
1196                }
1197            }
1198        }
1199        _ => unimplemented!(),
1200    }
1201    .into()
1202}
1203
1204/// Derive macro generating an impl of the trait `StepCurve` for enums or single field tuple structs.
1205#[proc_macro_error]
1206#[proc_macro_derive(StepCurve)]
1207pub fn derive_step_curve(input: TokenStream) -> TokenStream {
1208    let input = parse_macro_input!(input as DeriveInput);
1209    let trait_name = quote! { truck_stepio::out::StepCurve };
1210    let ty = input.ident;
1211    let gen = input.generics;
1212    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
1213    match input.data {
1214        Data::Enum(DataEnum { ref variants, .. }) => {
1215            let variant = variants.into_iter().next().expect("empty enum!");
1216            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
1217            let methods = methods!(
1218                variants,
1219                trait_name,
1220                fn same_sense(&self,) -> bool,
1221            );
1222            quote! {
1223                #[automatically_derived]
1224                impl #gen #trait_name for #ty #gen
1225                where
1226                    #(#where_predicates,)*
1227                    #(#tys: #trait_name,)* {
1228                    #(#methods)*
1229                }
1230            }
1231        }
1232        Data::Struct(DataStruct { ref fields, .. }) => {
1233            let field: Vec<_> = fields.iter().collect();
1234            if field.len() != 1 || field[0].ident.is_some() {
1235                unimplemented!();
1236            }
1237            let field_type = &field[0].ty;
1238            quote! {
1239                #[automatically_derived]
1240                impl #gen #trait_name for #ty #gen
1241                where
1242                    #(#where_predicates,)*
1243                    #field_type: #trait_name, {
1244                    fn same_sense(&self) -> bool { #trait_name::same_sense(&self.0) }
1245                }
1246            }
1247        }
1248        _ => unimplemented!(),
1249    }
1250    .into()
1251}
1252
1253/// Derive macro generating an impl of the trait `StepSurface` for enums or single field tuple structs.
1254#[proc_macro_error]
1255#[proc_macro_derive(StepSurface)]
1256pub fn derive_step_surface(input: TokenStream) -> TokenStream {
1257    let input = parse_macro_input!(input as DeriveInput);
1258    let trait_name = quote! { truck_stepio::out::StepSurface };
1259    let ty = input.ident;
1260    let gen = input.generics;
1261    let where_predicates = gen.where_clause.iter().flat_map(|x| &x.predicates);
1262    match input.data {
1263        Data::Enum(DataEnum { ref variants, .. }) => {
1264            let variant = variants.into_iter().next().expect("empty enum!");
1265            let tys: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect();
1266            let methods = methods!(
1267                variants,
1268                trait_name,
1269                fn same_sense(&self,) -> bool,
1270            );
1271            quote! {
1272                #[automatically_derived]
1273                impl #gen #trait_name for #ty #gen
1274                where
1275                    #(#where_predicates,)*
1276                    #(#tys: #trait_name,)* {
1277                    #(#methods)*
1278                }
1279            }
1280        }
1281        Data::Struct(DataStruct { ref fields, .. }) => {
1282            let field: Vec<_> = fields.iter().collect();
1283            if field.len() != 1 || field[0].ident.is_some() {
1284                unimplemented!();
1285            }
1286            let field_type = &field[0].ty;
1287            quote! {
1288                #[automatically_derived]
1289                impl #gen #trait_name for #ty #gen
1290                where
1291                    #(#where_predicates,)*
1292                    #field_type: #trait_name, {
1293                    fn same_sense(&self) -> bool { #trait_name::same_sense(&self.0) }
1294                }
1295            }
1296        }
1297        _ => unimplemented!(),
1298    }
1299    .into()
1300}