#![deny(rustdoc::broken_intra_doc_links)]
use std::{marker::PhantomData, num::FpCategory};
use num::Complex;
use try_create::ValidationPolicy;
use crate::core::{
errors::{ErrorsValidationRawComplex, ErrorsValidationRawReal, capture_backtrace},
traits::{
raw::{RawComplexTrait, RawRealTrait, RawScalarTrait},
validation::{
GuaranteesFiniteComplexValues, GuaranteesFiniteRealValues, ValidationPolicyComplex,
ValidationPolicyReal,
},
},
};
pub struct StrictFinitePolicy<ScalarType: Sized, const PRECISION: u32>(PhantomData<ScalarType>);
pub type Native64RawRealStrictFinitePolicy = StrictFinitePolicy<f64, 53>;
pub type Native64RawComplexStrictFinitePolicy = StrictFinitePolicy<Complex<f64>, 53>;
impl ValidationPolicy for Native64RawRealStrictFinitePolicy {
type Value = f64;
type Error = ErrorsValidationRawReal<f64>;
fn validate_ref(value: &f64) -> Result<(), Self::Error> {
match value.classify() {
FpCategory::Nan => Err(ErrorsValidationRawReal::IsNaN {
value: *value,
backtrace: capture_backtrace(),
}),
FpCategory::Infinite => {
if value.is_sign_positive() {
Err(ErrorsValidationRawReal::IsPosInfinity {
backtrace: capture_backtrace(),
})
} else {
Err(ErrorsValidationRawReal::IsNegInfinity {
backtrace: capture_backtrace(),
})
}
}
FpCategory::Subnormal => Err(ErrorsValidationRawReal::IsSubnormal {
value: *value,
backtrace: capture_backtrace(),
}),
FpCategory::Normal | FpCategory::Zero => Ok(()),
}
}
}
pub struct DebugValidationPolicy<P: ValidationPolicy>(PhantomData<P>);
impl<P: ValidationPolicy> ValidationPolicy for DebugValidationPolicy<P> {
type Value = P::Value;
type Error = P::Error;
#[inline(always)]
fn validate_ref(value: &Self::Value) -> Result<(), Self::Error> {
#[cfg(debug_assertions)]
{
P::validate_ref(value)
}
#[cfg(not(debug_assertions))]
{
let _ = value; Ok(())
}
}
}
impl<P> ValidationPolicyReal for DebugValidationPolicy<P>
where
P: ValidationPolicyReal,
{
const PRECISION: u32 = P::PRECISION;
}
impl<P> ValidationPolicyComplex for DebugValidationPolicy<P>
where
P: ValidationPolicyComplex,
{
const PRECISION: u32 = P::PRECISION;
}
pub(crate) fn validate_complex<P: ValidationPolicyReal>(
real_part: &P::Value,
imag_part: &P::Value,
) -> Result<(), ErrorsValidationRawComplex<P::Error>> {
let real_validation = P::validate_ref(real_part);
let imag_validation = P::validate_ref(imag_part);
match (real_validation, imag_validation) {
(Ok(()), Ok(())) => Ok(()),
(Ok(()), Err(imag_err)) => Err(ErrorsValidationRawComplex::InvalidImaginaryPart {
source: Box::new(imag_err),
}),
(Err(real_err), Ok(())) => Err(ErrorsValidationRawComplex::InvalidRealPart {
source: Box::new(real_err),
}),
(Err(real_err), Err(imag_err)) => Err(ErrorsValidationRawComplex::InvalidBothParts {
real_error: Box::new(real_err),
imag_error: Box::new(imag_err),
}),
}
}
#[inline(always)]
pub fn validate_in_debug<P: ValidationPolicy>(value: &P::Value, msg: &str) {
#[cfg(debug_assertions)]
{
if let Err(e) = P::validate_ref(value) {
panic!("Debug validation of {msg} value failed: {e}");
}
}
#[cfg(not(debug_assertions))]
{
let _ = value;
let _ = msg;
}
}
impl ValidationPolicy for Native64RawComplexStrictFinitePolicy {
type Value = Complex<f64>;
type Error = ErrorsValidationRawComplex<ErrorsValidationRawReal<f64>>;
fn validate_ref(value: &Complex<f64>) -> Result<(), Self::Error> {
validate_complex::<Native64RawRealStrictFinitePolicy>(&value.re, &value.im)
}
}
impl<RawReal: RawRealTrait, const PRECISION: u32> ValidationPolicyReal
for StrictFinitePolicy<RawReal, PRECISION>
where
StrictFinitePolicy<RawReal, PRECISION>:
ValidationPolicy<Value = RawReal, Error = <RawReal as RawScalarTrait>::ValidationErrors>,
{
const PRECISION: u32 = PRECISION;
}
impl<RawComplex: RawComplexTrait, const PRECISION: u32> ValidationPolicyComplex
for StrictFinitePolicy<RawComplex, PRECISION>
where
StrictFinitePolicy<RawComplex, PRECISION>: ValidationPolicy<
Value = RawComplex,
Error = <RawComplex as RawScalarTrait>::ValidationErrors,
>,
{
const PRECISION: u32 = PRECISION;
}
#[cfg(feature = "rug")]
pub(crate) mod rug_impls {
use super::*; use crate::core::errors::capture_backtrace;
use std::num::FpCategory;
impl<const PRECISION: u32> ValidationPolicy for StrictFinitePolicy<rug::Float, PRECISION> {
type Value = rug::Float;
type Error = ErrorsValidationRawReal<rug::Float>;
fn validate_ref(value: &rug::Float) -> Result<(), Self::Error> {
let actual_precision = value.prec();
if actual_precision == PRECISION {
match value.classify() {
FpCategory::Infinite => {
if value.is_sign_positive() {
Err(ErrorsValidationRawReal::IsPosInfinity {
backtrace: capture_backtrace(),
})
} else {
Err(ErrorsValidationRawReal::IsNegInfinity {
backtrace: capture_backtrace(),
})
}
}
FpCategory::Nan => Err(ErrorsValidationRawReal::IsNaN {
value: value.clone(),
backtrace: capture_backtrace(),
}),
FpCategory::Subnormal => Err(ErrorsValidationRawReal::IsSubnormal {
value: value.clone(),
backtrace: capture_backtrace(),
}),
FpCategory::Zero | FpCategory::Normal => Ok(()),
}
} else {
Err(ErrorsValidationRawReal::PrecisionMismatch {
input_value: value.clone(),
actual_precision,
requested_precision: PRECISION,
backtrace: capture_backtrace(),
})
}
}
}
impl<const PRECISION: u32> ValidationPolicy for StrictFinitePolicy<rug::Complex, PRECISION> {
type Value = rug::Complex;
type Error = ErrorsValidationRawComplex<ErrorsValidationRawReal<rug::Float>>;
fn validate_ref(value: &rug::Complex) -> Result<(), Self::Error> {
validate_complex::<StrictFinitePolicy<rug::Float, PRECISION>>(
value.real(),
value.imag(),
)
}
}
}
impl<RawReal: RawRealTrait, const PRECISION: u32> GuaranteesFiniteRealValues
for StrictFinitePolicy<RawReal, PRECISION>
where
StrictFinitePolicy<RawReal, PRECISION>: ValidationPolicyReal,
{
}
impl<RawReal: RawRealTrait, const PRECISION: u32> GuaranteesFiniteRealValues
for DebugValidationPolicy<StrictFinitePolicy<RawReal, PRECISION>>
where
StrictFinitePolicy<RawReal, PRECISION>: ValidationPolicyReal,
{
}
impl<RawComplex: RawComplexTrait, const PRECISION: u32> GuaranteesFiniteComplexValues
for StrictFinitePolicy<RawComplex, PRECISION>
where
StrictFinitePolicy<RawComplex, PRECISION>: ValidationPolicyComplex,
{
}
impl<RawComplex: RawComplexTrait, const PRECISION: u32> GuaranteesFiniteComplexValues
for DebugValidationPolicy<StrictFinitePolicy<RawComplex, PRECISION>>
where
StrictFinitePolicy<RawComplex, PRECISION>: ValidationPolicyComplex,
{
}