From 27a15eb4ed3ccb29ecae527643ce6508aa5bb622 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:24:27 -0800 Subject: [PATCH] fmt + cli fix --- libs/macros-core/ffi/mod.rs | 156 ++--- libs/macros-core/lib.rs | 22 +- libs/macros-core/mass_impl/args.rs | 93 ++- libs/macros-core/mass_impl/mod.rs | 92 ++- libs/macros-core/mass_impl/variants.rs | 218 +++---- libs/macros/lib.rs | 33 +- libs/scripts.py | 9 +- libtrig/angle.rs | 850 ++++++++++++------------- libtrig/coords/coord2d.rs | 589 +++++++++-------- libtrig/coords/mod.rs | 10 +- libtrig/lib.rs | 46 +- libtrig/traits/mod.rs | 166 ++--- libtrig/traits/number.rs | 34 +- libtrig/types.rs | 32 +- llm/lib.rs | 104 ++- llm/math.rs | 321 +++++----- 16 files changed, 1396 insertions(+), 1379 deletions(-) diff --git a/libs/macros-core/ffi/mod.rs b/libs/macros-core/ffi/mod.rs index 74603b5..53de198 100644 --- a/libs/macros-core/ffi/mod.rs +++ b/libs/macros-core/ffi/mod.rs @@ -1,78 +1,78 @@ -use crate::TokenStream; - -/// Simplifies the creation of FFI functions -/// -/// # Example -/// ```rust,ignore,no_run -/// #[macros::ffi(type = "system")] -/// pub fn Java_Main_greet<'a>( -/// mut env: JNIEnv<'a>, _class: JClass<'a>, input: JString<'a> -/// ) -> jstring { -/// // First, we have to get the string out of Java. Check out the `strings` -/// // module for more info on how this works. -/// let input: String = env.get_string(&input).expect("Couldn't get java string!").into(); -/// -/// // Then we have to create a new Java string to return. Again, more info -/// // in the `strings` module. -/// let output = env.new_string( -/// format!("Hello, {}!", input) -/// ).expect("Couldn't create java string!"); -/// -/// // Finally, extract the raw pointer to return. -/// output.into_raw() -/// } -/// ``` -pub fn ffi>(cfg: T, input: T) -> TokenStream { - let res = parse_func(input.into()).to_string(); - let settings = parse_settings(cfg.into()); - let res = res.replace("__FFI_RAW_MODIFIERS__", &settings.0); - let res = res.replace("__FFI_EXTERN_MODIFIER__", &settings.1); - match syn::parse_str::(&res) { - Ok(res) => res, - Err(err) => err.to_compile_error(), - } -} - -/// parses the function it should be attached to -fn parse_func(item: TokenStream) -> TokenStream { - let input = match syn::parse2::(item) { - Ok(input) => input, - Err(err) => { - return err.to_compile_error(); - } - }; - let ret = &input.sig.output; - let inputs = &input.sig.inputs; - let name = &input.sig.ident; - let generics = &input.sig.generics; - let body = &input.block; - let attrs = &input.attrs; - let vis = &input.vis; - let result = quote::quote! { - #(#attrs)* - #[no_mangle] - #vis __FFI_RAW_MODIFIERS__ extern __FFI_EXTERN_MODIFIER__ fn #name #generics(#inputs) #ret { - #body - } - }; - result -} - -/// parses the settings (can be none, const, unsafe or both) -fn parse_settings(attr: TokenStream) -> (String, String) { - let modifiers_str = attr.to_string(); - let mut res = String::new(); - if modifiers_str.contains("const") { - res.push_str("const "); - } - if modifiers_str.contains("unsafe") { - res.push_str("unsafe "); - } - let t = if modifiers_str.contains("type=") { - let type_str = modifiers_str.split("type=").collect::>()[1]; - type_str.split(' ').collect::>()[0] - } else { - "C" - }; - (res, format!("\"{}\"",t)) -} +use crate::TokenStream; + +/// Simplifies the creation of FFI functions +/// +/// # Example +/// ```rust,ignore,no_run +/// #[macros::ffi(type = "system")] +/// pub fn Java_Main_greet<'a>( +/// mut env: JNIEnv<'a>, _class: JClass<'a>, input: JString<'a> +/// ) -> jstring { +/// // First, we have to get the string out of Java. Check out the `strings` +/// // module for more info on how this works. +/// let input: String = env.get_string(&input).expect("Couldn't get java string!").into(); +/// +/// // Then we have to create a new Java string to return. Again, more info +/// // in the `strings` module. +/// let output = env.new_string( +/// format!("Hello, {}!", input) +/// ).expect("Couldn't create java string!"); +/// +/// // Finally, extract the raw pointer to return. +/// output.into_raw() +/// } +/// ``` +pub fn ffi>(cfg: T, input: T) -> TokenStream { + let res = parse_func(input.into()).to_string(); + let settings = parse_settings(cfg.into()); + let res = res.replace("__FFI_RAW_MODIFIERS__", &settings.0); + let res = res.replace("__FFI_EXTERN_MODIFIER__", &settings.1); + match syn::parse_str::(&res) { + Ok(res) => res, + Err(err) => err.to_compile_error(), + } +} + +/// parses the function it should be attached to +fn parse_func(item: TokenStream) -> TokenStream { + let input = match syn::parse2::(item) { + Ok(input) => input, + Err(err) => { + return err.to_compile_error(); + } + }; + let ret = &input.sig.output; + let inputs = &input.sig.inputs; + let name = &input.sig.ident; + let generics = &input.sig.generics; + let body = &input.block; + let attrs = &input.attrs; + let vis = &input.vis; + let result = quote::quote! { + #(#attrs)* + #[no_mangle] + #vis __FFI_RAW_MODIFIERS__ extern __FFI_EXTERN_MODIFIER__ fn #name #generics(#inputs) #ret { + #body + } + }; + result +} + +/// parses the settings (can be none, const, unsafe or both) +fn parse_settings(attr: TokenStream) -> (String, String) { + let modifiers_str = attr.to_string(); + let mut res = String::new(); + if modifiers_str.contains("const") { + res.push_str("const "); + } + if modifiers_str.contains("unsafe") { + res.push_str("unsafe "); + } + let t = if modifiers_str.contains("type=") { + let type_str = modifiers_str.split("type=").collect::>()[1]; + type_str.split(' ').collect::>()[0] + } else { + "C" + }; + (res, format!("\"{}\"", t)) +} diff --git a/libs/macros-core/lib.rs b/libs/macros-core/lib.rs index 2f66cc6..ae0ecc9 100644 --- a/libs/macros-core/lib.rs +++ b/libs/macros-core/lib.rs @@ -1,11 +1,11 @@ -//! A collection of core functionality for the macros. - -#![warn(missing_docs, unused, clippy::all)] - -use proc_macro2::TokenStream; - -mod mass_impl; -mod ffi; - -pub use mass_impl::mass_impl; -pub use ffi::ffi; +//! A collection of core functionality for the macros. + +#![warn(missing_docs, unused, clippy::all)] + +use proc_macro2::TokenStream; + +mod ffi; +mod mass_impl; + +pub use ffi::ffi; +pub use mass_impl::mass_impl; diff --git a/libs/macros-core/mass_impl/args.rs b/libs/macros-core/mass_impl/args.rs index c41e1d5..82a031c 100644 --- a/libs/macros-core/mass_impl/args.rs +++ b/libs/macros-core/mass_impl/args.rs @@ -1,47 +1,46 @@ -//! Argument parsing for the `mass_impl` macro. - -pub use super::variants::TypeVariant; - -/// The configuration for the `mass_impl` macro. -pub struct MassImplMacroConfig { - /// The type variants to implement the trait for. - pub type_variants: Vec, -} - -impl std::fmt::Debug for MassImplMacroConfig { - /// Formats a `TypeVariant` - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("MassImplMacroConfig") - .field("type_variants", &self.type_variants) - .field("number_of_passthroughs", &self.number_of_passthroughs()) - .finish() - } -} - -impl MassImplMacroConfig { - /// Returns the number of passthroughs for this type variant. - pub fn number_of_passthroughs(&self) -> i32 { - let mut i = 1; - for variant in &self.type_variants { - i *= variant.number_of_passthroughs(); - } - i - } -} - -// parses this: -// $SELF = @R @M Vec2D, -// $OTHER = @R @M Vec2D -// -impl syn::parse::Parse for MassImplMacroConfig { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut type_variants = Vec::new(); - let vars = syn::punctuated::Punctuated::::parse_terminated(input)?; - for var in vars { - type_variants.push(var); - } - Ok(MassImplMacroConfig { - type_variants, - }) - } -} \ No newline at end of file +//! Argument parsing for the `mass_impl` macro. + +pub use super::variants::TypeVariant; + +/// The configuration for the `mass_impl` macro. +pub struct MassImplMacroConfig { + /// The type variants to implement the trait for. + pub type_variants: Vec, +} + +impl std::fmt::Debug for MassImplMacroConfig { + /// Formats a `TypeVariant` + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MassImplMacroConfig") + .field("type_variants", &self.type_variants) + .field("number_of_passthroughs", &self.number_of_passthroughs()) + .finish() + } +} + +impl MassImplMacroConfig { + /// Returns the number of passthroughs for this type variant. + pub fn number_of_passthroughs(&self) -> i32 { + let mut i = 1; + for variant in &self.type_variants { + i *= variant.number_of_passthroughs(); + } + i + } +} + +// parses this: +// $SELF = @R @M Vec2D, +// $OTHER = @R @M Vec2D +// +impl syn::parse::Parse for MassImplMacroConfig { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let mut type_variants = Vec::new(); + let vars = + syn::punctuated::Punctuated::::parse_terminated(input)?; + for var in vars { + type_variants.push(var); + } + Ok(MassImplMacroConfig { type_variants }) + } +} diff --git a/libs/macros-core/mass_impl/mod.rs b/libs/macros-core/mass_impl/mod.rs index df384c6..e60835c 100644 --- a/libs/macros-core/mass_impl/mod.rs +++ b/libs/macros-core/mass_impl/mod.rs @@ -1,47 +1,45 @@ -use crate::TokenStream; - -mod variants; -mod args; - -/// A macro for implementing a trait for a list of types. -pub fn mass_impl>(cfg: T, input: T) -> TokenStream { - let cfg: TokenStream = cfg.into(); - let input: TokenStream = input.into(); - let config = match syn::parse2::(cfg) { - Ok(config) => config, - Err(err) => { - return err.to_compile_error(); - } - }; - let mut results = vec![input.to_string()]; - - for tv in &config.type_variants { - let mut temp_results = Vec::new(); - if tv.allow_owned { - for r in &results { - let new = r.replace(&tv.alias.to_string(), &tv.ty.to_string()); - temp_results.push(new); - } - } - if tv.allow_ref { - for r in &results { - let new = r.replace(&tv.alias.to_string(), &format!("&{}", tv.ty)); - temp_results.push(new); - } - } - if tv.allow_mut { - for r in &results { - let new = r.replace(&tv.alias.to_string(), &format!("&mut {}", tv.ty)); - temp_results.push(new); - } - } - results = temp_results; - } - let single_str = results.join("\n"); - match syn::parse_str::(&single_str) { - Ok(ts) => ts, - Err(err) => { - err.to_compile_error() - } - } -} \ No newline at end of file +use crate::TokenStream; + +mod args; +mod variants; + +/// A macro for implementing a trait for a list of types. +pub fn mass_impl>(cfg: T, input: T) -> TokenStream { + let cfg: TokenStream = cfg.into(); + let input: TokenStream = input.into(); + let config = match syn::parse2::(cfg) { + Ok(config) => config, + Err(err) => { + return err.to_compile_error(); + } + }; + let mut results = vec![input.to_string()]; + + for tv in &config.type_variants { + let mut temp_results = Vec::new(); + if tv.allow_owned { + for r in &results { + let new = r.replace(&tv.alias.to_string(), &tv.ty.to_string()); + temp_results.push(new); + } + } + if tv.allow_ref { + for r in &results { + let new = r.replace(&tv.alias.to_string(), &format!("&{}", tv.ty)); + temp_results.push(new); + } + } + if tv.allow_mut { + for r in &results { + let new = r.replace(&tv.alias.to_string(), &format!("&mut {}", tv.ty)); + temp_results.push(new); + } + } + results = temp_results; + } + let single_str = results.join("\n"); + match syn::parse_str::(&single_str) { + Ok(ts) => ts, + Err(err) => err.to_compile_error(), + } +} diff --git a/libs/macros-core/mass_impl/variants.rs b/libs/macros-core/mass_impl/variants.rs index 52ed5bc..a00c4f1 100644 --- a/libs/macros-core/mass_impl/variants.rs +++ b/libs/macros-core/mass_impl/variants.rs @@ -1,107 +1,111 @@ -/// A type variant, used in the `#[mass_impl(...)]` macro. -/// -/// Input generally looks like this: -/// -/// ```rust,ignore,no_run -/// $NAME = @RM SomeStruct -/// ``` -/// -/// Which essentially means: -/// - `$NAME` is the alias for `SomeStruct` -/// - `@R` means that `SomeStruct` can be passed by reference -/// - `@RM` means that `SomeStruct` can be passed by mutable reference -/// -/// So it will create 3 bodies for the macro: -/// - `impl SomeTrait for SomeStruct` -/// - `impl SomeTrait for &SomeStruct` -/// - `impl SomeTrait for &mut SomeStruct` -pub struct TypeVariant { - /// The alias for the type (e.g. `$NAME`) - pub alias: syn::Ident, - /// The type (e.g. `SomeStruct`) - pub ty: syn::Ident, - /// Whether or not the type can be passed by value - pub allow_owned: bool, - /// Whether or not the type can be passed by reference - pub allow_ref: bool, - /// Whether or not the type can be passed by mutable reference - pub allow_mut: bool, -} - -impl TypeVariant { - /// Returns the number of passthroughs for this type variant. - pub fn number_of_passthroughs(&self) -> i32 { - let mut i =if self.allow_owned { 1 } else { 0 }; - if self.allow_ref { i += 1 }; - if self.allow_mut { i += 1 }; - i - } -} - -impl std::fmt::Debug for TypeVariant { - /// Formats a `TypeVariant` - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("TypeVariant") - .field("alias", &self.alias) - .field("ty", &self.ty) - .field("allow_owned", &self.allow_owned) - .field("allow_ref", &self.allow_ref) - .field("allow_mut", &self.allow_mut) - .finish() - } -} - -impl syn::parse::Parse for TypeVariant { - /// Turns this: - /// - /// ```rust,ignore,no_run - /// $NAME = @RM SomeStruct, - /// ``` - /// - /// Into this: - /// - /// ```rust,ignore,no_run - /// TypeVariant { - /// alias: "NAME" - /// ty: SomeStruct, - /// allow_owned: true, - /// allow_ref: true, - /// allow_mut: true, - /// } - /// ``` - fn parse(input: syn::parse::ParseStream) -> syn::Result { - use syn::*; - let _ = input.parse::()?; - let alias = input.parse::()?; - input.parse::()?; - let mut allow_owned = false; - let mut allow_ref = false; - let mut allow_mut = false; - loop { - if input.peek(Token![@]) { - let _ = input.parse::()?; - let modifier = input.parse::()?; - let modifier = modifier.to_string(); - if modifier.contains('R') { - allow_ref = true; - } - if modifier.contains('M') { - allow_mut = true; - } - if modifier.contains('O') { - allow_owned = true; - } - } else { - break; - } - }; - let ty = input.parse::()?; - Ok(TypeVariant { - alias, - ty, - allow_owned, - allow_ref, - allow_mut, - }) - } -} +/// A type variant, used in the `#[mass_impl(...)]` macro. +/// +/// Input generally looks like this: +/// +/// ```rust,ignore,no_run +/// $NAME = @RM SomeStruct +/// ``` +/// +/// Which essentially means: +/// - `$NAME` is the alias for `SomeStruct` +/// - `@R` means that `SomeStruct` can be passed by reference +/// - `@RM` means that `SomeStruct` can be passed by mutable reference +/// +/// So it will create 3 bodies for the macro: +/// - `impl SomeTrait for SomeStruct` +/// - `impl SomeTrait for &SomeStruct` +/// - `impl SomeTrait for &mut SomeStruct` +pub struct TypeVariant { + /// The alias for the type (e.g. `$NAME`) + pub alias: syn::Ident, + /// The type (e.g. `SomeStruct`) + pub ty: syn::Ident, + /// Whether or not the type can be passed by value + pub allow_owned: bool, + /// Whether or not the type can be passed by reference + pub allow_ref: bool, + /// Whether or not the type can be passed by mutable reference + pub allow_mut: bool, +} + +impl TypeVariant { + /// Returns the number of passthroughs for this type variant. + pub fn number_of_passthroughs(&self) -> i32 { + let mut i = if self.allow_owned { 1 } else { 0 }; + if self.allow_ref { + i += 1 + }; + if self.allow_mut { + i += 1 + }; + i + } +} + +impl std::fmt::Debug for TypeVariant { + /// Formats a `TypeVariant` + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TypeVariant") + .field("alias", &self.alias) + .field("ty", &self.ty) + .field("allow_owned", &self.allow_owned) + .field("allow_ref", &self.allow_ref) + .field("allow_mut", &self.allow_mut) + .finish() + } +} + +impl syn::parse::Parse for TypeVariant { + /// Turns this: + /// + /// ```rust,ignore,no_run + /// $NAME = @RM SomeStruct, + /// ``` + /// + /// Into this: + /// + /// ```rust,ignore,no_run + /// TypeVariant { + /// alias: "NAME" + /// ty: SomeStruct, + /// allow_owned: true, + /// allow_ref: true, + /// allow_mut: true, + /// } + /// ``` + fn parse(input: syn::parse::ParseStream) -> syn::Result { + use syn::*; + let _ = input.parse::()?; + let alias = input.parse::()?; + input.parse::()?; + let mut allow_owned = false; + let mut allow_ref = false; + let mut allow_mut = false; + loop { + if input.peek(Token![@]) { + let _ = input.parse::()?; + let modifier = input.parse::()?; + let modifier = modifier.to_string(); + if modifier.contains('R') { + allow_ref = true; + } + if modifier.contains('M') { + allow_mut = true; + } + if modifier.contains('O') { + allow_owned = true; + } + } else { + break; + } + } + let ty = input.parse::()?; + Ok(TypeVariant { + alias, + ty, + allow_owned, + allow_ref, + allow_mut, + }) + } +} diff --git a/libs/macros/lib.rs b/libs/macros/lib.rs index 886ee0c..8c4053d 100644 --- a/libs/macros/lib.rs +++ b/libs/macros/lib.rs @@ -1,17 +1,16 @@ -#![doc = include_str!("./README.md")] - -#![warn(missing_docs, unused, clippy::all)] - -use proc_macro::TokenStream; - -/// A macro for implementing a trait for a list of types. -#[proc_macro_attribute] -pub fn mass_impl(cfg: TokenStream, input: TokenStream) -> TokenStream { - mc::mass_impl(cfg, input).into() -} - -/// A macro for generating FFI functions. -#[proc_macro_attribute] -pub fn ffi(cfg: TokenStream, input: TokenStream) -> TokenStream { - mc::ffi(cfg, input).into() -} +#![doc = include_str!("./README.md")] +#![warn(missing_docs, unused, clippy::all)] + +use proc_macro::TokenStream; + +/// A macro for implementing a trait for a list of types. +#[proc_macro_attribute] +pub fn mass_impl(cfg: TokenStream, input: TokenStream) -> TokenStream { + mc::mass_impl(cfg, input).into() +} + +/// A macro for generating FFI functions. +#[proc_macro_attribute] +pub fn ffi(cfg: TokenStream, input: TokenStream) -> TokenStream { + mc::ffi(cfg, input).into() +} diff --git a/libs/scripts.py b/libs/scripts.py index 791e5a7..fc84c8f 100644 --- a/libs/scripts.py +++ b/libs/scripts.py @@ -11,17 +11,20 @@ def run_cmd(cmd: str, cwd: str, args: list[str]) -> str | int | None: def fmt(cd: str, args: list[str]) -> str | int | None: cmd = ["cargo", "fmt"] if '--check' in args: cmd.extend(['--', '--check']) - subprocess.run(cmd, cwd=cd) + res = subprocess.run(cmd, cwd=cd) + if res.returncode != 0: exit(res.returncode) def test(cd: str, args: list[str]) -> str | int | None: cmd = ["cargo", "tarpaulin"] cmd.extend(args) - subprocess.run(cmd, cwd=cd) + res = subprocess.run(cmd, cwd=cd) + if res.returncode != 0: exit(res.returncode) def build(cd: str, args: list[str]) -> str | int | None: cmd = ["cargo", "build"] cmd.extend(args) - subprocess.run(cmd, cwd=cd) + res = subprocess.run(cmd, cwd=cd) + if res.returncode != 0: exit(res.returncode) def hlp() -> None: print("") diff --git a/libtrig/angle.rs b/libtrig/angle.rs index 719495d..9005943 100644 --- a/libtrig/angle.rs +++ b/libtrig/angle.rs @@ -1,425 +1,425 @@ -use crate::*; - -/// A wrapper around a `float` value that represents an angle. -/// -/// It can be created from either radians or degrees, and can be converted to either radians or degrees. -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Angle2D(RadianOrDegree64, bool); - -impl Angle2D { - /// Creates a new `Angle2D` from the given `value` and `is_radians` flag. - #[inline] - #[must_use] - pub const fn new(value: RadianOrDegree64, is_radians: bool) -> Self { - Self(value, is_radians) - } - /// Creates a new `Angle2D` from the given `value` in radians. - #[inline] - #[must_use] - pub const fn from_radians(value: Radian64) -> Self { - Self::new(value, true) - } - /// Creates a new `Angle2D` from the given `value` in degrees. - #[inline] - #[must_use] - pub const fn from_degrees(value: Degree64) -> Self { - Self::new(value, false) - } - /// Creates a new `Angle2D` with a value of `0.0` radians. - #[inline] - #[must_use] - pub const fn zero() -> Self { - Self::new(0.0, true) - } - /// Creates a new `Angle2D` with a value of `0.0` degrees. - #[inline] - #[must_use] - pub const fn zero_deg() -> Self { - Self::new(0.0, false) - } - /// Returns the value of the angle in radians. - #[inline] - #[must_use] - pub fn to_radians(&self) -> Radian64 { - if self.1 { - self.0 - } else { - self.0.to_radians() - } - } - /// Returns the value of the angle in degrees. - #[inline] - #[must_use] - pub fn to_degrees(&self) -> Degree64 { - if self.1 { - self.0.to_degrees() - } else { - self.0 - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Add for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() + rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() + rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Add for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() + rhs) - } else { - Angle2D::from_degrees(self.to_degrees() + rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() + rhs.to_radians(); - } else { - self.0 = self.to_degrees() + rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() + rhs; - } else { - self.0 = self.to_degrees() + rhs; - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Sub for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() - rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() - rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Sub for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() - rhs) - } else { - Angle2D::from_degrees(self.to_degrees() - rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() - rhs.to_radians(); - } else { - self.0 = self.to_degrees() - rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() - rhs; - } else { - self.0 = self.to_degrees() - rhs; - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::Mul for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() * rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() * rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Mul for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() * rhs) - } else { - Angle2D::from_degrees(self.to_degrees() * rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() * rhs.to_radians(); - } else { - self.0 = self.to_degrees() * rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() * rhs; - } else { - self.0 = self.to_degrees() * rhs; - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::Div for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() / rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() / rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Div for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() / rhs) - } else { - Angle2D::from_degrees(self.to_degrees() / rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() / rhs.to_radians(); - } else { - self.0 = self.to_degrees() / rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() / rhs; - } else { - self.0 = self.to_degrees() / rhs; - } - } -} - -#[macros::mass_impl($THIS = @ORM Angle2D)] -impl core::ops::Neg for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - if self.1 { - Angle2D::from_radians(-self.to_radians()) - } else { - Angle2D::from_degrees(-self.to_degrees()) - } - } -} - -impl Default for Angle2D { - #[inline] - #[must_use] - fn default() -> Self { - Self::zero() - } -} - -impl core::fmt::Display for Angle2D { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if self.1 { - return write!(f, "{}rad", self.to_radians()); - } - write!(f, "{}°", self.to_degrees()) - } -} - -impl> From<(F, bool)> for Angle2D { - #[inline] - #[must_use] - fn from((f, r): (F, bool)) -> Self { - if r { - Self::from_radians(f.into()) - } else { - Self::from_degrees(f.into()) - } - } -} - -impl crate::traits::Number for Angle2D {} - -macro_rules! i { - ($n:ident $($t:tt)*) => ( - #[inline] - #[must_use] - fn $n(&self) -> Float64 { - self.0.$n() - } - i!($($t)*); - ); - () => (); -} - -impl crate::traits::Float for Angle2D { - #[inline] - #[must_use] - fn mul_add(&self, a: Self, b: Self) -> Float64 { - self.0.mul_add(a.0, b.0) - } - #[inline] - #[must_use] - fn div_euclid(&self, rhs: Self) -> Float64 { - self.0.div_euclid(rhs.0) - } - #[inline] - #[must_use] - fn rem_euclid(&self, rhs: Self) -> Float64 { - self.0.rem_euclid(rhs.0) - } - #[inline] - #[must_use] - fn powi(&self, n: Int) -> Float64 { - self.0.powi(n) - } - #[inline] - #[must_use] - fn powf(&self, n: Self) -> Float64 { - self.0.powf(n.0) - } - #[inline] - #[must_use] - fn log(&self, base: Self) -> Float64 { - self.0.log(base.0) - } - #[inline] - #[must_use] - fn atan2(&self, other: Self) -> Float64 { - self.0.atan2(other.0) - } - #[inline] - #[must_use] - fn hypot(&self, other: Self) -> Float64 { - self.0.hypot(other.0) - } - #[inline] - #[must_use] - fn sin_cos(&self) -> (Float64, Float64) { - self.0.sin_cos() - } - - i!(floor ceil round trunc fract abs signum sqrt exp exp2 ln log2 log10 cbrt - sin cos tan asin acos atan exp_m1 ln_1p sinh cosh tanh asinh acosh atanh); -} +use crate::*; + +/// A wrapper around a `float` value that represents an angle. +/// +/// It can be created from either radians or degrees, and can be converted to either radians or degrees. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub struct Angle2D(RadianOrDegree64, bool); + +impl Angle2D { + /// Creates a new `Angle2D` from the given `value` and `is_radians` flag. + #[inline] + #[must_use] + pub const fn new(value: RadianOrDegree64, is_radians: bool) -> Self { + Self(value, is_radians) + } + /// Creates a new `Angle2D` from the given `value` in radians. + #[inline] + #[must_use] + pub const fn from_radians(value: Radian64) -> Self { + Self::new(value, true) + } + /// Creates a new `Angle2D` from the given `value` in degrees. + #[inline] + #[must_use] + pub const fn from_degrees(value: Degree64) -> Self { + Self::new(value, false) + } + /// Creates a new `Angle2D` with a value of `0.0` radians. + #[inline] + #[must_use] + pub const fn zero() -> Self { + Self::new(0.0, true) + } + /// Creates a new `Angle2D` with a value of `0.0` degrees. + #[inline] + #[must_use] + pub const fn zero_deg() -> Self { + Self::new(0.0, false) + } + /// Returns the value of the angle in radians. + #[inline] + #[must_use] + pub fn to_radians(&self) -> Radian64 { + if self.1 { + self.0 + } else { + self.0.to_radians() + } + } + /// Returns the value of the angle in degrees. + #[inline] + #[must_use] + pub fn to_degrees(&self) -> Degree64 { + if self.1 { + self.0.to_degrees() + } else { + self.0 + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::Add for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() + rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() + rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::Add for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() + rhs) + } else { + Angle2D::from_degrees(self.to_degrees() + rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() + rhs.to_radians(); + } else { + self.0 = self.to_degrees() + rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() + rhs; + } else { + self.0 = self.to_degrees() + rhs; + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::Sub for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() - rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() - rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::Sub for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() - rhs) + } else { + Angle2D::from_degrees(self.to_degrees() - rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() - rhs.to_radians(); + } else { + self.0 = self.to_degrees() - rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() - rhs; + } else { + self.0 = self.to_degrees() - rhs; + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::Mul for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() * rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() * rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::Mul for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() * rhs) + } else { + Angle2D::from_degrees(self.to_degrees() * rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() * rhs.to_radians(); + } else { + self.0 = self.to_degrees() * rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() * rhs; + } else { + self.0 = self.to_degrees() * rhs; + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::Div for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() / rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() / rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::Div for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() / rhs) + } else { + Angle2D::from_degrees(self.to_degrees() / rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() / rhs.to_radians(); + } else { + self.0 = self.to_degrees() / rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() / rhs; + } else { + self.0 = self.to_degrees() / rhs; + } + } +} + +#[macros::mass_impl($THIS = @ORM Angle2D)] +impl core::ops::Neg for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn neg(self) -> Self::Output { + if self.1 { + Angle2D::from_radians(-self.to_radians()) + } else { + Angle2D::from_degrees(-self.to_degrees()) + } + } +} + +impl Default for Angle2D { + #[inline] + #[must_use] + fn default() -> Self { + Self::zero() + } +} + +impl core::fmt::Display for Angle2D { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if self.1 { + return write!(f, "{}rad", self.to_radians()); + } + write!(f, "{}°", self.to_degrees()) + } +} + +impl> From<(F, bool)> for Angle2D { + #[inline] + #[must_use] + fn from((f, r): (F, bool)) -> Self { + if r { + Self::from_radians(f.into()) + } else { + Self::from_degrees(f.into()) + } + } +} + +impl crate::traits::Number for Angle2D {} + +macro_rules! i { + ($n:ident $($t:tt)*) => ( + #[inline] + #[must_use] + fn $n(&self) -> Float64 { + self.0.$n() + } + i!($($t)*); + ); + () => (); +} + +impl crate::traits::Float for Angle2D { + #[inline] + #[must_use] + fn mul_add(&self, a: Self, b: Self) -> Float64 { + self.0.mul_add(a.0, b.0) + } + #[inline] + #[must_use] + fn div_euclid(&self, rhs: Self) -> Float64 { + self.0.div_euclid(rhs.0) + } + #[inline] + #[must_use] + fn rem_euclid(&self, rhs: Self) -> Float64 { + self.0.rem_euclid(rhs.0) + } + #[inline] + #[must_use] + fn powi(&self, n: Int) -> Float64 { + self.0.powi(n) + } + #[inline] + #[must_use] + fn powf(&self, n: Self) -> Float64 { + self.0.powf(n.0) + } + #[inline] + #[must_use] + fn log(&self, base: Self) -> Float64 { + self.0.log(base.0) + } + #[inline] + #[must_use] + fn atan2(&self, other: Self) -> Float64 { + self.0.atan2(other.0) + } + #[inline] + #[must_use] + fn hypot(&self, other: Self) -> Float64 { + self.0.hypot(other.0) + } + #[inline] + #[must_use] + fn sin_cos(&self) -> (Float64, Float64) { + self.0.sin_cos() + } + + i!(floor ceil round trunc fract abs signum sqrt exp exp2 ln log2 log10 cbrt + sin cos tan asin acos atan exp_m1 ln_1p sinh cosh tanh asinh acosh atanh); +} diff --git a/libtrig/coords/coord2d.rs b/libtrig/coords/coord2d.rs index 66358bd..81bac40 100644 --- a/libtrig/coords/coord2d.rs +++ b/libtrig/coords/coord2d.rs @@ -1,296 +1,293 @@ -use crate::*; - -/// A wrapper around a `float` value that represents a 2D coordinate. -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Coord2D { - /// The x coordinate. - pub x: Float64, - /// The y coordinate. - pub y: Float64, -} - -impl Coord2D { - /// Creates a new `Vec2D` from the given `x` and `y` values. - #[inline] - #[must_use] - pub const fn new(x: Float64, y: Float64) -> Self { - Self { x, y } - } - /// Creates a new `Vec2D` located at the origin. - #[inline] - #[must_use] - pub const fn origin() -> Self { - Self::new(0.0, 0.0) - } - /// Rotates the vector by the given angle in radians. - #[inline] - #[must_use] - pub fn rotate_by(&self, angle: Angle2D) -> Self { - #[allow(unused_imports)] - use crate::traits::Float; - let angle = angle.to_radians(); - let (sin, cos) = angle.sin_cos(); - Self::new( - self.x * cos - self.y * sin, - self.x * sin + self.y * cos, - ) - } - /// Returns the angle of the vector in radians. - #[inline] - #[must_use] - pub fn angle(&self) -> Angle2D { - #[allow(unused_imports)] - use crate::traits::Float; - Angle2D::from_radians(self.y.atan2(self.x)) - } - /// Returns the inverted position. - /// - /// Same as rotating the position by 180 degrees. - #[inline] - #[must_use] - pub fn inverse(&self) -> Self { - -self - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Add for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x + rhs.x(), self.y + rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::Add for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x + rhs.x, self.y + rhs.y) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.x += rhs.x(); - self.y += rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.x += rhs.x; - self.y += rhs.y; - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Sub for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x - rhs.x(), self.y - rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::Sub for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x - rhs.x, self.y - rhs.y) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.x -= rhs.x(); - self.y -= rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.x -= rhs.x; - self.y -= rhs.y; - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::Mul for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x * rhs, self.y * rhs) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::Mul for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x * rhs.x(), self.y * rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - self.x *= rhs; - self.y *= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - self.x *= rhs.x(); - self.y *= rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::Div for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x / rhs, self.y / rhs) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::Div for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x / rhs.x(), self.y / rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - self.x /= rhs; - self.y /= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - self.x /= rhs.x(); - self.y /= rhs.y(); - } -} - -#[macros::mass_impl($THIS = @ORM Coord2D)] -impl core::ops::Neg for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - Coord2D::new(-self.x, -self.y) - } -} - -impl core::fmt::Display for Coord2D { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "[{}, {}]", self.x, self.y) - } -} - -impl Default for Coord2D { - #[inline] - #[must_use] - fn default() -> Self { - Self::origin() - } -} - -impl> From<(F, F)> for Coord2D { - #[inline] - #[must_use] - fn from((x, y): (F, F)) -> Self { - Self::new(x.into(), y.into()) - } -} - -impl From for (Float64, Float64) { - #[inline] - #[must_use] - fn from(Coord2D {x, y}: Coord2D) -> Self { - (x, y) - } -} +use crate::*; + +/// A wrapper around a `float` value that represents a 2D coordinate. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub struct Coord2D { + /// The x coordinate. + pub x: Float64, + /// The y coordinate. + pub y: Float64, +} + +impl Coord2D { + /// Creates a new `Vec2D` from the given `x` and `y` values. + #[inline] + #[must_use] + pub const fn new(x: Float64, y: Float64) -> Self { + Self { x, y } + } + /// Creates a new `Vec2D` located at the origin. + #[inline] + #[must_use] + pub const fn origin() -> Self { + Self::new(0.0, 0.0) + } + /// Rotates the vector by the given angle in radians. + #[inline] + #[must_use] + pub fn rotate_by(&self, angle: Angle2D) -> Self { + #[allow(unused_imports)] + use crate::traits::Float; + let angle = angle.to_radians(); + let (sin, cos) = angle.sin_cos(); + Self::new(self.x * cos - self.y * sin, self.x * sin + self.y * cos) + } + /// Returns the angle of the vector in radians. + #[inline] + #[must_use] + pub fn angle(&self) -> Angle2D { + #[allow(unused_imports)] + use crate::traits::Float; + Angle2D::from_radians(self.y.atan2(self.x)) + } + /// Returns the inverted position. + /// + /// Same as rotating the position by 180 degrees. + #[inline] + #[must_use] + pub fn inverse(&self) -> Self { + -self + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::Add for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x + rhs.x(), self.y + rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::Add for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x + rhs.x, self.y + rhs.y) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.x += rhs.x(); + self.y += rhs.y(); + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.x += rhs.x; + self.y += rhs.y; + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::Sub for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x - rhs.x(), self.y - rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::Sub for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x - rhs.x, self.y - rhs.y) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.x -= rhs.x(); + self.y -= rhs.y(); + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.x -= rhs.x; + self.y -= rhs.y; + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Float64 +)] +impl core::ops::Mul for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x * rhs, self.y * rhs) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::Mul for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x * rhs.x(), self.y * rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Float64 +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + self.x *= rhs; + self.y *= rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + self.x *= rhs.x(); + self.y *= rhs.y(); + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Float64 +)] +impl core::ops::Div for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x / rhs, self.y / rhs) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::Div for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x / rhs.x(), self.y / rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Float64 +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + self.x /= rhs; + self.y /= rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + self.x /= rhs.x(); + self.y /= rhs.y(); + } +} + +#[macros::mass_impl($THIS = @ORM Coord2D)] +impl core::ops::Neg for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn neg(self) -> Self::Output { + Coord2D::new(-self.x, -self.y) + } +} + +impl core::fmt::Display for Coord2D { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "[{}, {}]", self.x, self.y) + } +} + +impl Default for Coord2D { + #[inline] + #[must_use] + fn default() -> Self { + Self::origin() + } +} + +impl> From<(F, F)> for Coord2D { + #[inline] + #[must_use] + fn from((x, y): (F, F)) -> Self { + Self::new(x.into(), y.into()) + } +} + +impl From for (Float64, Float64) { + #[inline] + #[must_use] + fn from(Coord2D { x, y }: Coord2D) -> Self { + (x, y) + } +} diff --git a/libtrig/coords/mod.rs b/libtrig/coords/mod.rs index aad37f6..2589cb1 100644 --- a/libtrig/coords/mod.rs +++ b/libtrig/coords/mod.rs @@ -1,5 +1,5 @@ -mod coord2d; -// mod coord3d; - -pub use coord2d::Coord2D; -// pub use coord3d::Coord3D; \ No newline at end of file +mod coord2d; +// mod coord3d; + +pub use coord2d::Coord2D; +// pub use coord3d::Coord3D; diff --git a/libtrig/lib.rs b/libtrig/lib.rs index b4a993b..c3747a8 100644 --- a/libtrig/lib.rs +++ b/libtrig/lib.rs @@ -1,24 +1,22 @@ -#![feature(const_mut_refs)] - -#![no_std] - -#![warn(missing_docs, unused, clippy::all)] -#![doc = include_str!("./README.md")] - -pub(crate) mod vectors; -pub(crate) mod traits; -pub(crate) mod coords; -pub(crate) mod angle; -pub(crate) mod types; - -pub use llm; - -pub mod prelude { - //! Re-exports all the traits. - pub use super::traits::*; -} - -pub use vectors::*; -pub use coords::*; -pub use angle::*; -pub use types::*; +#![feature(const_mut_refs)] +#![no_std] +#![warn(missing_docs, unused, clippy::all)] +#![doc = include_str!("./README.md")] + +pub(crate) mod angle; +pub(crate) mod coords; +pub(crate) mod traits; +pub(crate) mod types; +pub(crate) mod vectors; + +pub use llm; + +pub mod prelude { + //! Re-exports all the traits. + pub use super::traits::*; +} + +pub use angle::*; +pub use coords::*; +pub use types::*; +pub use vectors::*; diff --git a/libtrig/traits/mod.rs b/libtrig/traits/mod.rs index 041f127..258f1df 100644 --- a/libtrig/traits/mod.rs +++ b/libtrig/traits/mod.rs @@ -1,83 +1,83 @@ -use crate::*; - -mod number; -mod float; - -pub use number::Number; -pub use float::Float; - -macro_rules! simpl { - ($n:ident => $m:ident $($t:tt)*) => ( - #[inline] - #[must_use] - fn $n(&self) -> Self { - llm::$m(*self) - } - simpl!($($t)*); - ); - ($n:ident $($t:tt)*) => (simpl!($n => $n $($t)*);); - () => (); -} - -#[allow(unused)] -impl Float for Float64 { - simpl!(floor ceil round trunc abs => fabs sqrt exp exp2 ln log2 log10 cbrt - sin cos tan asin acos atan exp_m1 => expm1 ln_1p => log1p - sinh cosh tanh asinh acosh atanh); - #[inline] - #[must_use] - fn mul_add(&self, a: Self, b: Self) -> Self { - llm::fma(*self, a, b) - } - #[inline] - #[must_use] - fn div_euclid(&self, rhs: Self) -> Self { - todo!("div_euclid") - } - #[inline] - #[must_use] - fn rem_euclid(&self, rhs: Self) -> Self { - todo!("rem_euclid") - } - #[inline] - #[must_use] - fn signum(&self) -> Self { - if *self > 0.0 { - 1.0 - } else if *self < 0.0 { - -1.0 - } else { - Float64::NAN - } - } - #[inline] - #[must_use] - fn powi(&self, n: Int) -> Self { - llm::pow(*self, n as Float64) - } - #[inline] - #[must_use] - fn powf(&self, n: Self) -> Self { - llm::pow(*self, n) - } - #[inline] - #[must_use] - fn log(&self, base: Self) -> Self { - llm::log(*self) / llm::log(base) - } - #[inline] - #[must_use] - fn hypot(&self, other: Self) -> Self { - llm::hypot(*self, other) - } - #[inline] - #[must_use] - fn atan2(&self, other: Self) -> Self { - llm::atan2(*self, other) - } - #[inline] - #[must_use] - fn fract(&self) -> Self { - *self - self.floor() - } -} \ No newline at end of file +use crate::*; + +mod float; +mod number; + +pub use float::Float; +pub use number::Number; + +macro_rules! simpl { + ($n:ident => $m:ident $($t:tt)*) => ( + #[inline] + #[must_use] + fn $n(&self) -> Self { + llm::$m(*self) + } + simpl!($($t)*); + ); + ($n:ident $($t:tt)*) => (simpl!($n => $n $($t)*);); + () => (); +} + +#[allow(unused)] +impl Float for Float64 { + simpl!(floor ceil round trunc abs => fabs sqrt exp exp2 ln log2 log10 cbrt + sin cos tan asin acos atan exp_m1 => expm1 ln_1p => log1p + sinh cosh tanh asinh acosh atanh); + #[inline] + #[must_use] + fn mul_add(&self, a: Self, b: Self) -> Self { + llm::fma(*self, a, b) + } + #[inline] + #[must_use] + fn div_euclid(&self, rhs: Self) -> Self { + todo!("div_euclid") + } + #[inline] + #[must_use] + fn rem_euclid(&self, rhs: Self) -> Self { + todo!("rem_euclid") + } + #[inline] + #[must_use] + fn signum(&self) -> Self { + if *self > 0.0 { + 1.0 + } else if *self < 0.0 { + -1.0 + } else { + Float64::NAN + } + } + #[inline] + #[must_use] + fn powi(&self, n: Int) -> Self { + llm::pow(*self, n as Float64) + } + #[inline] + #[must_use] + fn powf(&self, n: Self) -> Self { + llm::pow(*self, n) + } + #[inline] + #[must_use] + fn log(&self, base: Self) -> Self { + llm::log(*self) / llm::log(base) + } + #[inline] + #[must_use] + fn hypot(&self, other: Self) -> Self { + llm::hypot(*self, other) + } + #[inline] + #[must_use] + fn atan2(&self, other: Self) -> Self { + llm::atan2(*self, other) + } + #[inline] + #[must_use] + fn fract(&self) -> Self { + *self - self.floor() + } +} diff --git a/libtrig/traits/number.rs b/libtrig/traits/number.rs index 36de71b..833bd9d 100644 --- a/libtrig/traits/number.rs +++ b/libtrig/traits/number.rs @@ -1,13 +1,21 @@ -use core::ops; - -/// A trait for types that can be used as numbers. -pub trait Number: - core::fmt::Debug + Copy + Clone + PartialEq + - ops::Add + ops::AddAssign + - ops::Sub + ops::SubAssign + - ops::Mul + ops::MulAssign + - ops::Div + ops::DivAssign + -{ } - -impl Number for crate::Int { } -impl Number for crate::Float64 { } +use core::ops; + +/// A trait for types that can be used as numbers. +pub trait Number: + core::fmt::Debug + + Copy + + Clone + + PartialEq + + ops::Add + + ops::AddAssign + + ops::Sub + + ops::SubAssign + + ops::Mul + + ops::MulAssign + + ops::Div + + ops::DivAssign +{ +} + +impl Number for crate::Int {} +impl Number for crate::Float64 {} diff --git a/libtrig/types.rs b/libtrig/types.rs index 71e2971..e3b9261 100644 --- a/libtrig/types.rs +++ b/libtrig/types.rs @@ -1,16 +1,16 @@ -pub use llm::{Float64, Float32, Radian64, Radian32}; - -/// A degree. (64bit) -pub type Degree64 = f64; - -/// A degree. (32bit) -pub type Degree32 = f32; - -/// An integer. -pub type Int = i32; - -/// A radian or degree. (64bit) -pub type RadianOrDegree64 = Float64; - -/// A radian or degree. (32bit) -pub type RadianOrDegree32 = Float32; +pub use llm::{Float32, Float64, Radian32, Radian64}; + +/// A degree. (64bit) +pub type Degree64 = f64; + +/// A degree. (32bit) +pub type Degree32 = f32; + +/// An integer. +pub type Int = i32; + +/// A radian or degree. (64bit) +pub type RadianOrDegree64 = Float64; + +/// A radian or degree. (32bit) +pub type RadianOrDegree32 = Float32; diff --git a/llm/lib.rs b/llm/lib.rs index f31d77c..a4a6d75 100644 --- a/llm/lib.rs +++ b/llm/lib.rs @@ -1,53 +1,51 @@ -#![doc = include_str!("./README.md")] - -#![no_std] -#![feature(core_intrinsics)] - -#![allow(clippy::unreadable_literal)] -#![allow(clippy::many_single_char_names)] -#![allow(clippy::needless_return)] -#![allow(clippy::int_plus_one)] -#![allow(clippy::deprecated_cfg_attr)] -#![allow(clippy::mixed_case_hex_literals)] -#![allow(clippy::float_cmp)] -#![allow(clippy::eq_op)] -#![allow(clippy::assign_op_pattern)] - -mod types; -mod math; - -pub use self::math::*; -pub use self::types::*; - -/// Approximate equality with 1 ULP of tolerance -#[doc(hidden)] -#[inline] -pub fn _eqf(a: Float32, b: Float32) -> Result<(), u32> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); - - if err <= 1 { - Ok(()) - } else { - Err(err as u32) - } - } -} - -#[doc(hidden)] -#[inline] -pub fn _eq(a: Float64, b: Float64) -> Result<(), u64> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); - - if err <= 1 { - Ok(()) - } else { - Err(err as u64) - } - } -} +#![doc = include_str!("./README.md")] +#![no_std] +#![feature(core_intrinsics)] +#![allow(clippy::unreadable_literal)] +#![allow(clippy::many_single_char_names)] +#![allow(clippy::needless_return)] +#![allow(clippy::int_plus_one)] +#![allow(clippy::deprecated_cfg_attr)] +#![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::float_cmp)] +#![allow(clippy::eq_op)] +#![allow(clippy::assign_op_pattern)] + +mod math; +mod types; + +pub use self::math::*; +pub use self::types::*; + +/// Approximate equality with 1 ULP of tolerance +#[doc(hidden)] +#[inline] +pub fn _eqf(a: Float32, b: Float32) -> Result<(), u32> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u32) + } + } +} + +#[doc(hidden)] +#[inline] +pub fn _eq(a: Float64, b: Float64) -> Result<(), u64> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u64) + } + } +} diff --git a/llm/math.rs b/llm/math.rs index 84e9869..14eb550 100644 --- a/llm/math.rs +++ b/llm/math.rs @@ -1,154 +1,167 @@ -macro_rules! force_eval { - ($e:expr) => { - unsafe { ::core::ptr::read_volatile(&$e) } - }; -} - -#[cfg(not(debug_assertions))] -macro_rules! i { - ($array:expr, $index:expr) => { - unsafe { *$array.get_unchecked($index) } - }; - ($array:expr, $index:expr, = , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) = $rhs; - } - }; - ($array:expr, $index:expr, += , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) += $rhs; - } - }; - ($array:expr, $index:expr, -= , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) -= $rhs; - } - }; - ($array:expr, $index:expr, &= , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) &= $rhs; - } - }; - ($array:expr, $index:expr, == , $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) == $rhs } - }; -} - -#[cfg(debug_assertions)] -macro_rules! i { - ($array:expr, $index:expr) => { - *$array.get($index).unwrap() - }; - ($array:expr, $index:expr, = , $rhs:expr) => { - *$array.get_mut($index).unwrap() = $rhs; - }; - ($array:expr, $index:expr, -= , $rhs:expr) => { - *$array.get_mut($index).unwrap() -= $rhs; - }; - ($array:expr, $index:expr, += , $rhs:expr) => { - *$array.get_mut($index).unwrap() += $rhs; - }; - ($array:expr, $index:expr, &= , $rhs:expr) => { - *$array.get_mut($index).unwrap() &= $rhs; - }; - ($array:expr, $index:expr, == , $rhs:expr) => { - *$array.get_mut($index).unwrap() == $rhs - }; -} - -// Temporary macro to avoid panic codegen for division (in debug mode too). At -// the time of this writing this is only used in a few places, and once -// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and -// the native `/` operator can be used and panics won't be codegen'd. -#[cfg(debug_assertions)] -macro_rules! div { - ($a:expr, $b:expr) => { - $a / $b - }; -} - -#[cfg(not(debug_assertions))] -macro_rules! div { - ($a:expr, $b:expr) => { - unsafe { core::intrinsics::unchecked_div($a, $b) } - }; -} - - -macro_rules! consts { - (const $name:ident: $ty:ty = $value:expr; $($t:tt)* ) => ( - #[allow(clippy::excessive_precision)] - #[deny(clippy::approx_constant)] - const $name: $ty = $value; - consts!($($t)*); - ); - () => (); -} - -macro_rules! llvm_intrinsically_optimized { - (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all($($clause)*))] - { $e } - }; -} - -macro_rules! import { - ($p:vis $n:ident) => ( - mod $n; #[allow(unused_imports)] $p use self::$n::*; - ); - ($p:vis $n:ident $(, $m:ident)*) => ( - import!($p $n); import!($p $($m),*); - ); -} - -// Public modules -import!(pub acos, acosf, acosh, acoshf, asin, asinf, asinh, asinhf, atan, atan2, atan2f, atanf, atanh, atanhf); -import!(pub cbrt, cbrtf, ceil, ceilf, copysign, copysignf, cos, cosf, cosh, coshf); -import!(pub erf, erff, exp, exp10, exp10f, exp2, exp2f, expf, expm1, expm1f); -import!(pub fabs, fabsf, fdim, fdimf, floor, floorf, fma, fmaf, fmax, fmaxf, fmin, fminf, fmod, fmodf, frexp, frexpf); -import!(pub hypot, hypotf); -import!(pub ilogb, ilogbf); -import!(pub j0, j0f, j1, j1f, jn, jnf); -import!(pub ldexp, ldexpf, lgamma, lgamma_r, lgammaf, lgammaf_r, ln, lnf, log, log10, log10f, log1p, log1pf, log2, log2f, logf); -import!(pub modf, modff); -import!(pub nextafter, nextafterf); -import!(pub pow, powf); -import!(pub remainder, remainderf, remquo, remquof, rint, rintf, round, roundf); -import!(pub scalbn, scalbnf, sin, sincos, sincosf, sinf, sinh, sinhf, sqrt, sqrtf); -import!(pub tan, tanf, tanh, tanhf, tgamma, tgammaf, trunc, truncf); - -// Private modules -import!(expo2, fenv, k_cos, k_cosf, k_expo2, k_expo2f, k_sin, k_sinf, k_tan, k_tanf, rem_pio2, rem_pio2_large, rem_pio2f); - -use crate::Float64; - -#[inline] -fn get_high_word(x: Float64) -> u32 { - (x.to_bits() >> 32) as u32 -} - -#[inline] -fn get_low_word(x: Float64) -> u32 { - x.to_bits() as u32 -} - -#[inline] -fn with_set_high_word(f: Float64, hi: u32) -> Float64 { - let mut tmp = f.to_bits(); - tmp &= 0x00000000_ffffffff; - tmp |= (hi as u64) << 32; - Float64::from_bits(tmp) -} - -#[inline] -fn with_set_low_word(f: Float64, lo: u32) -> Float64 { - let mut tmp = f.to_bits(); - tmp &= 0xffffffff_00000000; - tmp |= lo as u64; - Float64::from_bits(tmp) -} - -#[inline] -fn combine_words(hi: u32, lo: u32) -> Float64 { - Float64::from_bits((hi as u64) << 32 | lo as u64) -} +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e) } + }; +} + +#[cfg(not(debug_assertions))] +macro_rules! i { + ($array:expr, $index:expr) => { + unsafe { *$array.get_unchecked($index) } + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) = $rhs; + } + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) += $rhs; + } + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) -= $rhs; + } + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) &= $rhs; + } + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) == $rhs } + }; +} + +#[cfg(debug_assertions)] +macro_rules! i { + ($array:expr, $index:expr) => { + *$array.get($index).unwrap() + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + *$array.get_mut($index).unwrap() = $rhs; + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + *$array.get_mut($index).unwrap() -= $rhs; + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + *$array.get_mut($index).unwrap() += $rhs; + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + *$array.get_mut($index).unwrap() &= $rhs; + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + *$array.get_mut($index).unwrap() == $rhs + }; +} + +// Temporary macro to avoid panic codegen for division (in debug mode too). At +// the time of this writing this is only used in a few places, and once +// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and +// the native `/` operator can be used and panics won't be codegen'd. +#[cfg(debug_assertions)] +macro_rules! div { + ($a:expr, $b:expr) => { + $a / $b + }; +} + +#[cfg(not(debug_assertions))] +macro_rules! div { + ($a:expr, $b:expr) => { + unsafe { core::intrinsics::unchecked_div($a, $b) } + }; +} + +macro_rules! consts { + (const $name:ident: $ty:ty = $value:expr; $($t:tt)* ) => ( + #[allow(clippy::excessive_precision)] + #[deny(clippy::approx_constant)] + const $name: $ty = $value; + consts!($($t)*); + ); + () => (); +} + +macro_rules! llvm_intrinsically_optimized { + (#[cfg($($clause:tt)*)] $e:expr) => { + #[cfg(all($($clause)*))] + { $e } + }; +} + +macro_rules! import { + ($p:vis $n:ident) => ( + mod $n; #[allow(unused_imports)] $p use self::$n::*; + ); + ($p:vis $n:ident $(, $m:ident)*) => ( + import!($p $n); import!($p $($m),*); + ); +} + +// Public modules +import!(pub acos, acosf, acosh, acoshf, asin, asinf, asinh, asinhf, atan, atan2, atan2f, atanf, atanh, atanhf); +import!(pub cbrt, cbrtf, ceil, ceilf, copysign, copysignf, cos, cosf, cosh, coshf); +import!(pub erf, erff, exp, exp10, exp10f, exp2, exp2f, expf, expm1, expm1f); +import!(pub fabs, fabsf, fdim, fdimf, floor, floorf, fma, fmaf, fmax, fmaxf, fmin, fminf, fmod, fmodf, frexp, frexpf); +import!(pub hypot, hypotf); +import!(pub ilogb, ilogbf); +import!(pub j0, j0f, j1, j1f, jn, jnf); +import!(pub ldexp, ldexpf, lgamma, lgamma_r, lgammaf, lgammaf_r, ln, lnf, log, log10, log10f, log1p, log1pf, log2, log2f, logf); +import!(pub modf, modff); +import!(pub nextafter, nextafterf); +import!(pub pow, powf); +import!(pub remainder, remainderf, remquo, remquof, rint, rintf, round, roundf); +import!(pub scalbn, scalbnf, sin, sincos, sincosf, sinf, sinh, sinhf, sqrt, sqrtf); +import!(pub tan, tanf, tanh, tanhf, tgamma, tgammaf, trunc, truncf); + +// Private modules +import!( + expo2, + fenv, + k_cos, + k_cosf, + k_expo2, + k_expo2f, + k_sin, + k_sinf, + k_tan, + k_tanf, + rem_pio2, + rem_pio2_large, + rem_pio2f +); + +use crate::Float64; + +#[inline] +fn get_high_word(x: Float64) -> u32 { + (x.to_bits() >> 32) as u32 +} + +#[inline] +fn get_low_word(x: Float64) -> u32 { + x.to_bits() as u32 +} + +#[inline] +fn with_set_high_word(f: Float64, hi: u32) -> Float64 { + let mut tmp = f.to_bits(); + tmp &= 0x00000000_ffffffff; + tmp |= (hi as u64) << 32; + Float64::from_bits(tmp) +} + +#[inline] +fn with_set_low_word(f: Float64, lo: u32) -> Float64 { + let mut tmp = f.to_bits(); + tmp &= 0xffffffff_00000000; + tmp |= lo as u64; + Float64::from_bits(tmp) +} + +#[inline] +fn combine_words(hi: u32, lo: u32) -> Float64 { + Float64::from_bits((hi as u64) << 32 | lo as u64) +}