use proc_macro2::TokenStream;
use quote::quote;
use super::{join, storage_types::FloatType, CallerType, Codegen};
impl Codegen {
fn ensure_float_traits(&self) -> TokenStream {
let path_prefix = match self.caller_type {
CallerType::Internal => quote! { ::num_traits::float },
CallerType::External => quote! { ::diman::internal::num_traits_reexport },
};
if cfg!(feature = "num-traits-libm") {
quote! {
use #path_prefix::Float;
}
} else {
quote! {
use #path_prefix::FloatCore;
}
}
}
fn dimensionless_float_method(
&self,
float_type: &FloatType,
method_name: &TokenStream,
) -> TokenStream {
let float_type_name = &float_type.name;
let dimension_type = &self.defs.dimension_type;
let quantity_type = &self.defs.quantity_type;
quote! {
impl #quantity_type<#float_type_name, {#dimension_type::none()} > {
pub fn #method_name(&self) -> #quantity_type<#float_type_name, {#dimension_type::none()}> {
Self(self.0.#method_name())
}
}
}
}
fn dimensionless_float_method_for_all_float_types(
&self,
method_name: &TokenStream,
) -> TokenStream {
self.float_types()
.iter()
.map(|float_type| self.dimensionless_float_method(float_type, method_name))
.collect()
}
#[cfg_attr(
not(any(feature = "std", feature = "num-traits-libm")),
allow(dead_code)
)]
fn all_dimensionless_float_methods(&self) -> TokenStream {
join([
self.dimensionless_float_method_for_all_float_types("e! { log2 }),
self.dimensionless_float_method_for_all_float_types("e! { ln }),
self.dimensionless_float_method_for_all_float_types("e! { log10 }),
self.dimensionless_float_method_for_all_float_types("e! { exp }),
self.dimensionless_float_method_for_all_float_types("e! { exp2 }),
self.dimensionless_float_method_for_all_float_types("e! { ceil }),
self.dimensionless_float_method_for_all_float_types("e! { floor }),
self.dimensionless_float_method_for_all_float_types("e! { sin }),
self.dimensionless_float_method_for_all_float_types("e! { cos }),
self.dimensionless_float_method_for_all_float_types("e! { tan }),
self.dimensionless_float_method_for_all_float_types("e! { asin }),
self.dimensionless_float_method_for_all_float_types("e! { acos }),
self.dimensionless_float_method_for_all_float_types("e! { atan }),
self.dimensionless_float_method_for_all_float_types("e! { sinh }),
self.dimensionless_float_method_for_all_float_types("e! { cosh }),
self.dimensionless_float_method_for_all_float_types("e! { tanh }),
self.dimensionless_float_method_for_all_float_types("e! { asinh }),
self.dimensionless_float_method_for_all_float_types("e! { acosh }),
self.dimensionless_float_method_for_all_float_types("e! { atanh }),
self.dimensionless_float_method_for_all_float_types("e! { exp_m1 }),
self.dimensionless_float_method_for_all_float_types("e! { ln_1p }),
])
}
pub fn gen_float_methods(&self) -> TokenStream {
join([
self.ensure_float_traits(),
#[cfg(any(feature = "std", feature = "num-traits-libm"))]
self.all_dimensionless_float_methods(),
self.specific_float_methods_for_all_float_types(),
])
}
fn specific_float_methods_for_all_float_types(&self) -> TokenStream {
self.float_types()
.iter()
.map(|float_type| self.specific_float_methods(float_type))
.collect()
}
fn specific_float_methods(&self, float_type: &FloatType) -> TokenStream {
let float_type = &float_type.name;
let dimension_type = &self.defs.dimension_type;
let quantity_type = &self.defs.quantity_type;
#[cfg(any(feature = "std", feature = "num-traits-libm"))]
let roots = quote! {
pub fn sqrt(&self) -> #quantity_type<#float_type, { D.div_2() }>
{
#quantity_type::<#float_type, { D.div_2() }>(self.0.sqrt())
}
pub fn cbrt(&self) -> #quantity_type<#float_type, { D.div_3() }>
{
#quantity_type::<#float_type, { D.div_3() }>(self.0.cbrt())
}
};
#[cfg(all(not(feature = "std"), not(feature = "num-traits-libm")))]
let roots = quote! {};
quote! {
impl<const D: #dimension_type> #quantity_type<#float_type, D> {
pub fn squared(&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.powi(2))
}
pub fn cubed(&self) -> #quantity_type<#float_type, { D.mul(3) }>
where
#quantity_type::<#float_type, { D.mul(3) }>:
{
#quantity_type::<#float_type, { D.mul(3) }>(self.0.powi(3))
}
pub fn powi<const I: i32>(&self) -> #quantity_type<#float_type, { D.mul(I) }>
where
#quantity_type::<#float_type, { D.mul(I) }>:
{
#quantity_type::<#float_type, { D.mul(I) }>(self.0.powi(I))
}
#roots
pub fn min<Q: Into<Self>>(self, other: Q) -> Self {
Self(self.0.min(other.into().0))
}
pub fn max<Q: Into<Self>>(self, other: Q) -> Self {
Self(self.0.max(other.into().0))
}
pub fn clamp<Q: Into<Self>>(self, min: Q, max: Q) -> Self {
Self(self.0.clamp(min.into().0, max.into().0))
}
pub fn zero() -> Self {
Self(0.0)
}
pub fn is_positive(&self) -> bool {
self.0 > 0.0
}
pub fn is_positive_or_zero(&self) -> bool {
self.0 >= 0.0
}
pub fn is_negative(&self) -> bool {
self.0 < 0.0
}
pub fn is_negative_or_zero(&self) -> bool {
self.0 <= 0.0
}
pub fn is_nan(&self) -> bool {
self.0.is_nan()
}
}
}
}
}