diman_unit_system 0.5.1

Internal procedural macros for diman.
Documentation
use proc_macro2::TokenStream;
use quote::quote;

use super::{storage_types::VectorType, Codegen};

impl Codegen {
    pub fn gen_vector_methods(&self) -> TokenStream {
        self.vector_types()
            .iter()
            .map(|vector_type| self.impl_vector_methods(vector_type))
            .collect()
    }

    fn impl_vector_methods(&self, vector_type: &VectorType) -> TokenStream {
        let dimension_type = &self.defs.dimension_type;
        let quantity_type = &self.defs.quantity_type;
        let VectorType {
            name: vector_type_name,
            float_type,
            num_dims,
            ..
        } = vector_type;
        let float_type = &float_type.name;
        let new_z_impl = if *num_dims == 3 {
            quote! {
                pub fn new_z(q: #quantity_type<#float_type, D>) -> #quantity_type<#vector_type_name, D> {
                    q * <#vector_type_name>::Z
                }
            }
        } else {
            quote! {}
        };
        let z_impl = if *num_dims == 3 {
            quote! {
                pub fn z(&self) -> #quantity_type<#float_type, D> {
                    #quantity_type(self.0.z)
                }
            }
        } else {
            quote! {}
        };
        let set_z_impl = if *num_dims == 3 {
            quote! {
                pub fn set_z(&mut self, new_z: #quantity_type<#float_type, D>) {
                    self.0.z = new_z.value_unchecked();
                }
            }
        } else {
            quote! {}
        };
        let new_impl = if *num_dims == 3 {
            quote! {
                pub fn new(
                    x: #quantity_type<#float_type, D>,
                    y: #quantity_type<#float_type, D>,
                    z: #quantity_type<#float_type, D>,
                ) -> Self {
                    Self(<#vector_type_name>::new(x.value_unchecked(), y.value_unchecked(), z.value_unchecked()))
                }
            }
        } else {
            quote! {
                pub fn new(
                    x: #quantity_type<#float_type, D>,
                    y: #quantity_type<#float_type, D>,
                ) -> Self {
                    Self(<#vector_type_name>::new(x.value_unchecked(), y.value_unchecked()))
                }
            }
        };
        quote! {
            impl<const D: #dimension_type> #quantity_type<#vector_type_name, D> {
                #new_impl

                pub fn new_x(q: #quantity_type<#float_type, D>) -> #quantity_type<#vector_type_name, D> {
                    q * <#vector_type_name>::X
                }

                pub fn new_y(q: #quantity_type<#float_type, D>) -> #quantity_type<#vector_type_name, D> {
                    q * <#vector_type_name>::Y
                }

                #new_z_impl

                pub fn x(&self) -> #quantity_type<#float_type, D> {
                    #quantity_type(self.0.x)
                }

                pub fn y(&self) -> #quantity_type<#float_type, D> {
                    #quantity_type(self.0.y)
                }

                #z_impl

                pub fn set_x(&mut self, new_x: #quantity_type<#float_type, D>) {
                    self.0.x = new_x.value_unchecked();
                }

                pub fn set_y(&mut self, new_y: #quantity_type<#float_type, D>) {
                    self.0.y = new_y.value_unchecked();
                }

                #set_z_impl

                pub fn zero() -> Self {
                    Self(<#vector_type_name>::ZERO)
                }

                pub fn min(self, rhs: Self) -> Self {
                    Self(self.0.min(rhs.0))
                }

                pub fn max(self, rhs: Self) -> Self {
                    Self(self.0.max(rhs.0))
                }

                pub fn length(&self) -> #quantity_type<#float_type, D> {
                    #quantity_type::<#float_type, D>(self.0.length())
                }

                pub fn distance(&self, other: &Self) -> #quantity_type<#float_type, D> {
                    #quantity_type::<#float_type, D>(self.0.distance(other.0))
                }

                pub fn distance_squared(
                    &self,
                    other: &Self,
                ) -> #quantity_type<#float_type, { D.mul(2) }>
                where
                    #quantity_type<#float_type, { D.mul(2) }>:,
                {
                    #quantity_type::<#float_type, { D.mul(2) }>(self.0.distance_squared(other.0))
                }

                pub fn normalize(&self) -> #quantity_type<#vector_type_name, { #dimension_type::none() }> {
                    #quantity_type::<#vector_type_name, { #dimension_type::none() }>(self.0.normalize())
                }

                pub fn dot<const DR: Dimension>(
                    self,
                    rhs: Quantity<#vector_type_name, DR>,
                ) -> #quantity_type<#float_type, { D.add(DR) }> {
                    #quantity_type(self.0.dot(rhs.0))
                }
            }
        }
    }
}