truck_geoderive/
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 top_type_of_enumeration<'a>(
22    variants: impl IntoIterator<Item = &'a Variant> + 'a,
23) -> TokenStream2 {
24    let variant = variants.into_iter().next().expect("empty enum!");
25    let vec: Vec<_> = variant.fields.iter().collect();
26    match vec.len() {
27        0 => panic!("empty field!"),
28        1 => vec[0].ty.to_token_stream(),
29        _ => unimplemented!(),
30    }
31}
32
33fn enumerate_impl_return_something<'a>(
34    variants: impl IntoIterator<Item = &'a Variant> + 'a,
35    method: TokenStream2,
36    method_variants: TokenStream2,
37) -> TokenStream2 {
38    let impls: Vec<_> = variants
39        .into_iter()
40        .map(|variant| {
41            let variant_name = &variant.ident;
42            let vec: Vec<_> = variant.fields.iter().collect();
43            match vec.len() {
44                0 => panic!("empty field!"),
45                1 => match &vec[0].ident {
46                    Some(ident) => quote! {
47                        Self::#variant_name { #ident } => #method(#ident, #method_variants)
48                    },
49                    None => quote! {
50                        Self::#variant_name(got) => #method(got, #method_variants)
51                    },
52                },
53                _ => unimplemented!(),
54            }
55        })
56        .collect();
57    quote! { match self { #(#impls),* } }
58}
59
60fn enumerate_impl_return_self<'a>(
61    variants: impl IntoIterator<Item = &'a Variant> + 'a,
62    method: TokenStream2,
63    method_variants: TokenStream2,
64) -> TokenStream2 {
65    let impls: Vec<_> = variants
66        .into_iter()
67        .map(|variant| {
68            let variant_name = &variant.ident;
69            let vec: Vec<_> = variant.fields.iter().collect();
70            match vec.len() {
71                0 => panic!("empty field!"),
72                1 => match &vec[0].ident {
73                    Some(ident) => {
74                        quote! {
75                            Self::#variant_name { #ident } => Self::#variant_name { #ident: #method(#ident, #method_variants) }
76                        }
77                    }
78                    None => {
79                        quote! {
80                            Self::#variant_name(got) => Self::#variant_name(#method(got, #method_variants))
81                        }
82                    }
83                },
84                _ => unimplemented!(),
85            }
86        })
87        .collect();
88    quote! {
89        match self {
90            #(#impls),*
91        }
92    }
93}
94
95#[derive(Clone, Debug)]
96struct Field {
97    var: TokenStream2,
98    ty: TokenStream2,
99}
100
101macro_rules! fields {
102    ($($var: tt : $ty: tt),*) => {
103        vec![$(Field {
104            var: quote! { $var },
105            ty: quote! { $ty },
106        }),*]
107    };
108}
109
110#[derive(Clone, Debug)]
111struct Method<I> {
112    name: TokenStream2,
113    generics: Option<TokenStream2>,
114    self_field: TokenStream2,
115    fields: Vec<Field>,
116    return_type: TokenStream2,
117    variants: I,
118    trait_name: TokenStream2,
119}
120
121macro_rules! methods {
122    (
123        $variants: ident, $trait_name: ident,
124        $(fn $name: ident (
125            $self_field: expr,
126            $($var: ident: $ty: ty),*$(,)?
127        ) -> $return_type: ty),*$(,)?
128    ) => {
129        vec![$(Method {
130            name: quote! { $name },
131            generics: None,
132            self_field: quote! { $self_field, },
133            fields: fields!($($var: $ty),*),
134            return_type: quote! { $return_type },
135            variants: $variants,
136            trait_name: $trait_name.clone(),
137        }
138        .to_token_stream()),*]
139    };
140    (
141        $variants: ident, $trait_name: ident,
142        $(fn $name: ident <$($gen: ident: $path: path),*> (
143            $self_field: expr,
144            $($var: ident: $ty: ty),*$(,)?
145        ) -> $return_type: ty),*$(,)?
146    ) => {
147        vec![$(Method {
148            name: quote! { $name },
149            generics: Some(quote! { <$($gen: $path),*> }),
150            self_field: quote! { $self_field, },
151            fields: fields!($($var: $ty),*),
152            return_type: quote! { $return_type },
153            variants: $variants,
154            trait_name: $trait_name.clone(),
155        }
156        .to_token_stream()),*]
157    };
158}
159
160impl<'a, I> Method<I>
161where I: IntoIterator<Item = &'a Variant> + 'a + Copy
162{
163    fn to_token_stream(&'a self) -> TokenStream2 {
164        let method_name = &self.name;
165        let generics = &self.generics;
166        let trait_name = &self.trait_name;
167        let self_field = &self.self_field;
168        let fields = self
169            .fields
170            .iter()
171            .map(|f| {
172                let var = &f.var;
173                let ty = &f.ty;
174                quote! { #var: #ty }
175            })
176            .collect::<Vec<_>>();
177        let vals = self
178            .fields
179            .iter()
180            .map(|f| f.var.to_token_stream())
181            .collect::<Vec<_>>();
182        let return_type = &self.return_type;
183        let implement = if return_type.to_string() == "Self" {
184            enumerate_impl_return_self::<'_>(
185                self.variants,
186                quote! { #trait_name::#method_name },
187                quote! { #(#vals),* },
188            )
189        } else {
190            enumerate_impl_return_something::<'a>(
191                self.variants,
192                quote! { #trait_name::#method_name },
193                quote! { #(#vals),* },
194            )
195        };
196        quote! {
197            #[inline(always)]
198            fn #method_name #generics (#self_field #(#fields),*) -> #return_type { #implement }
199        }
200    }
201}
202
203/// Derive macro generating an impl of the trait `BoundedCurve` for Enums or single field tuple structs.
204#[proc_macro_error]
205#[proc_macro_derive(BoundedCurve)]
206pub fn derive_bounded_curve(input: TokenStream) -> TokenStream {
207    let input = parse_macro_input!(input as DeriveInput);
208    let trait_name = quote! { BoundedCurve };
209    let ty = input.ident;
210    let gen = input.generics;
211    match input.data {
212        Data::Enum(DataEnum { ref variants, .. }) => {
213            let methods = methods! {
214                variants, trait_name,
215                fn parameter_range(&self,) -> (f64, f64),
216            };
217            quote! {
218                #[automatically_derived]
219                impl #gen truck_geotrait::#trait_name for #ty {
220                    #(#methods)*
221                }
222            }
223        }
224        Data::Struct(DataStruct { ref fields, .. }) => {
225            let field: Vec<_> = fields.iter().collect();
226            if field.len() != 1 || field[0].ident.is_some() {
227                unimplemented!();
228            }
229            quote! {
230                #[automatically_derived]
231                impl #gen truck_geotrait::#trait_name for #ty {
232                    #[inline(always)]
233                    fn parameter_range(&self) -> (f64, f64) { self.0.parameter_range() }
234                }
235            }
236        }
237        _ => unimplemented!(),
238    }
239    .into()
240}
241
242/// Derive macro generating an impl of the trait `BoundedSurface` for Enums or single field tuple structs.
243#[proc_macro_error]
244#[proc_macro_derive(BoundedSurface)]
245pub fn derive_bounded_surface(input: TokenStream) -> TokenStream {
246    let input = parse_macro_input!(input as DeriveInput);
247    let trait_name = quote! { BoundedSurface };
248    let ty = input.ident;
249    let gen = input.generics;
250    match input.data {
251        Data::Enum(DataEnum { ref variants, .. }) => {
252            let methods = methods! {
253                variants, trait_name,
254                fn parameter_range(&self,) -> ((f64, f64), (f64, f64)),
255            };
256            quote! {
257                #[automatically_derived]
258                impl #gen truck_geotrait::#trait_name for #ty {
259                    #(#methods)*
260                }
261            }
262        }
263        Data::Struct(DataStruct { ref fields, .. }) => {
264            let field: Vec<_> = fields.iter().collect();
265            if field.len() != 1 || field[0].ident.is_some() {
266                unimplemented!();
267            }
268            quote! {
269                #[automatically_derived]
270                impl #gen truck_geotrait::#trait_name for #ty {
271                    #[inline(always)]
272                    fn parameter_range(&self) -> ((f64, f64), (f64, f64)) {
273                        self.0.parameter_range()
274                    }
275                }
276            }
277        }
278        _ => unimplemented!(),
279    }
280    .into()
281}
282
283/// Derive macro generating an impl of the trait `Cut` for Enums or single field tuple structs.
284#[proc_macro_error]
285#[proc_macro_derive(Cut)]
286pub fn derive_cut(input: TokenStream) -> TokenStream {
287    let input = parse_macro_input!(input as DeriveInput);
288    let trait_name = quote! { Cut };
289    let ty = input.ident;
290    let gen = input.generics;
291    match input.data {
292        Data::Enum(DataEnum { ref variants, .. }) => {
293            let methods = methods! {
294                variants, trait_name,
295                fn cut(&mut self, t: f64) -> Self,
296            };
297            quote! {
298                #[automatically_derived]
299                impl #gen truck_geotrait::#trait_name for #ty {
300                    #(#methods)*
301                }
302            }
303        }
304        Data::Struct(DataStruct { ref fields, .. }) => {
305            let field: Vec<_> = fields.iter().collect();
306            if field.len() != 1 || field[0].ident.is_some() {
307                unimplemented!();
308            }
309            quote! {
310                #[automatically_derived]
311                impl #gen truck_geotrait::#trait_name for #ty {
312                    #[inline(always)]
313                    fn cut(&mut self, t: f64) -> Self { Self(self.0.cut(t)) }
314                }
315            }
316        }
317        _ => unimplemented!(),
318    }
319    .into()
320}
321
322/// Derive macro generating an impl of the trait `Invertible` for Enums or single field tuple structs.
323#[proc_macro_error]
324#[proc_macro_derive(Invertible)]
325pub fn derive_invertible(input: TokenStream) -> TokenStream {
326    let input = parse_macro_input!(input as DeriveInput);
327    let trait_name = quote! { Invertible };
328    let ty = input.ident;
329    let gen = input.generics;
330    match input.data {
331        Data::Enum(DataEnum { ref variants, .. }) => {
332            let methods = methods! {
333                variants, trait_name,
334                fn invert(&mut self,) -> (),
335                fn inverse(&self,) -> Self,
336            };
337            quote! {
338                #[automatically_derived]
339                impl #gen truck_geotrait::#trait_name for #ty {
340                    #(#methods)*
341                }
342            }
343        }
344        Data::Struct(DataStruct { ref fields, .. }) => {
345            let field: Vec<_> = fields.iter().collect();
346            if field.len() != 1 || field[0].ident.is_some() {
347                unimplemented!();
348            }
349            quote! {
350                #[automatically_derived]
351                impl #gen truck_geotrait::#trait_name for #ty {
352                    #[inline(always)]
353                    fn invert(&mut self) { self.0.invert() }
354                    #[inline(always)]
355                    fn inverse(&self) -> Self { Self(self.0.inverse()) }
356                }
357            }
358        }
359        _ => unimplemented!(),
360    }
361    .into()
362}
363
364/// Derive macro generating an impl of the trait `ParameterDivision1D` for Enums or single field tuple structs.
365#[proc_macro_error]
366#[proc_macro_derive(ParameterDivision1D)]
367pub fn derive_parameter_division_1d(input: TokenStream) -> TokenStream {
368    let input = parse_macro_input!(input as DeriveInput);
369    let trait_name = quote! { ParameterDivision1D };
370    let ty = input.ident;
371    let gen = input.generics;
372    match input.data {
373        Data::Enum(DataEnum { ref variants, .. }) => {
374            let top_ty = top_type_of_enumeration(variants);
375            let methods = methods! {
376                variants, trait_name,
377                fn parameter_division(&self, range: (f64, f64), tol: f64) -> (Vec<f64>, Vec<Self::Point>),
378            };
379            quote! {
380                #[automatically_derived]
381                impl #gen truck_geotrait::#trait_name for #ty {
382                    type Point = <#top_ty as #trait_name>::Point;
383                    #(#methods)*
384                }
385            }
386        }
387        Data::Struct(DataStruct { ref fields, .. }) => {
388            let field: Vec<_> = fields.iter().collect();
389            if field.len() != 1 || field[0].ident.is_some() {
390                unimplemented!();
391            }
392            let field_type = &field[0].ty;
393            quote! {
394                #[automatically_derived]
395                impl #gen truck_geotrait::#trait_name for #ty {
396                    type Point = <#field_type as #trait_name>::Point;
397                    #[inline(always)]
398                    fn parameter_division(&self, range: (f64, f64), tol: f64) -> (Vec<f64>, Vec<Self::Point>) {
399                        self.0.parameter_division(range, tol)
400                    }
401                }
402            }
403        }
404        _ => unimplemented!(),
405    }
406    .into()
407}
408
409/// Derive macro generating an impl of the trait `ParameterDivision2D` for Enums or single field tuple structs.
410#[proc_macro_error]
411#[proc_macro_derive(ParameterDivision2D)]
412pub fn derive_parameter_division_2d(input: TokenStream) -> TokenStream {
413    let input = parse_macro_input!(input as DeriveInput);
414    let trait_name = quote! { ParameterDivision2D };
415    let ty = input.ident;
416    let gen = input.generics;
417    match input.data {
418        Data::Enum(DataEnum { ref variants, .. }) => {
419            let methods = methods! {
420                variants, trait_name,
421                fn parameter_division(&self, range: ((f64, f64), (f64, f64)), tol: f64) -> (Vec<f64>, Vec<f64>),
422            };
423            quote! {
424                #[automatically_derived]
425                impl #gen truck_geotrait::#trait_name for #ty {
426                    #(#methods)*
427                }
428            }
429        }
430        Data::Struct(DataStruct { ref fields, .. }) => {
431            let field: Vec<_> = fields.iter().collect();
432            if field.len() != 1 || field[0].ident.is_some() {
433                unimplemented!();
434            }
435            quote! {
436                #[automatically_derived]
437                impl #gen truck_geotrait::#trait_name for #ty {
438                    #[inline(always)]
439                    fn parameter_division(&self, range: ((f64, f64), (f64, f64)), tol: f64) -> (Vec<f64>, Vec<f64>) {
440                        self.0.parameter_division(range, tol)
441                    }
442                }
443            }
444        }
445        _ => unimplemented!(),
446    }
447    .into()
448}
449
450/// Derive macro generating an impl of the trait `ParametricCurve` for Enums or single field tuple structs.
451#[proc_macro_error]
452#[proc_macro_derive(ParametricCurve)]
453pub fn derive_parametric_curve(input: TokenStream) -> TokenStream {
454    let input = parse_macro_input!(input as DeriveInput);
455    let trait_name = quote! { ParametricCurve };
456    let ty = input.ident;
457    let gen = input.generics;
458    match input.data {
459        Data::Enum(DataEnum { ref variants, .. }) => {
460            let top_ty = top_type_of_enumeration(variants);
461            let methods = methods!(
462                variants,
463                trait_name,
464                fn subs(&self, t: f64) -> Self::Point,
465                fn der(&self, t: f64) -> Self::Vector,
466                fn der2(&self, t: f64) -> Self::Vector,
467            );
468            quote! {
469                #[automatically_derived]
470                impl #gen truck_geotrait::#trait_name for #ty {
471                    type Point = <#top_ty as #trait_name>::Point;
472                    type Vector = <#top_ty as #trait_name>::Vector;
473                    #(#methods)*
474                }
475            }
476        }
477        Data::Struct(DataStruct { ref fields, .. }) => {
478            let field: Vec<_> = fields.iter().collect();
479            if field.len() != 1 || field[0].ident.is_some() {
480                unimplemented!();
481            }
482            let field_type = &field[0].ty;
483            quote! {
484                #[automatically_derived]
485                impl #gen truck_geotrait::#trait_name for #ty {
486                    type Point = <#field_type as #trait_name>::Point;
487                    type Vector = <#field_type as #trait_name>::Vector;
488                    #[inline(always)]
489                    fn subs(&self, t: f64) -> Self::Point { self.0.subs(t) }
490                    #[inline(always)]
491                    fn der(&self, t: f64) -> Self::Vector { self.0.der(t) }
492                    #[inline(always)]
493                    fn der2(&self, t: f64) -> Self::Vector { self.0.der2(t) }
494                }
495            }
496        }
497        _ => unimplemented!(),
498    }
499    .into()
500}
501
502/// Derive macro generating an impl of the trait `ParametricSurface` for Enums or single field tuple structs.
503#[proc_macro_error]
504#[proc_macro_derive(ParametricSurface)]
505pub fn derive_parametric_surface(input: TokenStream) -> TokenStream {
506    let input = parse_macro_input!(input as DeriveInput);
507    let trait_name = quote! { ParametricSurface };
508    let ty = input.ident;
509    let gen = input.generics;
510    match input.data {
511        Data::Enum(DataEnum { ref variants, .. }) => {
512            let top_ty = top_type_of_enumeration(variants);
513            let methods = methods!(
514                variants,
515                trait_name,
516                fn subs(&self, s: f64, t: f64) -> Self::Point,
517                fn uder(&self, s: f64, t: f64) -> Self::Vector,
518                fn vder(&self, s: f64, t: f64) -> Self::Vector,
519                fn uuder(&self, s: f64, t: f64) -> Self::Vector,
520                fn uvder(&self, s: f64, t: f64) -> Self::Vector,
521                fn vvder(&self, s: f64, t: f64) -> Self::Vector,
522            );
523            quote! {
524                #[automatically_derived]
525                impl #gen truck_geotrait::#trait_name for #ty {
526                    type Point = <#top_ty as #trait_name>::Point;
527                    type Vector = <#top_ty as #trait_name>::Vector;
528                    #(#methods)*
529                }
530            }
531        }
532        Data::Struct(DataStruct { ref fields, .. }) => {
533            let field: Vec<_> = fields.iter().collect();
534            if field.len() != 1 || field[0].ident.is_some() {
535                unimplemented!();
536            }
537            let field_type = &field[0].ty;
538            quote! {
539                #[automatically_derived]
540                impl #gen truck_geotrait::#trait_name for #ty {
541                    type Point = <#field_type as #trait_name>::Point;
542                    type Vector = <#field_type as #trait_name>::Vector;
543                    #[inline(always)]
544                    fn subs(&self, s: f64, t: f64) -> Self::Point { self.0.subs(s, t) }
545                    #[inline(always)]
546                    fn uder(&self, s: f64, t: f64) -> Self::Vector { self.0.uder(s, t) }
547                    #[inline(always)]
548                    fn vder(&self, s: f64, t: f64) -> Self::Vector { self.0.vder(s, t) }
549                    #[inline(always)]
550                    fn uuder(&self, s: f64, t: f64) -> Self::Vector { self.0.uuder(s, t) }
551                    #[inline(always)]
552                    fn uvder(&self, s: f64, t: f64) -> Self::Vector { self.0.uvder(s, t) }
553                    #[inline(always)]
554                    fn vvder(&self, s: f64, t: f64) -> Self::Vector { self.0.vvder(s, t) }
555                }
556            }
557        }
558        _ => unimplemented!(),
559    }
560    .into()
561}
562
563/// Derive macro generating an impl of the trait `ParametricSurface3D` for Enums or single field tuple structs.
564#[proc_macro_error]
565#[proc_macro_derive(ParametricSurface3D)]
566pub fn derive_parametric_surface3d(input: TokenStream) -> TokenStream {
567    let input = parse_macro_input!(input as DeriveInput);
568    let trait_name0 = quote! { ParametricSurface };
569    let trait_name1 = quote! { ParametricSurface3D };
570    let ty = input.ident;
571    let gen = input.generics;
572    match input.data {
573        Data::Enum(DataEnum { ref variants, .. }) => {
574            let methods0 = methods!(
575                variants,
576                trait_name0,
577                fn subs(&self, s: f64, t: f64) -> Self::Point,
578                fn uder(&self, s: f64, t: f64) -> Self::Vector,
579                fn vder(&self, s: f64, t: f64) -> Self::Vector,
580                fn uuder(&self, s: f64, t: f64) -> Self::Vector,
581                fn uvder(&self, s: f64, t: f64) -> Self::Vector,
582                fn vvder(&self, s: f64, t: f64) -> Self::Vector,
583            );
584            let methods1 = methods!(
585                variants,
586                trait_name1,
587                fn normal(&self, u: f64, v: f64) -> Vector3,
588            );
589            quote! {
590                #[automatically_derived]
591                impl #gen truck_geotrait::#trait_name0 for #ty {
592                    type Point = Point3;
593                    type Vector = Vector3;
594                    #(#methods0)*
595                }
596
597                #[automatically_derived]
598                impl #gen truck_geotrait::#trait_name1 for #ty {
599                    #(#methods1)*
600                }
601            }
602        }
603        Data::Struct(DataStruct { ref fields, .. }) => {
604            let field: Vec<_> = fields.iter().collect();
605            if field.len() != 1 || field[0].ident.is_some() {
606                unimplemented!();
607            }
608            quote! {
609                #[automatically_derived]
610                impl #gen truck_geotrait::#trait_name0 for #ty {
611                    type Point = Point3;
612                    type Vector = Vector3;
613                    #[inline(always)]
614                    fn subs(&self, s: f64, t: f64) -> Self::Point { self.0.subs(s, t) }
615                    #[inline(always)]
616                    fn uder(&self, s: f64, t: f64) -> Self::Vector { self.0.uder(s, t) }
617                    #[inline(always)]
618                    fn vder(&self, s: f64, t: f64) -> Self::Vector { self.0.vder(s, t) }
619                    #[inline(always)]
620                    fn uuder(&self, s: f64, t: f64) -> Self::Vector { self.0.uuder(s, t) }
621                    #[inline(always)]
622                    fn uvder(&self, s: f64, t: f64) -> Self::Vector { self.0.uvder(s, t) }
623                    #[inline(always)]
624                    fn vvder(&self, s: f64, t: f64) -> Self::Vector { self.0.vvder(s, t) }
625                }
626                #[automatically_derived]
627                impl #gen truck_geotrait::#trait_name1 for #ty {
628                    #[inline(always)]
629                    fn normal(&self, u: f64, v: f64) -> Vector3 { self.0.normal(u, v) }
630                }
631            }
632        }
633        _ => unimplemented!(),
634    }
635    .into()
636}
637
638/// Derive macro generating an impl of the trait `SearchNearestParameter<D1>` for Enums or single field tuple structs.
639#[proc_macro_error]
640#[proc_macro_derive(SearchNearestParameterD1)]
641pub fn derive_snp_d1(input: TokenStream) -> TokenStream {
642    let input = parse_macro_input!(input as DeriveInput);
643    let trait_name = quote! { SearchNearestParameter::<D1> };
644    let ty = input.ident;
645    let gen = input.generics;
646    match input.data {
647        Data::Enum(DataEnum { ref variants, .. }) => {
648            let top_ty = top_type_of_enumeration(variants);
649            let methods = methods!(
650                variants,
651                trait_name,
652                fn search_nearest_parameter<H: Into<SPHint1D>>(
653                    &self,
654                    pt: Self::Point,
655                    hint: H,
656                    trials: usize,
657                ) -> Option<f64>,
658            );
659            quote! {
660                #[automatically_derived]
661                impl #gen truck_geotrait::SearchNearestParameter<D1> for #ty {
662                    type Point = <#top_ty as #trait_name>::Point;
663                    #(#methods)*
664                }
665            }
666        }
667        Data::Struct(DataStruct { ref fields, .. }) => {
668            let field: Vec<_> = fields.iter().collect();
669            if field.len() != 1 || field[0].ident.is_some() {
670                unimplemented!();
671            }
672            let field_type = &field[0].ty;
673            quote! {
674                #[automatically_derived]
675                impl #gen truck_geotrait::SearchNearestParameter<D1> for #ty {
676                    type Point = <#field_type as #trait_name>::Point;
677                    #[inline(always)]
678                    fn search_nearest_parameter<H: Into<SPHint1D>>(
679                        &self,
680                        pt: Self::Point,
681                        hint: H,
682                        trials: usize,
683                    ) -> Option<f64> {
684                        self.0.search_nearest_parameter(pt, hint, trials)
685                    }
686                }
687            }
688        }
689        _ => unimplemented!(),
690    }
691    .into()
692}
693
694/// Derive macro generating an impl of the trait `SearchNearestParameter<D2>` for Enums or single field tuple structs.
695#[proc_macro_error]
696#[proc_macro_derive(SearchNearestParameterD2)]
697pub fn derive_snp_d2(input: TokenStream) -> TokenStream {
698    let input = parse_macro_input!(input as DeriveInput);
699    let trait_name = quote! { SearchNearestParameter::<D2> };
700    let ty = input.ident;
701    let gen = input.generics;
702    match input.data {
703        Data::Enum(DataEnum { ref variants, .. }) => {
704            let top_ty = top_type_of_enumeration(variants);
705            let methods = methods!(
706                variants,
707                trait_name,
708                fn search_nearest_parameter<H: Into<SPHint2D>>(
709                    &self,
710                    pt: Self::Point,
711                    hint: H,
712                    trials: usize,
713                ) -> Option<(f64, f64)>,
714            );
715            quote! {
716                #[automatically_derived]
717                impl #gen truck_geotrait::SearchNearestParameter<D2> for #ty {
718                    type Point = <#top_ty as #trait_name>::Point;
719                    #(#methods)*
720                }
721            }
722        }
723        Data::Struct(DataStruct { ref fields, .. }) => {
724            let field: Vec<_> = fields.iter().collect();
725            if field.len() != 1 || field[0].ident.is_some() {
726                unimplemented!();
727            }
728            let field_type = &field[0].ty;
729            quote! {
730                #[automatically_derived]
731                impl #gen truck_geotrait::SearchNearestParameter<D2> for #ty {
732                    type Point = <#field_type as #trait_name>::Point;
733                    #[inline(always)]
734                    fn search_nearest_parameter<H: Into<SPHint2D>>(
735                        &self,
736                        pt: Self::Point,
737                        hint: H,
738                        trials: usize,
739                    ) -> Option<(f64, f64)> {
740                        self.0.search_nearest_parameter(pt, hint, trials)
741                    }
742                }
743            }
744        }
745        _ => unimplemented!(),
746    }
747    .into()
748}
749
750/// Derive macro generating an impl of the trait `SearchParameter<D1>` for Enums or single field tuple structs.
751#[proc_macro_error]
752#[proc_macro_derive(SearchParameterD1)]
753pub fn derive_sp_d1(input: TokenStream) -> TokenStream {
754    let input = parse_macro_input!(input as DeriveInput);
755    let trait_name = quote! { SearchParameter::<D1> };
756    let ty = input.ident;
757    let gen = input.generics;
758    match input.data {
759        Data::Enum(DataEnum { ref variants, .. }) => {
760            let top_ty = top_type_of_enumeration(variants);
761            let methods = methods!(
762                variants,
763                trait_name,
764                fn search_parameter<H: Into<SPHint1D>>(
765                    &self,
766                    pt: Self::Point,
767                    hint: H,
768                    trials: usize,
769                ) -> Option<f64>,
770            );
771            quote! {
772                #[automatically_derived]
773                impl #gen truck_geotrait::SearchParameter<D1> for #ty {
774                    type Point = <#top_ty as #trait_name>::Point;
775                    #(#methods)*
776                }
777            }
778        }
779        Data::Struct(DataStruct { ref fields, .. }) => {
780            let field: Vec<_> = fields.iter().collect();
781            if field.len() != 1 || field[0].ident.is_some() {
782                unimplemented!();
783            }
784            let field_type = &field[0].ty;
785            quote! {
786                #[automatically_derived]
787                impl #gen truck_geotrait::SearchParameter<D1> for #ty {
788                    type Point = <#field_type as #trait_name>::Point;
789                    #[inline(always)]
790                    fn search_parameter<H: Into<SPHint1D>>(
791                        &self,
792                        pt: Self::Point,
793                        hint: H,
794                        trials: usize,
795                    ) -> Option<f64> {
796                        self.0.search_nearest_parameter(pt, hint, trials)
797                    }
798                }
799            }
800        }
801        _ => unimplemented!(),
802    }
803    .into()
804}
805
806/// Derive macro generating an impl of the trait `SearchParameter<D2>` for Enums or single field tuple structs.
807#[proc_macro_error]
808#[proc_macro_derive(SearchParameterD2)]
809pub fn derive_sp_d2(input: TokenStream) -> TokenStream {
810    let input = parse_macro_input!(input as DeriveInput);
811    let trait_name = quote! { SearchParameter::<D2> };
812    let ty = input.ident;
813    let gen = input.generics;
814    match input.data {
815        Data::Enum(DataEnum { ref variants, .. }) => {
816            let top_ty = top_type_of_enumeration(variants);
817            let methods = methods!(
818                variants,
819                trait_name,
820                fn search_parameter<H: Into<SPHint2D>>(
821                    &self,
822                    pt: Self::Point,
823                    hint: H,
824                    trials: usize,
825                ) -> Option<(f64, f64)>,
826            );
827            quote! {
828                #[automatically_derived]
829                impl #gen truck_geotrait::SearchParameter<D2> for #ty {
830                    type Point = <#top_ty as #trait_name>::Point;
831                    #(#methods)*
832                }
833            }
834        }
835        Data::Struct(DataStruct { ref fields, .. }) => {
836            let field: Vec<_> = fields.iter().collect();
837            if field.len() != 1 || field[0].ident.is_some() {
838                unimplemented!();
839            }
840            let field_type = &field[0].ty;
841            quote! {
842                #[automatically_derived]
843                impl #gen truck_geotrait::SearchParameter<D2> for #ty {
844                    type Point = <#field_type as #trait_name>::Point;
845                    #[inline(always)]
846                    fn search_parameter<H: Into<SPHint2D>>(
847                        &self,
848                        pt: Self::Point,
849                        hint: H,
850                        trials: usize,
851                    ) -> Option<(f64, f64)> {
852                        self.0.search_nearest_parameter(pt, hint, trials)
853                    }
854                }
855            }
856        }
857        _ => unimplemented!(),
858    }
859    .into()
860}